diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ec35c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +*unit-test.log +failed-test.log +TAGS +*.tar.gz +*.pyc +.*.swp +*~ +\#* +.#* +*.DS_Store +.sass-cache/ +*.pho +build/ +html/ +/static/ +/media/ +MNIMakefile +test_failures.txt +test_rerun.txt +*.log +*.rerun +failure-list.txt +*.idx +*.ilg +*.ind +.coverage +GridPlatform.pdf +GridPlatformDomainModel.pdf +.project +.idea diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000..d768253 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,8 @@ +[settings] +known_first_party=gridplatform,legacy +known_third_party=django,pytz +force_single_line=true +add_imports=__future__.absolute_import,__future__.unicode_literals +not_skip=__init__.py +skip=migrations +lines_after_imports=2 diff --git a/.pep8 b/.pep8 new file mode 100644 index 0000000..c60af27 --- /dev/null +++ b/.pep8 @@ -0,0 +1,2 @@ +[flake8] +exclude=migrations diff --git a/.reviewboardrc b/.reviewboardrc new file mode 100644 index 0000000..0af1bbd --- /dev/null +++ b/.reviewboardrc @@ -0,0 +1,2 @@ +REVIEWBOARD_URL = 'http://reviewboard.gridmanager.dk/' +REPOSITORY = 'GridPlatform' diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..05d96c5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + "version": "0.1.0", + "configurations": [ + { + "name": "Attach", + "type": "chrome", + "request": "attach", + "port": 9222, + "url": "http://127.0.0.1:8080/skave.html", + "webRoot": "C:\\Users\\code\\repos\\hogt_web\\frontend\\vama", + "sourceMapPathOverrides": { + "/source/*": "${workspaceRoot}/*" + } + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..eb4a8e0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.pythonPath": "C:/Users/code/.virtualenvs/portal/Scripts/python.exe", + "python.linting.pylintArgs": ["--load-plugins", "pylint_django", "--disable=missing-docstring"], + "python.linting.flake8Enabled": true +} diff --git a/EmonTX/SC-EmonTX_V140_Net210/SC-EmonTX_V140_Net210.ino b/EmonTX/SC-EmonTX_V140_Net210/SC-EmonTX_V140_Net210.ino new file mode 100644 index 0000000..2548e24 --- /dev/null +++ b/EmonTX/SC-EmonTX_V140_Net210/SC-EmonTX_V140_Net210.ino @@ -0,0 +1,542 @@ +#define emonTxV3 // Tell emonLib this is the emonTx V3 - don't read Vcc assume Vcc = 3.3V as is always the case on emonTx V3 eliminates bandgap error and need for calibration http://harizanov.com/2013/09/thoughts-on-avr-adc-accuracy/ +#define RF69_COMPAT 1 // Set to 1 if using RFM69CW or 0 is using RFM12B +#include //https://github.com/jcw/jeelib - Tested with JeeLib 3/11/14 +#include + +ISR(WDT_vect) { Sleepy::watchdogEvent(); } // Attached JeeLib sleep function to Atmega328 watchdog -enables MCU to be put into sleep mode inbetween readings to reduce power consumption + +#include "EmonLib.h" // Include EmonLib energy monitoring library https://github.com/openenergymonitor/EmonLib +EnergyMonitor ct1, ct2, ct3, ct4; + +// - OneWire and Dallas has been taken out of this software +#include //http://www.pjrc.com/teensy/td_libs_OneWire.html +#include //http://download.milesburton.com/Arduino/MaximTemperature/DallasTemperature_LATEST.zip + +const byte version = 140; // firmware version divided by 10 e,g 160 = V1.60 + +//----------------------------emonTx V3 Settings--------------------------------------------------------------------------------------------------------------- +const byte Vrms= 230; // Vrms for apparent power readings (when no AC-AC voltage sample is present) +const byte TIME_BETWEEN_READINGS = 9; //Time between readings + +//http://openenergymonitor.org/emon/buildingblocks/calibration + +const float Ical1= 90.9; // (2000 turns / 22 Ohm burden) = 90.9 +const float Ical2= 90.9; // (2000 turns / 22 Ohm burden) = 90.9 +const float Ical3= 90.9; // (2000 turns / 22 Ohm burden) = 90.9 +const float Ical4= 16.67; // (2000 turns / 120 Ohm burden) = 16.67 + +const float Vcal= 242; //238.86 reported, 216 measured +//Old value for standard software 268.97; // (230V x 13) / (9V x 1.2) = 276.9 Calibration for UK AC-AC adapter 77DB-06-09 +//const float Vcal= 276.9; //Calibrated by OpenEnergy Forum +//const float Vcal= 260; // Calibration for EU AC-AC adapter 77DE-06-09 + +const float phase_shift= 1.7; +const int no_of_samples= 1662; +const int no_of_half_wavelengths= 30; +const int timeout= 2000; //emonLib timeout +const int ACAC_DETECTION_LEVEL= 3000; +const byte min_pulsewidth= 110; // minimum width of interrupt pulse (default pulse output meters = 100ms) +const int TEMPERATURE_PRECISION= 11; //9 (93.8ms),10 (187.5ms) ,11 (375ms) or 12 (750ms) bits equal to resplution of 0.5C, 0.25C, 0.125C and 0.0625C +const byte MaxOnewire= 6; + + +#define ASYNC_DELAY 375 // DS18B20 conversion delay - 9bit requres 95ms, 10bit 187ms, 11bit 375ms and 12bit resolution takes 750ms + +//------------------------------------------------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------------------------------------------------- + + +//----------------------------emonTx V3 hard-wired connections--------------------------------------------------------------------------------------------------------------- +const byte LEDpin= 6; // emonTx V3 LED +const byte DS18B20_PWR= 19; // DS18B20 Power +const byte DIP_switch1= 8; // Voltage selection 230 / 110 V AC (default switch off 230V) - switch off D8 is HIGH from internal pullup +const byte DIP_switch2= 9; // RF node ID (default no chance in node ID, switch on for nodeID -1) switch off D9 is HIGH from internal pullup +const byte battery_voltage_pin= 7; // Battery Voltage sample from 3 x AA +const byte pulse_countINT= 1; // INT 1 / Dig 3 Terminal Block / RJ45 Pulse counting pin(emonTx V3.4) - (INT0 / Dig2 emonTx V3.2) +const byte pulse_count_pin= 3; // INT 1 / Dig 3 Terminal Block / RJ45 Pulse counting pin(emonTx V3.4) - (INT0 / Dig2 emonTx V3.2) +#define ONE_WIRE_BUS 5 // DS18B20 Data +//------------------------------------------------------------------------------------------------------------------------------------------- + +//Setup DS128B20 +OneWire oneWire(ONE_WIRE_BUS); +DallasTemperature sensors(&oneWire); +byte allAddress [MaxOnewire][8]; // 8 bytes per address +byte numSensors; +//------------------------------------------------------------------------------------------------------------------------------------------- + +//-----------------------RFM12B / RFM69CW SETTINGS---------------------------------------------------------------------------------------------------- +#define RF_freq RF12_433MHZ // Frequency of RF69CW module can be RF12_433MHZ, RF12_868MHZ or RF12_915MHZ. You should use the one matching the module you have. +byte nodeID = 10; // emonTx RFM12B node ID +const int networkGroup = 210; + +// Note: Please update emonhub configuration guide on OEM wide packet structure change: +// https://github.com/openenergymonitor/emonhub/blob/emon-pi/configuration.md +/* +[[9]] + nodename = EMONTX9 + firmware =V130 + hardware = SC-EmonTx + [[[rx]]] + names = power1, power2, power3, power4, Vrms, pulse, Wh1, Wh2, Wh3, Wh4, RunHours1, RunHours2, RunHours3, RunHours4 + datacodes = h,h,h,h,h, L, l, l, l, l, L, L, L, L + scales = 1,1,1,1,0.01, 1, 1, 1, 1, 1, 1, 1, 1, 1 + units = W,W,W,W,V, p, Wh, Wh, Wh, Wh, sec, sec, sec, sec + senddata = 0,0,0,0,0,0,1,0,0,0,1,0,0,0 */ + +typedef struct { + int power1, power2, power3, power4, Vrms, temp[MaxOnewire]; + unsigned long pulseCount; //pulse counter maintained + long lAccPower1, lAccPower2, lAccPower3, lAccPower4; //accumulating power added + unsigned long lRunHour1,lRunHour2, lRunHour3, lRunHour4; //accumulating running hours +} PayloadTX; // create structure - a neat way of packaging data for RF comms +PayloadTX emontx_package; + +//------------------------------------------------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------------------------------------------------- + +//Random Variables +//boolean settled = false; +boolean CT1, CT2, CT3, CT4, ACAC, debug, DS18B20_STATUS; +byte CT_count=0; +volatile byte pulseCount = 0; +unsigned long pulsetime=0; // Record time of interrupt pulse +long lWhCounter1,lWhCounter2,lWhCounter3,lWhCounter4; + +void setup() +{ + pinMode(LEDpin, OUTPUT); + pinMode(DS18B20_PWR, OUTPUT); + + pinMode(pulse_count_pin, INPUT_PULLUP); // Set emonTx V3.4 interrupt pulse counting pin as input (Dig 3 / INT1) + emontx_package.pulseCount=0; // Make sure pulse count starts at zero + + digitalWrite(LEDpin,HIGH); + + Serial.begin(9600); + + Serial.print("SC-EmonTx - Version "); Serial.println(version*0.01); + #if (RF69_COMPAT) + Serial.println(" RFM69CW"); + #else + Serial.println(" RFM12B"); + #endif + Serial.println("www.scnordic.com"); + + //READ DIP SWITCH POSITIONS + pinMode(DIP_switch1, INPUT_PULLUP); + pinMode(DIP_switch2, INPUT_PULLUP); + + if ((digitalRead(DIP_switch1)==HIGH) && (digitalRead(DIP_switch2)==HIGH)) nodeID=9; // IF DIP switch 1 is switched on then subtract 1 from nodeID + if ((digitalRead(DIP_switch1)==LOW) && (digitalRead(DIP_switch2)==HIGH)) nodeID=8; // IF DIP switch 1 is switched on then subtract 1 from nodeID + if ((digitalRead(DIP_switch1)==HIGH) && (digitalRead(DIP_switch2)==LOW)) nodeID=7; // IF DIP switch 1 is switched on then subtract 1 from nodeID + if ((digitalRead(DIP_switch1)==LOW) && (digitalRead(DIP_switch2)==LOW)) nodeID=6; // IF DIP switch 1 is switched on then subtract 1 from nodeID + + Serial.print("NodeID: "); Serial.println(nodeID); + Serial.print("Net: "); Serial.println(networkGroup); + Serial.print("TXPackage size: "); Serial.println(sizeof(emontx_package)); + Serial.print("Reporting interval: "); Serial.println(TIME_BETWEEN_READINGS); + + Serial.print("POST.....wait 10s"); + delay(10); + + rf12_initialize(nodeID, RF_freq, networkGroup); // initialize RFM12B/rfm69CW + + rf12_sendWait(2); + emontx_package.power1=0; + + if (analogRead(1) > 0) {CT1 = 1; CT_count++;} else CT1=0; // check to see if CT is connected to CT1 input, if so enable that channel + if (analogRead(2) > 0) {CT2 = 1; CT_count++;} else CT2=0; // check to see if CT is connected to CT2 input, if so enable that channel + if (analogRead(3) > 0) {CT3 = 1; CT_count++;} else CT3=0; // check to see if CT is connected to CT3 input, if so enable that channel + if (analogRead(4) > 0) {CT4 = 1; CT_count++;} else CT4=0; // check to see if CT is connected to CT4 input, if so enable that channel + + if ( CT_count == 0) CT1=1; // If no CT's are connect ed CT1-4 then by default read from CT1 + + // Quick check to see if there is a voltage waveform present on the ACAC Voltage input + // Check consists of calculating the RMS from 100 samples of the voltage input. + Sleepy::loseSomeTime(10000); //wait for settle + digitalWrite(LEDpin,LOW); + + // Calculate if there is an ACAC adapter on analog input 0 + //double vrms = calc_rms(0,1780) * (Vcal * (3.3/1024) ); + double vrms = calc_rms(0,1780) * 0.87; + if (vrms>90) ACAC = 1; else ACAC=0; + + if (ACAC) + { + for (int i=0; i<10; i++) // indicate AC has been detected by flashing LED 10 times + { + digitalWrite(LEDpin, HIGH); delay(200); + digitalWrite(LEDpin, LOW); delay(300); + } + } + else + digitalWrite(LEDpin, HIGH); delay(2000); digitalWrite(LEDpin, LOW); // indicate DC power has been detected by turing LED on then off + + //################################################################################################################################ + //Setup and for presence of DS18B20 + //################################################################################################################################ + digitalWrite(DS18B20_PWR, HIGH); delay(100); + sensors.begin(); + sensors.setWaitForConversion(false); // disable automatic temperature conversion to reduce time spent awake, conversion will be implemented manually in sleeping + // http://harizanov.com/2013/07/optimizing-ds18b20-code-for-low-power-applications/ + numSensors=(sensors.getDeviceCount()); + if (numSensors > MaxOnewire) numSensors=MaxOnewire; //Limit number of sensors to max number of sensors + + byte j=0; // search for one wire devices and + // copy to device address arrays. + while ((j < numSensors) && (oneWire.search(allAddress[j]))) j++; + + delay(500); + digitalWrite(DS18B20_PWR, LOW); + + if (numSensors==0) DS18B20_STATUS=0; + else DS18B20_STATUS=1; + + lWhCounter1 = lWhCounter2 = lWhCounter3 = lWhCounter4 = 0; + + + //################################################################################################################################ + + if (Serial) debug = 1; else debug=0; // if serial UART to USB is connected show debug O/P. If not then disable serial + if (debug==1) + { + Serial.print("CT 1 Cal "); Serial.println(Ical1); + Serial.print("CT 2 Cal "); Serial.println(Ical2); + Serial.print("CT 3 Cal "); Serial.println(Ical3); + Serial.print("CT 4 Cal "); Serial.println(Ical4); + delay(1000); + + Serial.print("RMS Voltage on AC-AC is: ~"); + Serial.print(vrms,0); Serial.println("V"); + + if (ACAC) { + Serial.println("AC-AC detected - Real Power measure enabled"); + Serial.println("assuming pwr from AC-AC (jumper closed)"); +// if (USA==TRUE) Serial.println("USA mode active"); + Serial.print("Vcal: "); Serial.println(Vcal); + Serial.print("Phase Shift: "); Serial.println(phase_shift); + } else { + Serial.println("AC-AC NOT detected - Apparent Pwr measure enabled"); + Serial.print("Assuming VRMS: "); Serial.print(Vrms); Serial.println("V"); + Serial.println("Assuming power from batt / 5V USB - power save enabled"); + } + + if (CT_count==0) { + Serial.println("NO CT's detected"); + } else { + if (CT1) Serial.println("CT 1 detected"); + if (CT2) Serial.println("CT 2 detected"); + if (CT3) Serial.println("CT 3 detected"); + if (CT4) Serial.println("CT 4 detected"); + } + + if (DS18B20_STATUS==1) { + Serial.print("Detected Temp Sensors: "); + Serial.println(numSensors); + } else { + Serial.println("No temperature sensor"); + } + + #if (RF69_COMPAT) + Serial.println("RFM69CW"); + #else + Serial.println("RFM12B"); + #endif + + Serial.print("Node: "); Serial.print(nodeID); + Serial.print(" Freq: "); + if (RF_freq == RF12_433MHZ) Serial.print("433Mhz"); + if (RF_freq == RF12_868MHZ) Serial.print("868Mhz"); + if (RF_freq == RF12_915MHZ) Serial.print("915Mhz"); + Serial.print(" Network: "); Serial.println(networkGroup); + + Serial.println("CT1-4 Vrms/BATT Pulse kwh1-4 Live1-4"); + + if (DS18B20_STATUS==1){Serial.print(" Temperature 1-"); Serial.print(numSensors);} + //Serial.println("Temperature sensors are disabled in this SW "); + + delay(500); + } + else + Serial.end(); + + if (CT1) ct1.current(1, Ical1); // CT ADC channel 1, calibration. calibration (2000 turns / 22 Ohm burden resistor = 90.909) + if (CT2) ct2.current(2, Ical2); // CT ADC channel 2, calibration. + if (CT3) ct3.current(3, Ical3); // CT ADC channel 3, calibration. + if (CT4) ct4.current(4, Ical4); // CT ADC channel 4, calibration. calibration (2000 turns / 120 Ohm burden resistor = 16.66) high accuracy @ low power - 4.5kW Max @ 240V + + if (ACAC) + { + if (CT1) ct1.voltage(0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift + if (CT2) ct2.voltage(0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift + if (CT3) ct3.voltage(0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift + if (CT4) ct4.voltage(0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift + } + + attachInterrupt(pulse_countINT, onPulse, FALLING); // Attach pulse counting interrupt pulse counting + + //Serial.println("+WDT"); + //wdt_reset(); + //wdt_enable(WDTO_8S); + + for(byte j=0;j 20) + emontx_package.lRunHour1 += TIME_BETWEEN_READINGS; + if(emontx_package.power2 > 20) + emontx_package.lRunHour2 += TIME_BETWEEN_READINGS; + if(emontx_package.power3 > 20) + emontx_package.lRunHour3 += TIME_BETWEEN_READINGS; + if(emontx_package.power4 > 20) + emontx_package.lRunHour4 += TIME_BETWEEN_READINGS; + + int iDelta; + + iDelta = lWhCounter4 / (3600 / TIME_BETWEEN_READINGS); + emontx_package.lAccPower4 += iDelta; + lWhCounter4 -= (iDelta * (3600 / TIME_BETWEEN_READINGS)); + + iDelta = lWhCounter3 / (3600 / TIME_BETWEEN_READINGS); + emontx_package.lAccPower3 += iDelta; + lWhCounter3 -= (iDelta * (3600 / TIME_BETWEEN_READINGS)); + + iDelta = lWhCounter2 / (3600 / TIME_BETWEEN_READINGS); + emontx_package.lAccPower2 += iDelta; + lWhCounter2 -= (iDelta * (3600 / TIME_BETWEEN_READINGS)); + + iDelta = lWhCounter1 / (3600 / TIME_BETWEEN_READINGS); + emontx_package.lAccPower1 += iDelta; + lWhCounter1 -= (iDelta * (3600 / TIME_BETWEEN_READINGS)); + + if (debug==1) { + Serial.print(emontx_package.power1); Serial.print(" "); + Serial.print(emontx_package.power2); Serial.print(" "); + Serial.print(emontx_package.power3); Serial.print(" "); + Serial.print(emontx_package.power4); Serial.print(" "); + Serial.print(emontx_package.Vrms); + + Serial.print("v C:"); + Serial.print(emontx_package.pulseCount); Serial.print(" "); + Serial.print(emontx_package.lAccPower1); Serial.print("."); Serial.print(lWhCounter1); Serial.print(" "); + Serial.print(emontx_package.lAccPower2); Serial.print(" "); + Serial.print(emontx_package.lAccPower3); Serial.print(" "); + + Serial.print(" L: "); Serial.print(emontx_package.lRunHour1); + Serial.print("-"); Serial.print(emontx_package.lRunHour2); + Serial.print("-"); Serial.print(emontx_package.lRunHour3); + Serial.print("-"); Serial.println(emontx_package.lRunHour4); + + if (DS18B20_STATUS==1){ + for(byte j=0;j 0) { + int incomingByte = 0; + // read the incoming byte: + incomingByte = Serial.read(); + + // say what you got: + Serial.print("RX: "); + Serial.println(incomingByte, DEC); + } +} + +void send_rf_data() +{ + rf12_sleep(RF12_WAKEUP); + rf12_sendNow(0, &emontx_package, sizeof emontx_package); //send data via RFM12B using new rf12_sendNow wrapper + rf12_sendWait(2); + + if (!ACAC) + rf12_sleep(RF12_SLEEP); //if powred by battery then put the RF module into sleep inbetween readings +} + + +double calc_rms(int pin, int samples) +{ + unsigned long sum = 0; + for (int i=0; i min_pulsewidth) { + pulseCount++; //calculate wh elapsed from time between pulses + } + pulsetime=millis(); +} + + +int get_temperature(byte sensor) +{ + float temp=(sensors.getTempC(allAddress[sensor])); + if ((temp<125.0) && (temp>-55.0)) return(temp*10); //if reading is within range for the sensor convert float to int ready to send via RF +} + + + diff --git a/EmonTX/emonTxV3_4_continuous_kwhtotals/emonTxV3_4_continuous_kwhtotals.ino b/EmonTX/emonTxV3_4_continuous_kwhtotals/emonTxV3_4_continuous_kwhtotals.ino new file mode 100644 index 0000000..78084a9 --- /dev/null +++ b/EmonTX/emonTxV3_4_continuous_kwhtotals/emonTxV3_4_continuous_kwhtotals.ino @@ -0,0 +1,337 @@ +// +// EmonTx v3.4 Continuous sampling With WH Totals Beta +// + +#define firmware_version "v0.2" +#define emonTxV3 +#define RF69_COMPAT 1 // Set to 1 if using RFM69CW or 0 is using RFM12B + +#include +#include +#include +#include + +ISR(WDT_vect) { Sleepy::watchdogEvent(); } + + +//----------------------------emonTx V3 Settings--------------------------------------------------------------------------------------------------------------- +const byte Vrms = 230; // Vrms for apparent power readings (when no AC-AC voltage sample is present) +const double TIME_BETWEEN_READINGS = 9.5; // Time between readings + +//http://openenergymonitor.org/emon/buildingblocks/calibration + +const float Ical1= 90.9; // (2000 turns / 22 Ohm burden) = 90.9 +const float Ical2= 90.9; // (2000 turns / 22 Ohm burden) = 90.9 +const float Ical3= 90.9; // (2000 turns / 22 Ohm burden) = 90.9 +const float Ical4= 16.67; // (2000 turns / 120 Ohm burden) = 16.67 +float Vcal= 260.4; // (230V x 13) / (9V x 1.2) = 276.9 Calibration for UK AC-AC adapter 77DB-06-09 + +//float Vcal=276.9; +//const float Vcal= 260; // Calibration for EU AC-AC adapter 77DE-06-09 +const float Vcal_USA= 130.0; // Calibration for US AC-AC adapter 77DA-10-09 +boolean USA=FALSE; + +const byte min_pulsewidth= 110; // minimum width of interrupt pulse (default pulse output meters = 100ms) +const int TEMPERATURE_PRECISION= 11; // 9 (93.8ms),10 (187.5ms) ,11 (375ms) or 12 (750ms) bits equal to resplution of 0.5C, 0.25C, 0.125C and 0.0625C +const byte MaxOnewire= 4; +#define ASYNC_DELAY 375 // DS18B20 conversion delay - 9bit requres 95ms, 10bit 187ms, 11bit 375ms and 12bit resolution takes 750ms +//------------------------------------------------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------------------------------------------------- + + +//----------------------------emonTx V3 hard-wired connections--------------------------------------------------------------------------------------------------------------- +const byte LEDpin= 6; // emonTx V3 LED +const byte DS18B20_PWR= 19; // DS18B20 Power +const byte DIP_switch1= 8; // Voltage selection 230 / 110 V AC (default switch off 230V) - switch off D8 is HIGH from internal pullup +const byte DIP_switch2= 9; // RF node ID (default no chance in node ID, switch on for nodeID -1) switch off D9 is HIGH from internal pullup +const byte battery_voltage_pin= 7; // Battery Voltage sample from 3 x AA +const byte pulse_countINT= 1; // INT 1 / Dig 3 Terminal Block / RJ45 Pulse counting pin(emonTx V3.4) - (INT0 / Dig2 emonTx V3.2) +const byte pulse_count_pin= 3; // INT 1 / Dig 3 Terminal Block / RJ45 Pulse counting pin(emonTx V3.4) - (INT0 / Dig2 emonTx V3.2) +#define ONE_WIRE_BUS 5 // DS18B20 Data +//------------------------------------------------------------------------------------------------------------------------------------------- + +//Setup DS128B20 +OneWire oneWire(ONE_WIRE_BUS); +DallasTemperature sensors(&oneWire); +byte allAddress [MaxOnewire][8]; // 8 bytes per address +byte numSensors; +//------------------------------------------------------------------------------------------------------------------------------------------- + +//-----------------------RFM12B / RFM69CW SETTINGS---------------------------------------------------------------------------------------------------- +#define RF_freq RF12_433MHZ // Frequency of RF69CW module can be RF12_433MHZ, RF12_868MHZ or RF12_915MHZ. You should use the one matching the module you have. +byte nodeID = 10; // emonTx RFM12B node ID +const int networkGroup = 210; + +#define RETRY_PERIOD 100 // how soon to retry if ACK didn't come in +#define RETRY_LIMIT 2 // maximum number of times to retry +#define ACK_TIME 40 // number of milliseconds to wait for an ack +#define RADIO_SYNC_MODE 2 + +typedef struct { + unsigned long msg; + int power1,power2, power3, power4, Vrms; + signed long kw1, kw2, kw3, kw4; + unsigned long pulseCount; + // unsigned long retry; + unsigned long fail; +} PayloadTX; + +PayloadTX emontx; + +boolean CT1, CT2, CT3, CT4, debug, DS18B20_STATUS; +volatile byte pulseCount = 0; +unsigned long pulsetime=0; +// Record time of interrupt pulse +unsigned long lastsent = 0; + + +void setup() +{ + pinMode(LEDpin, OUTPUT); + digitalWrite(LEDpin,HIGH); + + pinMode(pulse_count_pin, INPUT_PULLUP); // Set emonTx V3.4 interrupt pulse counting pin as input (Dig 3 / INT1) + emontx.pulseCount=0; // Make sure pulse count starts at zero + + Serial.begin(9600); + + Serial.print("emonTx V3.4 Continuous Beta "); Serial.print(firmware_version); + #if (RF69_COMPAT) + Serial.println(" RFM69CW"); + #else + Serial.println(" RFM12B"); + #endif + Serial.println("OpenEnergyMonitor.org"); + + // READ DIP SWITCH POSITIONS + pinMode(DIP_switch1, INPUT_PULLUP); + pinMode(DIP_switch2, INPUT_PULLUP); + if (digitalRead(DIP_switch1)==LOW && digitalRead(DIP_switch2)==LOW) nodeID = 4; // IF DIP switch 1 is switched on then subtract 1 from nodeID + if (digitalRead(DIP_switch1)==HIGH && digitalRead(DIP_switch2)==LOW) nodeID = 5; + if (digitalRead(DIP_switch1)==LOW && digitalRead(DIP_switch2)==HIGH) nodeID = 6; + if (digitalRead(DIP_switch1)==HIGH && digitalRead(DIP_switch2)==HIGH) nodeID = 7; + + if (USA==TRUE){ // if USA mode is true + Vcal=Vcal_USA; // Assume USA AC/AC adatper is being used, set calibration accordingly + } + + delay(10); + rf12_initialize(nodeID, RF_freq, networkGroup); // initialize RFM12B/rfm69CW + for (int i=10; i>=0; i--) // Send RF test sequence (for factory testing) + { + emontx.power1=i; + rf12_sendNow(0, &emontx, sizeof emontx); + delay(100); + } + rf12_sendWait(2); + emontx.power1=0; + + emontx.msg = 0; + emontx.fail = 0; + // emontx.retry = 0; + + digitalWrite(LEDpin,LOW); + + //################################################################################################################################ + //Setup and for presence of DS18B20 + //################################################################################################################################ + pinMode(DS18B20_PWR, OUTPUT); + digitalWrite(DS18B20_PWR, HIGH); delay(100); + sensors.begin(); + sensors.setWaitForConversion(false); // disable automatic temperature conversion to reduce time spent awake, conversion will be implemented manually in sleeping + // http://harizanov.com/2013/07/optimizing-ds18b20-code-for-low-power-applications/ + numSensors=(sensors.getDeviceCount()); + if (numSensors > MaxOnewire) numSensors=MaxOnewire; // Limit number of sensors to max number of sensors + for (byte j=0; jsleep->start mode + + EmonLibCM_voltageCal(Vcal*(3.3/1023)); // 260.4 * (3.3/1023) + + EmonLibCM_currentCal(0,Ical1*(3.3/1023)); // 2000 turns / 22 Ohms burden resistor + EmonLibCM_currentCal(1,Ical2*(3.3/1023)); // 2000 turns / 22 Ohms burden resistor + EmonLibCM_currentCal(2,Ical3*(3.3/1023)); // 2000 turns / 22 Ohms burden resistor + EmonLibCM_currentCal(3,Ical4*(3.3/1023)); // 2000 turns / 120 Ohms burden resistor + + EmonLibCM_phaseCal(0,0.22); + EmonLibCM_phaseCal(1,0.41); + EmonLibCM_phaseCal(2,0.60); + EmonLibCM_phaseCal(3,1.25); + + EmonLibCM_Init(); + + attachInterrupt(pulse_countINT, onPulse, FALLING); // Attach pulse counting interrupt pulse counting + +} //end SETUP + +void loop() +{ + if (EmonLibCM_Ready()) + { + // if (EmonLibCM_ACAC) {digitalWrite(LEDpin, HIGH); delay(10); digitalWrite(LEDpin, LOW);} // flash LED if powered by AC + + if (EmonLibCM_ACAC) { + EmonLibCM_datalog_period(TIME_BETWEEN_READINGS); + emontx.Vrms = EmonLibCM_Vrms*100; + emontx.power1 = EmonLibCM_getRealPower(0); + emontx.power2 = EmonLibCM_getRealPower(1); + emontx.power3 = EmonLibCM_getRealPower(2); + emontx.power4 = EmonLibCM_getRealPower(3); + emontx.kw1 = EmonLibCM_getWattHour(0); + emontx.kw2 = EmonLibCM_getWattHour(1); + emontx.kw3 = EmonLibCM_getWattHour(2); + emontx.kw4 = EmonLibCM_getWattHour(3); + } else { + emontx.Vrms = Vrms*100; + emontx.power1 = Vrms * EmonLibCM_getIrms(0); + emontx.power2 = Vrms * EmonLibCM_getIrms(1); + emontx.power3 = Vrms * EmonLibCM_getIrms(2); + emontx.power4 = Vrms * EmonLibCM_getIrms(3); + emontx.kw1 = 0; + emontx.kw2 = 0; + emontx.kw3 = 0; + emontx.kw4 = 0; + } + // read battery voltage if powered by DC + // int battery_voltage=analogRead(battery_voltage_pin) * 0.681322727; // 6.6V battery = 3.3V input = 1024 ADC + + if (DS18B20_STATUS==1) + { + digitalWrite(DS18B20_PWR, HIGH); + delay(50); + sensors.requestTemperatures(); + // Must wait for conversion, since we use ASYNC mode + if (EmonLibCM_ACAC) delay(ASYNC_DELAY); else Sleepy::loseSomeTime(ASYNC_DELAY); + + digitalWrite(DS18B20_PWR, LOW); + } + + if (pulseCount) // if the ISR has counted some pulses, update the total count + { + cli(); // Disable interrupt just in case pulse comes in while we are updating the count + emontx.pulseCount += pulseCount; + pulseCount = 0; + sei(); // Re-enable interrupts + } + + if (debug==1) { + Serial.print("data: "); + Serial.print(emontx.power1); Serial.print(" "); + Serial.print(emontx.power2); Serial.print(" "); + Serial.print(emontx.power3); Serial.print(" "); + Serial.print(emontx.power4); Serial.print(" "); + Serial.print(emontx.Vrms); Serial.print(" "); + Serial.print(emontx.pulseCount); Serial.print(" "); + if (DS18B20_STATUS==1){ + + } + Serial.print(", "); + Serial.print(millis()-lastsent); + Serial.println("ms"); + lastsent = millis(); + + delay(50); + } + + emontx.msg++; + if (!rfm69send()) { + emontx.fail++; + } + + if (!EmonLibCM_ACAC) { + int sleeptime = (TIME_BETWEEN_READINGS - 1)*1000; + if (DS18B20_STATUS) sleeptime -= (ASYNC_DELAY+50); + sleeptime -= 100; + EmonLibCM_Stop(); + delay(50); + msdelay(sleeptime); + EmonLibCM_datalog_period(1); + EmonLibCM_Start(); + } + } +} + +// The interrupt routine - runs each time a falling edge of a pulse is detected +void onPulse() +{ + if ( (millis() - pulsetime) > min_pulsewidth) { + pulseCount++; // calculate wh elapsed from time between pulses + } + pulsetime=millis(); +} + +void msdelay(int ms) +{ + // delay(ms); + Sleepy::loseSomeTime(ms); +} + +bool rfm69send() { + uint32_t sentTime; + bool success = false; + for (uint8_t i=0; i<=RETRY_LIMIT; i++) + { + rf12_sendNow(RF12_HDR_ACK, &emontx, sizeof emontx); + rf12_sendWait(RADIO_SYNC_MODE); + sentTime = millis(); + while (millis()-sentTime /dev/null > /dev/null + +$(filter %/djangojs.pot, $(POT_FILES)): + @echo makemessages $$(dirname $$(dirname $@))/djangojs.po + -@APP=$$(dirname $$(dirname $$(dirname $$(dirname $@))));\ + LC=$$(basename $$(dirname $$(dirname $@)));\ + mkdir -p $$APP/locale;\ + cd $$APP;\ + django-admin.py makemessages -d djangojs -l $$LC 2> /dev/null > /dev/null + +$(PO_FILES:.po=.mo) : %.mo : %.po + @APP=$$(dirname $$(dirname $$(dirname $$(dirname $*))));\ + echo compilemessages $$APP;\ + cd $$APP;\ + django-admin.py compilemessages + +.PHONY: compilemessages +compilemessages: $(patsubst %.po,%.mo,$(filter $(shell find . -name "*.po"), $(PO_FILES))) + +# Create zip file of PO-files for a given locale, preserving directory +# structure. Usage:: +# +# make es_translation.zip +$(addsuffix _translation.zip, $(LOCALES)) : %_translation.zip : + @echo zip $@ + @find . -path "*/locale/$*/*" -name "*.po" | xargs zip $@ + + +# Flake8 +# ====== +MODIFIED_FILES = $(shell git status --porcelain | awk '/^ ?[AMU].*\.py$$/ {print $$2}' | grep -v '/migrations/') + +.PHONY: flake8 +flake8: +ifneq ($(MODIFIED_FILES), ) + flake8 $(MODIFIED_FILES) $(FLAKE8FLAGS) +else + @echo "No modifications, skipping flake8" +endif + + +# Unit tests +# ========== +TESTS := $(subst /,.,$(APPS)) +RERUN_TESTS := $(if $(wildcard test_rerun.txt),$(shell grep -v '^unittest.loader.ModuleImportFailure' test_rerun.txt),$(TESTS)) +TESTFLAGS := --noinput --traceback + +DJANGO_SETTINGS_MODULE := gridplatform.settings.test + +# Run tests for all our apps +.PHONY: test +test: flake8 + DJANGO_SETTINGS_MODULE=$(DJANGO_SETTINGS_MODULE) \ + ./manage.py test $(TESTS) $(TESTFLAGS) + +# Run tests marked for rerun by the test runner +.PHONY: test-rerun +test-rerun: flake8 + DJANGO_SETTINGS_MODULE=$(DJANGO_SETTINGS_MODULE) \ + ./manage.py test $(RERUN_TESTS) $(TESTFLAGS) + +COVERAGE_INCLUDE_PATTERN = *gridplatform/*,*energymanager/*,*legacy/* + +.PHONY: test-coverage +test-coverage: flake8 + DJANGO_SETTINGS_MODULE=$(DJANGO_SETTINGS_MODULE) \ + coverage run --branch \ + ./manage.py test $(TESTS) $(TESTFLAGS) && \ + coverage report --include="$(COVERAGE_INCLUDE_PATTERN)" --omit="*/migrations/*" --show-missing + +# Prerequisites of running selenium-test target: +# +# - pip install selenium +# - apt-get install xvfb +# - download and extract the relevant chromedriver to the current directory: +# wget http://chromedriver.storage.googleapis.com/2.9/chromedriver_linux64.zip +# unzip chromedriver_linux64.zip +.PHONY: selenium-test +selenium-test: export PATH+=:$(abspath .) +selenium-test: export SELENIUM_SERVER=TRUE +selenium-test: test + + +# Playground... +# ============= +.PHONY: tags +tags: TAGS + +.PHONY: TAGS +TAGS: + find . -name "[a-z_]*.py" | xargs etags + +.PHONY: test-failures +test-failures: flake8 failure-list.txt + test -s failure-list.txt + DJANGO_SETTINGS_MODULE=$(DJANGO_SETTINGS_MODULE) \ + ./manage.py test $(shell cat failure-list.txt) $(TESTFLAGS) + + +TESTRUNNERS = $(addsuffix .run, $(TESTS)) + +.PHONY: $(TESTRUNNERS) +$(TESTRUNNERS): %.run : flake8 + DJANGO_SETTINGS_MODULE=$(DJANGO_SETTINGS_MODULE) \ + TEST_DATABASE_NAME=test_$* \ + TEST_LOG_FILE=$*.log \ + TEST_RERUN_FILE=$*.rerun \ + ./manage.py test $* $(TESTFLAGS) --verbosity=0 + +.PHONY: parallel-test +parallel-test: $(TESTRUNNERS) + +# Intentionally fail rebuilding this target if there were any import errors. +failure-list.txt: $(wildcard *.rerun) $(wildcard test_rerun.txt) + test -n "$?" + cat $? | grep -q '^unittest.loader.ModuleImportFailure'; test $$? -ne 0 + cat $? | sort | uniq > $@ + +SCSS_FILES = $(shell find legacy/website/static/ -type f -name "*.scss") + +legacy/website/static/style.css : $(SCSS_FILES) + scss legacy/website/static/style.scss:legacy/website/static/style.css + +.PHONY: scss +scss: legacy/website/static/style.css + + +.PHONY: clean +clean: + find . -name "*.pyc" -delete + rm -f *.rerun + rm -f *.log + rm -f GridPlatform.pdf GridPlatformDomainModel.pdf + +.PHONY: html +html: + PYTHONPATH=$(abspath .) sphinx-build -b html documentation/source documentation/build + +.PHONY: pdf +pdf: GridPlatform.pdf GridPlatformDomainModel.pdf + +RST_FILES = $(shell find documentation/source . -name "*.rst") +PY_FILES = $(shell find documentation/source . -name "*.py") + +GridPlatform.pdf GridPlatformDomainModel.pdf: $(RST_FILES) $(PY_FILES) + PYTHONPATH=$(abspath .) sphinx-build -b latex documentation/source documentation/build + make -C documentation/build + cp documentation/build/GridPlatform.pdf ./ + cp documentation/build/GridPlatformDomainModel.pdf ./ diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..2aa9dd4 --- /dev/null +++ b/README.txt @@ -0,0 +1,6 @@ +The documentation is made with Sphinx and a precompiled version in both HTML +and PDF format is delivered with this package. You can find it in the folder: + +documentation/dist + +Go read that documentation to get started. diff --git a/compilemessages.sh b/compilemessages.sh new file mode 100755 index 0000000..bad4c32 --- /dev/null +++ b/compilemessages.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +for d in `find gridplatform -maxdepth 1 -type d` +do + if [ $d = 'gridplatform' ] + then + continue + fi + cd $d + django-admin.py compilemessages + cd - +done diff --git a/doc/csgruppen/tarif_setup_script.py b/doc/csgruppen/tarif_setup_script.py new file mode 100644 index 0000000..8202cb9 --- /dev/null +++ b/doc/csgruppen/tarif_setup_script.py @@ -0,0 +1,30 @@ +""" + Don't run directly... C/P into ./manage.py shell. ONLY ONCE, AND ONLY AFTER NORD POOL FETCH!!! +""" +import datetime + +from pytz import timezone + +from gridplatform.tariffs.models import EnergyTariff +from gridplatform.tariffs.models import SpotPricePeriod +from gridplatform.global_datasources.models import GlobalDataSource + +dk1 = GlobalDataSource.objects.get( + name="dk1", app_label="nordpool", codename="nordpool_dk1", + country="DK", unit="currency_dkk*gigawatt^-1*hour^-1") +dk2 = GlobalDataSource.objects.get( + name="dk2", app_label="nordpool", codename="nordpool_dk2", + country="DK", unit="currency_dkk*gigawatt^-1*hour^-1") + +tariff = EnergyTariff.objects.get(pk=1) + +period = SpotPricePeriod.objects.create( + datasequence=tariff, + spotprice=dk1, + coefficient=1, + unit_for_constant_and_ceiling="currency_dkk*kilowatt^-1*hour^-1", + constant=0, + from_timestamp=datetime.datetime.now().replace(tzinfo=timezone('Europe/Copenhagen')), + subscription_fee=0, + subscription_period=3 +) diff --git a/doc/portal_setup.txt b/doc/portal_setup.txt new file mode 100644 index 0000000..8b17260 --- /dev/null +++ b/doc/portal_setup.txt @@ -0,0 +1,17 @@ +from gridplatform.users.models import User +from gridplatform.encryption.testutils import encryption_context + +with encryption_context(): + root = User.objects.create_user('root', 'hemmeligt', user_type=User.ADMIN) + root.is_staff = True + root.is_superuser = True + root.save() + + + +dropdb portal +createdb -E utf8 portal + +gunzip -c initial.sql.gz | psql portal > /dev/null +./manage.py migrate --all --noinput --traceback +./manage.py fix_contenttypes_and_permissions \ No newline at end of file diff --git a/doc/testdata.txt b/doc/testdata.txt new file mode 100644 index 0000000..0727c6e --- /dev/null +++ b/doc/testdata.txt @@ -0,0 +1,27 @@ +from gridplatform.datasources.models import * +from gridplatform.customer_datasources.models import * +import datetime +ds = CustomerDataSource.objects.get(pk=2) +start = datetime.datetime.now() +for x in range(1,60*24*7): + RawData.objects.create(timestamp=start, value=230000, unit='milivolt', datasource=ds) + start = start - datetime.timedelta(minutes=1) + + + +import datetime +import pytz +from gridplatform.datasources.models import * +from gridplatform.customer_datasources.models import * +data_source = CustomerDataSource.objects.get(pk=14) +timestamp = datetime.datetime(2015, 11, 1, 22, 29, 0, tzinfo=pytz.timezone('UTC')) +consumption = 0 +for x in xrange(1, 144000): + RawData.objects.create( + datasource=data_source, + value=consumption, + unit='milliwatt*hour', + timestamp=timestamp + ) + consumption += 6666 + timestamp += datetime.timedelta(minutes=1) diff --git a/doc/wifiagent_setup.mdown b/doc/wifiagent_setup.mdown new file mode 100644 index 0000000..0fc31c6 --- /dev/null +++ b/doc/wifiagent_setup.mdown @@ -0,0 +1,9 @@ +# Wifi Agent Software Setup + +## Database + +### User +`sudo -u postgres createuser --superuser $USER` + +`createdb --encoding=utf-8 agent` + diff --git a/documentation/source/apps.rst b/documentation/source/apps.rst new file mode 100644 index 0000000..de3d972 --- /dev/null +++ b/documentation/source/apps.rst @@ -0,0 +1,26 @@ +Apps +**** + +.. toctree:: + apps/gridplatform/bootstrap + apps/gridplatform/co2conversions + apps/gridplatform/condensing + apps/gridplatform/consumptions + apps/gridplatform/costcompensations + apps/gridplatform/customer_datasources + apps/gridplatform/customers + apps/gridplatform/datasequences + apps/gridplatform/datasources + apps/gridplatform/encryption + apps/gridplatform/energyperformances + apps/gridplatform/global_datasources + apps/gridplatform/productions + apps/gridplatform/provider_datasources + apps/gridplatform/providers + apps/gridplatform/reports + apps/gridplatform/rest + apps/gridplatform/tariffs + apps/gridplatform/token_auth + apps/gridplatform/trackuser + apps/gridplatform/users + apps/gridplatform/utils diff --git a/documentation/source/apps/gridplatform/bootstrap.rst b/documentation/source/apps/gridplatform/bootstrap.rst new file mode 100644 index 0000000..edcb713 --- /dev/null +++ b/documentation/source/apps/gridplatform/bootstrap.rst @@ -0,0 +1,25 @@ +Bootstrap +========= + +Configuration +------------- + +.. automodule:: gridplatform.bootstrap.conf + +Template Tags +------------- + +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.parse_token_arguments +.. autoclass:: gridplatform.bootstrap.templatetags.bootstrap_tags.BootstrapNode + :members: get_templates +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_icon +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.checkbox_icon_name +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_panel +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_field_input +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_field_label +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_field +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_hidden_field +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_non_field_errors +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_form +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_form_buttons +.. autofunction:: gridplatform.bootstrap.templatetags.bootstrap_tags.do_bootstrap_form diff --git a/documentation/source/apps/gridplatform/co2conversions.rst b/documentation/source/apps/gridplatform/co2conversions.rst new file mode 100644 index 0000000..153e47c --- /dev/null +++ b/documentation/source/apps/gridplatform/co2conversions.rst @@ -0,0 +1,19 @@ +.. _co2-conversions: + +CO₂ Conversions +=============== + +The CO₂ Conversions app define a small class hierachy of CO₂ +Conversions. The base class is :py:class:`Co2Conversion`, which is +abstract in the OO sense. :py:class:`Co2Conversion` is inherited by +:py:class:`DynamicCo2Conversion` and :py:class:`FixedCo2Conversion` +which are both concrete. + +.. autoclass:: gridplatform.co2conversions.models.Co2Conversion + :members: clean, _value_sequence + +.. autoclass:: gridplatform.co2conversions.models.DynamicCo2Conversion + :members: clean + +.. autoclass:: gridplatform.co2conversions.models.FixedCo2Conversion + :members: clean diff --git a/documentation/source/apps/gridplatform/condensing.rst b/documentation/source/apps/gridplatform/condensing.rst new file mode 100644 index 0000000..012c7fc --- /dev/null +++ b/documentation/source/apps/gridplatform/condensing.rst @@ -0,0 +1,35 @@ +Condensing +======================================================== + +This app defines models and utilities to optimize the data of +:py:class:`DataSources<.DataSource>` for further computations. In particular +many computations benifit from working on samples with fixed durations, mostly +this duration is one hour, but some times it is five minutes. + +The the timestamps of :py:class:`.RawData` are not always guaranteed to be on +the hour (or a five minute multiplum), in particular not those that stem from +meters. Therefore interpolation is often required. Interpolation is +computation wise relative expensive on :class:`datetime.datetime` objects. + +So what this app does is compute relevant +:py:class:`RangedSamples<.RangedSample>` for relevant +:py:class:`DataSources<.DataSource>` and store them in the database (as +:py:class:`.HourAccumulatedData` and :py:class:`.FiveMinuteAccumulatedData`). +This gives a performance boost by order of magnitude as they only need to be +computed once, and the extra space taken up by these values is not an issue. + +Models +------ + +.. automodule:: gridplatform.condensing.models + :members: validate_hour, validate_five_minutes, AccumulatedData, + HourAccumulatedData, FiveMinuteAccumulatedData, + cleanup_cache_for_rawdata_delete, get_hourly_accumulated, + get_five_minute_accumulated, get_accumulated, generate_cache, + missing_periods, generate_period_data, raw_data_for_cache, + adjust_from_to, period_aligned + +Commands +-------- + +.. automodule:: gridplatform.condensing.management.commands.generate_cache diff --git a/documentation/source/apps/gridplatform/consumptions.rst b/documentation/source/apps/gridplatform/consumptions.rst new file mode 100644 index 0000000..a09b9fa --- /dev/null +++ b/documentation/source/apps/gridplatform/consumptions.rst @@ -0,0 +1,58 @@ +Consumptions +============ + +This app defines models directly related to consumption, including +main consumptions, energy uses and consumption data sequences. + +Main Consumption and Energy Use +------------------------------- + +The consumptions app defines the models +:py:class:`~gridplatform.consumptions.models.MainConsumption` and +:py:class:`~gridplatform.consumptions.models.ConsumptionGroup`, where +the later should have been named ``EnergyUse``. The commonality +between these two models are sufficiently big that they share a base +class +:py:class:`~gridplatform.consumptions.models.ConsumptionUnionBase`. + + +.. autoclass:: gridplatform.consumptions.models.ConsumptionUnionBase + :members: energy_sum, energy_sequence, utility_sum, utility_sequence, + net_cost_sum, net_cost_sequence, + variable_cost_sum, variable_cost_sequence, + costcompensation_amount_sum, + co2_emissions_sum, co2_emissions_sequence + +.. autoclass:: gridplatform.consumptions.models.MainConsumption + :members: costcompensation_amount_sequence, total_cost_sum, fixed_cost_sum + +.. autoclass:: gridplatform.consumptions.models.ConsumptionGroup + :members: costcompensation_amount_sequence + +Consumption Data Sequence +------------------------- + +Secondarily the +:py:class:`~gridplatform.consumptions.models.Consumption` (a +``DataSequence`` specialization) is defined, along with small pallete +of input configuration periods. + +In particular one period +:py:class:`~gridplatform.consumptions.models.NonepulsePeriod` is used +to define the ``utility_sequence()`` of ``Consumption`` directly from +``DataSource`` with the relevant utility unit, and another period +:py:class:`~gridplatform.consumptions.models.PulsePeriod` is used to +define the ``utility_sequence()`` of ``Consumption`` via pulse +conversion from ``DataSource`` with the ``"impulse"`` unit. Finally a +period that skips the ``DataSource`` framework entirely is available, +the :py:class:`~gridplatform.consumptions.models.SingleValuePeriod`. + +.. autoclass:: gridplatform.consumptions.models.Consumption + :members: clean, energy_sequence, energy_sum, + utility_sequence, utility_sum + +.. autoclass:: gridplatform.consumptions.models.NonpulsePeriod + +.. autoclass:: gridplatform.consumptions.models.PulsePeriod + +.. autoclass:: gridplatform.consumptions.models.SingleValuePeriod diff --git a/documentation/source/apps/gridplatform/costcompensations.rst b/documentation/source/apps/gridplatform/costcompensations.rst new file mode 100644 index 0000000..66b1543 --- /dev/null +++ b/documentation/source/apps/gridplatform/costcompensations.rst @@ -0,0 +1,25 @@ +Cost Compensations +================== + +Cost compensations are described in the domain model in the section +:ref:`cost-compensations`. To facilitate changes in the domain, as mentioned +in :ref:`changes-in-domain`, the +:py:class:`~gridplatform.cost_compensations.models.CostCompensation` is defined +in terms of periods, namely +:py:class:`~gridplatform.cost_compensations.models.FixedCompensationPeriod`. +The periods are associated to cost compensations via the +:py:class:`~gridplatform.cost_compensations.models.CostCompensationPeriodManager`. + +A simpler design for solving a simular task is described in +:ref:`co2-conversions`. + +.. autoclass:: gridplatform.cost_compensations.models.CostCompensation + +.. autoclass:: gridplatform.cost_compensations.models.CostCompensationPeriodManager + :members: value_sequence + +.. autoclass:: gridplatform.cost_compensations.models.Period + + +.. autoclass:: gridplatform.cost_compensations.models.FixedCompensationPeriod + :members: clean diff --git a/documentation/source/apps/gridplatform/customer_datasources.rst b/documentation/source/apps/gridplatform/customer_datasources.rst new file mode 100644 index 0000000..05011a1 --- /dev/null +++ b/documentation/source/apps/gridplatform/customer_datasources.rst @@ -0,0 +1,10 @@ +Customer Data Sources +===================== + +This app defines :class:`~gridplatform.datasources.models.DataSource` owned by +:class:`~gridplatform.customers.models.Customer` +(:class:`~gridplatform.customer_datasources.models.CustomerDataSource`) and +shared among the :class:`~gridplatform.customers.models.Customer` of that +:class:`~gridplatform.customers.models.Customer`. + +.. autoclass:: gridplatform.customer_datasources.models.CustomerDataSource diff --git a/documentation/source/apps/gridplatform/customers.rst b/documentation/source/apps/gridplatform/customers.rst new file mode 100644 index 0000000..a330b60 --- /dev/null +++ b/documentation/source/apps/gridplatform/customers.rst @@ -0,0 +1,15 @@ +Customers +========= + +The ``customers`` app defines the +:py:class:`~gridplatform.customers.models.Customer` model, which in turn +represent the entity that owns any particular instance of the domain. + +.. autoclass:: gridplatform.customers.models.Customer + :members: clean_fields, save, now, get_encryption_id, satisfies_search, + get_production_unit_choices + +.. autoclass:: gridplatform.customers.managers.CustomerManager + +.. autoclass:: gridplatform.customers.managers.CustomerQuerySetMixin + :members: _apply_filtering diff --git a/documentation/source/apps/gridplatform/datasequences.rst b/documentation/source/apps/gridplatform/datasequences.rst new file mode 100644 index 0000000..2dcc658 --- /dev/null +++ b/documentation/source/apps/gridplatform/datasequences.rst @@ -0,0 +1,89 @@ +Data Sequences +============== + +Data sequences are the glue between sources of data and applications of data. +To support :ref:`changes-in-domain` data sequences are defined in terms of +periods. This app defines base classes and utility functions and utility +classes related to this task. + +Models +------ + +.. autoclass:: gridplatform.datasequences.models.CurrencyUnitMixin + +Base +~~~~ + +.. autofunction:: gridplatform.datasequences.models.base.is_clock_hour +.. autofunction:: gridplatform.datasequences.models.base.is_five_minute_multiplum +.. autoclass:: gridplatform.datasequences.models.DataSequenceBase + :members: next_valid_date, previous_valid_date, validate_requirements +.. autoclass:: gridplatform.datasequences.models.base.PeriodBaseManager + :members: in_range +.. autoclass:: gridplatform.datasequences.models.PeriodBase + :members: clean, clean_overlapping_periods + +Accumulation +~~~~~~~~~~~~ + +.. autoclass:: gridplatform.datasequences.models.AccumulationBase + :members: _hourly_accumulated, _five_minute_accumulated, + development_sequence, development_sum +.. autoclass:: gridplatform.datasequences.models.accumulation.AccumulationPeriodManager +.. autoclass:: gridplatform.datasequences.models.AccumulationPeriodBase + :members: _hourly_accumulated, _five_minute_accumulated, _get_unit +.. autoclass:: gridplatform.datasequences.models.NonpulseAccumulationPeriodMixin + :members: clean, _hourly_accumulated, _five_minute_accumulated +.. autoclass:: gridplatform.datasequences.models.PulseAccumulationPeriodMixin + :members: clean, _convert_sample, _hourly_accumulated, + _five_minute_accumulated +.. autoclass:: gridplatform.datasequences.models.SingleValueAccumulationPeriodMixin + :members: clean, _period_accumulated, _hourly_accumulated, + _five_minute_accumulated + +Energy Conversion +~~~~~~~~~~~~~~~~~ + +.. autofunction:: gridplatform.datasequences.models.energyconversion._break_into_hourly_samples +.. autoclass:: gridplatform.datasequences.models.EnergyPerVolumeDataSequence +.. autoclass:: gridplatform.datasequences.models.energyconversion.VolumeToEnergyConversionPeriodManager + :members: value_sequence +.. autoclass:: gridplatform.datasequences.models.EnergyPerVolumePeriod + :members: _raw_samples, _value_sequence + +Nonaccumulation +~~~~~~~~~~~~~~~ + +.. autoclass:: gridplatform.datasequences.models.NonaccumulationDataSequence + :members: clean, raw_sequence +.. autoclass:: gridplatform.datasequences.models.NonaccumulationPeriod + :members: _raw_sequence + +Piece-wise Constant +~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: gridplatform.datasequences.models.PiecewiseConstantBase +.. autoclass:: gridplatform.datasequences.models.piecewiseconstant.PiecewiseConstantPeriodManagerBase + :members: value_sequence +.. autoclass:: gridplatform.datasequences.models.PiecewiseConstantPeriodManager +.. autoclass:: gridplatform.datasequences.models.PiecewiseConstantPeriodBase + :members: _value_sequence +.. autoclass:: gridplatform.datasequences.models.piecewiseconstant.FixedPiecewiseConstantPeriodValueSequenceMixin + :members: _value_sequence + +Quality Control +~~~~~~~~~~~~~~~ + +.. autoclass:: gridplatform.datasequences.models.OfflineToleranceMixin + :members: validate_requirement +.. autoclass:: gridplatform.datasequences.models.NonaccumulationOfflineTolerance + +Utilities +--------- + +.. automodule:: gridplatform.datasequences.utils + :members: _pad_ranged_sample_sequence, multiply_ranged_sample_sequences, + subtract_ranged_sample_sequences, add_ranged_sample_sequences, + _fiveminutes_period_key, _hour_period_key, _day_period_key, + _month_period_key, _quarter_period_key, _year_period_key, + _PERIOD_KEYS, aggregate_sum_ranged_sample_sequence diff --git a/documentation/source/apps/gridplatform/datasources.rst b/documentation/source/apps/gridplatform/datasources.rst new file mode 100644 index 0000000..d845897 --- /dev/null +++ b/documentation/source/apps/gridplatform/datasources.rst @@ -0,0 +1,23 @@ +Data Sources +============ + +.. autoclass:: gridplatform.datasources.models.DataSource + :members: hourly_accumulated, five_minute_accumulated, _get_interpolate_fn, + raw_sequence, next_valid_date, previous_valid_date + +.. autoclass:: gridplatform.datasources.models.RawData + :members: clean, interpolate + +Managers +-------- + +.. autoclass:: gridplatform.datasources.managers.DataSourceQuerySetMixinBase + :members: _apply_filtering, _apply_customer_filtering, _apply_provider_filtering + + +.. autoclass:: gridplatform.datasources.managers.DataSourceQuerySetMixin + :members: _apply_customer_filtering, _apply_provider_filtering + +.. autoclass:: gridplatform.datasources.managers.DataSourceManagerBase + +.. autoclass:: gridplatform.datasources.managers.DataSourceManager diff --git a/documentation/source/apps/gridplatform/encryption.rst b/documentation/source/apps/gridplatform/encryption.rst new file mode 100644 index 0000000..a2e4a05 --- /dev/null +++ b/documentation/source/apps/gridplatform/encryption.rst @@ -0,0 +1,80 @@ +Encryption +========== + +To make sure no customer's confidential data is ever leaked we encrypt all +texts written by our users with a key specific to the organization of that +user. + + +Models +------ + +.. autoclass:: gridplatform.encryption.models.EncryptedModel + :members: __init__, save, _encrypt, _decrypt, reset_encryption, get_encryption_id, + clean_fields + +.. autoclass:: gridplatform.encryption.models.EncryptionUser + :members: generate_private_key, update_private_key, grant_key, + decrypt_private_key, decrypt_keys + +.. autoclass:: gridplatform.encryption.models.BaseEncryptionKey + :members: key_id, generate, share + +.. autoclass:: gridplatform.encryption.models.EncryptionKey + +.. autofunction:: gridplatform.encryption.models.auto_grant_to_current_user + + +Base +---- + +.. automodule:: gridplatform.encryption.base + :members: _get_cipher_module, get_cipher_module, MissingEncryptionKeyError, + _CachedKeys, EncryptionContext + +Cipher +------ + +.. automodule:: gridplatform.encryption.cipher + :members: generate_iv, generate_symmetric_key, hash_symmetric_key, + symmetric_cipher, generate_private_public_keypair, + load_private_key, load_public_key, private_key_cipher, + public_key_cipher + +Settings +-------- + +.. automodule:: gridplatform.encryption.conf + +Fields +------ + +.. automodule:: gridplatform.encryption.fields + :members: + +Filters +------- + +.. autoclass:: gridplatform.encryption.filters.DecryptingSearchFilter + +Managers +-------- + +.. automodule:: gridplatform.encryption.managers + :members: + +Middleware +---------- + +.. automodule:: gridplatform.encryption.middleware + :members: + +Shell +----- + +.. autoclass:: gridplatform.encryption.shell.Request + +Signals +------- + +.. automodule:: gridplatform.encryption.signals diff --git a/documentation/source/apps/gridplatform/energyperformances.rst b/documentation/source/apps/gridplatform/energyperformances.rst new file mode 100644 index 0000000..5bbf01c --- /dev/null +++ b/documentation/source/apps/gridplatform/energyperformances.rst @@ -0,0 +1,22 @@ +Energy Performances +=================== + +Energy performances are defined in the domain model in the section +:ref:`adjustments-etc`. The ``energyperformances`` app defines a class hierachy of +energy performances. Notably, there is the base class +:py:class:`~gridplatform.energyperformances.models.EnergyPerformance` which is +specialized by +:py:class:`~gridplatform.energyperformances.models.ProductionEnergyPerformance` +(based on production adjustments) and +:py:class:`~gridplatform.energyperformances.models.TimeEnergyPerformance` +(based on duration adjustments). + + +.. autoclass:: gridplatform.energyperformances.models.EnergyPerformance + :members: compute_performance + +.. autoclass:: gridplatform.energyperformances.models.ProductionEnergyPerformance + :members: compute_performance, clean_fields + +.. autoclass:: gridplatform.energyperformances.models.TimeEnergyPerformance + :members: compute_performance diff --git a/documentation/source/apps/gridplatform/global_datasources.rst b/documentation/source/apps/gridplatform/global_datasources.rst new file mode 100644 index 0000000..308c207 --- /dev/null +++ b/documentation/source/apps/gridplatform/global_datasources.rst @@ -0,0 +1,9 @@ +Global Data Sources +===================== + +This app defines a :class:`~gridplatform.datasources.models.DataSource` +specialization +(:class:`~gridplatform.global_datasources.models.GlobalDataSource`) shared +among all :class:`~gridplatform.customers.models.Customer` + +.. autoclass:: gridplatform.global_datasources.models.GlobalDataSource diff --git a/documentation/source/apps/gridplatform/productions.rst b/documentation/source/apps/gridplatform/productions.rst new file mode 100644 index 0000000..414e956 --- /dev/null +++ b/documentation/source/apps/gridplatform/productions.rst @@ -0,0 +1,19 @@ +Productions +=========== + +.. autoclass:: gridplatform.productions.models.Production + :members: clean, get_unit_display + +.. autoclass:: gridplatform.productions.models.ProductionGroup + :members: save, clean, development_sum, production_sequence, + next_valid_date, previous_valid_date + +.. autoclass:: gridplatform.productions.models.Period + +.. autoclass:: gridplatform.productions.models.NonpulsePeriod + +.. autoclass:: gridplatform.productions.models.PulsePeriod + +.. autoclass:: gridplatform.productions.models.SingleValuePeriod + +.. autoclass:: gridplatform.productions.models.OfflineTolerance diff --git a/documentation/source/apps/gridplatform/provider_datasources.rst b/documentation/source/apps/gridplatform/provider_datasources.rst new file mode 100644 index 0000000..904c33c --- /dev/null +++ b/documentation/source/apps/gridplatform/provider_datasources.rst @@ -0,0 +1,17 @@ +Provider Data Sources +===================== + +This app defines :class:`~gridplatform.datasources.models.DataSource` owned by +:class:`~gridplatform.providers.models.Provider` +(:class:`~gridplatform.provider_datasources.models.ProviderDataSource`) and +shared among the :class:`~gridplatform.customers.models.Customer` of that +:class:`~gridplatform.providers.models.Provider`. + +.. autoclass:: gridplatform.provider_datasources.models.ProviderDataSource + +.. autoclass:: gridplatform.provider_datasources.managers.ProviderDataSourceManager + +.. autoclass:: gridplatform.provider_datasources.managers.ProviderDataSourceManagerBase + +.. autoclass:: gridplatform.provider_datasources.managers.ProviderDataSourceQuerySetMixin + :members: _apply_customer_filtering, _apply_provider_filtering diff --git a/documentation/source/apps/gridplatform/providers.rst b/documentation/source/apps/gridplatform/providers.rst new file mode 100644 index 0000000..c1f147a --- /dev/null +++ b/documentation/source/apps/gridplatform/providers.rst @@ -0,0 +1,15 @@ +Providers +========= + +The ``providers`` app defines the +:py:class:`~gridplatform.providers.models.Provider` model, which represent the +entity that facilitates the software towards +:py:class:`~gridplatform.customers.models.Customer`. + + +.. autoclass:: gridplatform.providers.models.Provider + :members: get_encryption_id, save + +.. autofunction:: gridplatform.providers.models.auto_grant_provider_user_key + +.. autofunction:: gridplatform.providers.models.auto_grant_provider_customer_key diff --git a/documentation/source/apps/gridplatform/reports.rst b/documentation/source/apps/gridplatform/reports.rst new file mode 100644 index 0000000..faa5365 --- /dev/null +++ b/documentation/source/apps/gridplatform/reports.rst @@ -0,0 +1,112 @@ +Reports +======= + +The ``reports`` app defines some generic PDF report functionalities as +well as the first application of these functionalities, namely a +legacy consumption report. The legacy part of this app is outside the +scope of this section. + +Models +------ + +.. autoclass:: gridplatform.reports.models.Report + +Views +----- + +Reports are generated by submitting a report specific form to a +specializaton of +:py:class:`~gridplatform.reports.views.StartReportView`. If the +submitted form is valid a Celery task specific to the +:py:class:`~gridplatform.reports.views.StartReportView` specialization +is started. Ajax is then used to query +:py:func:`~gridplatform.reports.views.status` for the status of the +task (which may be rendered in a progress bar, or by a spinner icon or +similar). When :py:func:`~gridplatform.reports.views.status` reports +the task as completed, a +:py:class:`~gridplatform.reports.views.TaskForm` should be +submitted via Ajax to +:py:class:`~gridplatform.reports.views.FinalizeReportView` which then +generates the report and returns a JSON object that includes a URL to +:py:func:`~gridplatform.reports.views.serve` where the generated +report can be downloaded from. + +.. autofunction:: gridplatform.reports.views.is_queue_too_long + +.. autoclass:: gridplatform.reports.views.CeleryError + :members: __init__ + +.. autoclass:: gridplatform.reports.views.StartReportView + :members: get_task, get_task_data, start_task, form_valid, form_invalid + +.. autoclass:: gridplatform.reports.views.TaskForm + +.. autoclass:: gridplatform.reports.views.FinalizeReportView + :members: generate_report, form_valid, form_invalid + +.. autofunction:: gridplatform.reports.views.serve + +.. autofunction:: gridplatform.reports.views.status + +PDF Generation +-------------- + +PDF documents are generated by rendering a Django template into a +LaTex document and then compiling this into a PDF. + +Errors in the LaTeX code is signalled via the +:py:class:`~gridplatform.reports.pdf.LatexError` exception. + +Simple LaTex documents (without GNU Plots and free of Django +templates) are compiled via +:py:func:`~gridplatform.reports.pdf.compile_pdf`, which is implemented +in terms of :py:func:`~gridplatform.reports.pdf._compile_pdf`. + +:py:func:`~gridplatform.reports.pdf._compile_pdf` is also used in +implementing :py:func:`~gridplatform.reports.pdf._generate_pdf` (which +renders a Django template into a LaTex file first). +:py:func:`~gridplatform.reports.pdf._generate_pdf` and +:py:func:`~gridplatform.reports.pdf._generate_gnuplot` is used for +implementing :py:func:`~gridplatform.reports.pdf.generate_pdf` which +is the general interface for generating PDFs using Django templates +(rendered into LaTex files) along with GNU plots. + +.. autoclass:: gridplatform.reports.pdf.LatexError + :members: __init__ + +.. autofunction:: gridplatform.reports.pdf.compile_pdf + +.. autofunction:: gridplatform.reports.pdf._compile_pdf + +.. autofunction:: gridplatform.reports.pdf.generate_pdf + +.. autofunction:: gridplatform.reports.pdf._generate_pdf + +.. autofunction:: gridplatform.reports.pdf._generate_gnuplot + +.. autofunction:: gridplatform.reports.pdf.serve_pdf + +.. autoclass:: gridplatform.reports.pdf.PDFTemplateResponse + :members: rendered_content + +.. autoclass:: gridplatform.reports.pdf.PDFDetailView + :members: get_document_title, get_document_customer, + get_document_type, get_context_meta, get_context_data + +CSV Generation +-------------- + +CSV means comma separated values, which has stick to the text format +exported from MS Excell, even in Denmark (and other european +countries), where comma is used as decimal delimiter forcing +semi-colon to be used to seperate columns instead. + +:py:func:`~gridplatform.reports.csv.generate_csv` converts data into a +CSV format and :py:func:`~gridplatform.reports.csv.serve_csv` is +implemented in terms of +:py:func:`~gridplatform.reports.csv.generate_csv` and returns a +:py:class:`django.http.HttpResponse` holding the CSV as its content. + +.. autofunction:: gridplatform.reports.csv.generate_csv + +.. autofunction:: gridplatform.reports.csv.serve_csv diff --git a/documentation/source/apps/gridplatform/rest.rst b/documentation/source/apps/gridplatform/rest.rst new file mode 100644 index 0000000..8ad528b --- /dev/null +++ b/documentation/source/apps/gridplatform/rest.rst @@ -0,0 +1,25 @@ +**** +REST +**** + +Settings +======== + +.. automodule:: gridplatform.rest.conf + +Routers +======= + +.. automodule:: gridplatform.rest.routers + :members: + +Viewsets +======== + +.. automodule:: gridplatform.rest.viewsets + :members: + +Serializers +=========== +.. automodule:: gridplatform.rest.serializers + :members: diff --git a/documentation/source/apps/gridplatform/tariffs.rst b/documentation/source/apps/gridplatform/tariffs.rst new file mode 100644 index 0000000..6f44ec8 --- /dev/null +++ b/documentation/source/apps/gridplatform/tariffs.rst @@ -0,0 +1,32 @@ +Tariffs +======= + +Tariffs were mentioned in the domain model under the section +:ref:`data-sources`, and also in :ref:`main-consumptions`. To facilitate +changes in the domain, as mentioned in :ref:`changes-in-domain`, the +:py:class:`~gridplatform.tariffs.models.Tariff` (and its subclasses +:py:class:`~gridplatform.tariffs.models.EnergyTariff` and +:py:class:`~gridplatform.tariffs.models.VolumeTariff`) is defined in terms of +periods; namely :py:class:`~gridplatform.tariffs.models.FixedPricePeriod` and +:py:class:`~gridplatform.tariffs.models.SpotPricePeriod`. The periods are +associated to tariffs via the +:py:class:`~gridplatform.tariffs.models.TariffPeriodManager` + + +A simpler design for solving a simular task is described in +:ref:`co2-conversions`. + +.. autoclass:: gridplatform.tariffs.models.Tariff + +.. autoclass:: gridplatform.tariffs.models.EnergyTariff + +.. autoclass:: gridplatform.tariffs.models.VolumeTariff + +.. autoclass:: gridplatform.tariffs.models.TariffPeriodManager + :members: subscription_cost_sum, value_sequence + +.. autoclass:: gridplatform.tariffs.models.FixedPricePeriod + :members: subscription_cost_sum, clean, get_unit_choices, _value_sequence + +.. autoclass:: gridplatform.tariffs.models.SpotPricePeriod + :members: clean, _value_sequence diff --git a/documentation/source/apps/gridplatform/token_auth.rst b/documentation/source/apps/gridplatform/token_auth.rst new file mode 100644 index 0000000..857f1dc --- /dev/null +++ b/documentation/source/apps/gridplatform/token_auth.rst @@ -0,0 +1,19 @@ +Token Auth +========== + +The built-in token authentication of Django REST framework knows little about +our encryption scheme. This app provides the necessary customizations to +include the additionally needed information in the token string. + +.. autofunction:: gridplatform.token_auth.models.create_token + +.. autoclass:: gridplatform.token_auth.models.TokenData + :members: provide_token, decrypt_password, lookup_token + +.. autoclass:: gridplatform.token_auth.authentication.EncryptionTokenAuthentication + :members: authenticate, authenticate_credentials + +Configuration +------------- + +.. automodule:: gridplatform.token_auth.conf diff --git a/documentation/source/apps/gridplatform/trackuser.rst b/documentation/source/apps/gridplatform/trackuser.rst new file mode 100644 index 0000000..326c582 --- /dev/null +++ b/documentation/source/apps/gridplatform/trackuser.rst @@ -0,0 +1,84 @@ +Track User +================= + +The ``trackuser`` app defines a number of global functions to access various +data that depend on the user currently logged in. + +.. autofunction:: gridplatform.trackuser.get_user +.. autofunction:: gridplatform.trackuser._get_user_customer +.. autofunction:: gridplatform.trackuser._get_override_customer +.. autofunction:: gridplatform.trackuser._get_selected_customer +.. autofunction:: gridplatform.trackuser.get_customer +.. autofunction:: gridplatform.trackuser.get_provider +.. autofunction:: gridplatform.trackuser.get_provider_id +.. autofunction:: gridplatform.trackuser.get_timezone +.. autofunction:: gridplatform.trackuser.get_current_date + +Context Managers +---------------- + +.. py:function:: gridplatform.trackuser.replace_user(user) + + A context manager within which the :class:`~gridplatform.users.models.User` + returned by :py:func:`get_user` will appear to be the given user. + +.. py:function:: gridplatform.trackuser.replace_override_customer(customer) + + A context manager within which the + :class:`~gridplatform.customers.models.Customer` returned by + :py:func:`_get_override_customer` will appear to be the given customer. + +.. py:function:: gridplatform.trackuser.replace_selected_customer(customer) + + A context manager within which the + :class:`~gridplatform.customers.models.Customer` returned by + :py:func:`_get_selected_customer` will appear to be the given customer. + + +.. py:function:: gridplatform.trackuser.replace_customer(customer) + + A context manager within which the + :class:`~gridplatform.customers.models.Customer` returned by + :py:func:`get_customer` will appear to be the given customer. + + This is primariliy used for unit-testing. + +Managers +-------- + +.. autoclass:: gridplatform.trackuser.managers.FilteringQuerySetMixinBase + :members: iterator, aggregate, count, delete, update, _update, exists, + _clone, values, values_list, dates, + datetimes, _apply_filtering + +.. autoclass:: gridplatform.trackuser.managers.CustomerBoundQuerySetMixin + :members: _apply_filtering + +.. autoclass:: gridplatform.trackuser.managers.ProviderBoundQuerySetMixin + :members: _apply_filtering + +.. autoclass:: gridplatform.trackuser.managers.CustomerBoundManagerBase + +.. autoclass:: gridplatform.trackuser.managers.CustomerBoundManager + +.. autoclass:: gridplatform.trackuser.managers.TreeCustomerBoundManager + +.. autoclass:: gridplatform.trackuser.managers.StoredSubclassCustomerBoundManager + +.. autoclass:: gridplatform.trackuser.managers.StoredSubclassTreeCustomerBoundManager + +.. autoclass:: gridplatform.trackuser.managers.ProviderBoundManager + +Middleware +---------- + +.. autoclass:: gridplatform.trackuser.middleware.TrackUserMiddleware + +Tasks +----- + +The ``trackuser`` provides some Celery task decorators for tracking users and +similar context into Celery tasks. + +.. autofunction:: gridplatform.trackuser.tasks.trackuser_task +.. autofunction:: gridplatform.trackuser.tasks.task diff --git a/documentation/source/apps/gridplatform/users.rst b/documentation/source/apps/gridplatform/users.rst new file mode 100644 index 0000000..e3c9650 --- /dev/null +++ b/documentation/source/apps/gridplatform/users.rst @@ -0,0 +1,59 @@ +Users +===== + +This app defines the :py:class:`~gridplatform.users.models.User` model which is +used for user authentication and authorization. + +.. autoclass:: gridplatform.users.models.User + :members: clean_fields, save, _decrypt, get_username, set_password, + reset_password, is_admin, is_customer_superuser, + get_encryption_id, satisfies_search + + +Encryption Key Signal Handlers +------------------------------ + +A number of signal handlers take care of encryption key generation and sharing. + +.. autofunction:: gridplatform.users.models.create_user_key + +.. autofunction:: gridplatform.users.models.auto_grant_to_admins + +.. autofunction:: gridplatform.users.models.auto_grant_user_self_key + +.. autofunction:: gridplatform.users.models.auto_grant_user_key_to_superusers + +.. autofunction:: gridplatform.users.models.auto_grant_customer_superuser_user_keys + +.. autofunction:: gridplatform.users.models.auto_grant_provideruser_provider_key + +.. autofunction:: gridplatform.users.models.auto_grant_provideruser_customer_keys + +.. autofunction:: gridplatform.users.models.auto_grant_provideruser_provideruser_keys + + +Views +----- + +.. autoclass:: gridplatform.users.views.CustomerAdminOrAdminRequiredMixin + :members: dispatch + +.. autoclass:: gridplatform.users.views.UserProfileForm + :members: clean + +.. autoclass:: gridplatform.users.views.UserProfileView + :members: get_form_kwargs, form_valid + + +Managers +-------- + +.. autofunction:: gridplatform.users.managers.hash_username + +.. autoclass:: gridplatform.users.managers.UserManager + :members: create_user + +.. autoclass:: gridplatform.users.managers.UserQuerySetMixin + :members: _apply_filtering + +.. autoclass:: gridplatform.users.managers.BoundUserManager diff --git a/documentation/source/apps/gridplatform/utils.rst b/documentation/source/apps/gridplatform/utils.rst new file mode 100644 index 0000000..d0a067c --- /dev/null +++ b/documentation/source/apps/gridplatform/utils.rst @@ -0,0 +1,365 @@ +Utillities +========== + +The ``utils`` app contains various utility abstractions. The primary +purpose is to contain the clutter. + +Miscelaneous Functions +---------------------- + +.. autofunction:: gridplatform.utils.unix_timestamp + +.. autofunction:: gridplatform.utils.first_last + +.. autofunction:: gridplatform.utils.fraction_to_decimal + +.. autofunction:: gridplatform.utils.choices_extract_python_identifier + +.. autofunction:: gridplatform.utils.development_sum + +.. autofunction:: gridplatform.utils.sum_or_none + +Breadcrumbs +----------- + +Breadcrumbs are somewhat easier to work with given the following two +classes: + +.. autoclass:: gridplatform.utils.breadcrumbs.Breadcrumb + +.. autoclass:: gridplatform.utils.breadcrumbs.Breadcrumbs + :members: __add__ + + +ID Formatters +------------- + +.. autofunction:: gridplatform.utils.format_id.format_mac +.. autofunction:: gridplatform.utils.format_id.format_mbus_manufacturer +.. autofunction:: gridplatform.utils.format_id.format_mbus_enhanced + + +FTP client +---------- + +.. autofunction:: gridplatform.utils.ftpclient.ftpconnection + +Iterator Extensions +------------------- + +.. automodule:: gridplatform.utils.iter_ext + :members: nwise, triplewise, pairwise, pairwise_extended, flatten, + tee_lookahead, count_extended + +API +--- + +Utility functions for previous and next links in REST API for +resources that are defined in terms of data sequences. + +.. autofunction:: gridplatform.utils.api.next_valid_date_for_datasequence +.. autofunction:: gridplatform.utils.api.previous_valid_date_for_datasequence + + +Context Managers +---------------- + +.. autofunction:: gridplatform.utils.contextmanagers.global_context + + +Condense +-------- + +.. automodule:: gridplatform.utils.condense + :members: next_resolution, is_finer_resolution, + is_coarser_resolution, floor, ceil, get_date_formatter + +Decorators +---------- + +.. autofunction:: gridplatform.utils.decorators.deprecated +.. autofunction:: gridplatform.utils.decorators.virtual +.. autofunction:: gridplatform.utils.decorators.permission_required + + +Fields +------ + +.. autofunction:: gridplatform.utils.fields.parse_mac + +.. autoclass:: gridplatform.utils.fields.MacAddress +.. autoclass:: gridplatform.utils.fields.MacAddressFormField +.. autoclass:: gridplatform.utils.fields.MacAddressField + :members: to_python, get_internal_type, formfield + +.. autoclass:: gridplatform.utils.fields.JSONEncoder + :members: default + +.. autoclass:: gridplatform.utils.fields.JSONField + :members: __init__, to_python, get_prep_value, value_to_string, + value_from_object + +.. autoclass:: gridplatform.utils.fields.SplitHourMinuteWidget + :members: decompress + +.. autoclass:: gridplatform.utils.fields.SplitHiddenHourMinuteWidget + +.. autoclass:: gridplatform.utils.fields.DurationFormField + :members: compress + +.. autoclass:: gridplatform.utils.fields.DurationField + :members: formfield + +.. autoclass:: gridplatform.utils.fields.PercentField + :members: __init__ + +.. autoclass:: gridplatform.utils.fields.ImageFieldWithLoadCheck + :members: to_python + +.. autoclass:: gridplatform.utils.fields.ImageModelFieldWithLoadCheck + :members: formfield + +.. autoclass:: gridplatform.utils.fields.BigAutoField + +.. autoclass:: gridplatform.utils.fields.BuckinghamField + :members: validate, get_prep_value + + +Forms +----- + +.. autoclass:: gridplatform.utils.forms.TimePeriodFormMixin + :members: __init__, clean + +.. autoclass:: gridplatform.utils.forms.TimePeriodForm + +.. autoclass:: gridplatform.utils.forms.TimePeriodModelForm + :members: __init__, clean + +.. autoclass:: gridplatform.utils.forms.HalfOpenTimePeriodModelForm + :members: clean + +.. autofunction:: gridplatform.utils.forms.previous_month_initial_values + +.. autofunction:: gridplatform.utils.forms.this_week_initial_values + +.. autoclass:: gridplatform.utils.forms.YearWeekPeriodForm + :members: __init__, clean, get_timestamps + + +Formsets +-------- + +.. autoclass:: gridplatform.utils.formsets.SurvivingFormsModelFormSetMixin + :members: surviving_forms + + +Generic Views +------------- + +.. automodule:: gridplatform.utils.generic_views + :members: ListView, DetailView, CreateView, DeleteView, UpdateView, + InlineFormSet, ModelFormSetView, InlineFormSetView, + CreateWithInlinesView, UpdateWithInlinesView, View, + TemplateView, SearchableListMixin, FormView + +Access Control +^^^^^^^^^^^^^^ + +.. autoclass:: gridplatform.utils.generic_views.access_control.CheckAJAXMixin + +.. autoclass:: gridplatform.utils.generic_views.access_control.LoginRequiredMixin + +.. autoclass:: gridplatform.utils.generic_views.access_control.ModelPermissionRequiredMixin + +.. autoclass:: gridplatform.utils.generic_views.access_control.MultipleModelPermissionsRequiredMixin + +.. autoclass:: gridplatform.utils.generic_views.access_control.CustomerBoundMixin + + +Localized +^^^^^^^^^ + +.. autoclass:: gridplatform.utils.generic_views.localized.LocalizedModelFormMixin + :members: get_form_class + +.. autoclass:: gridplatform.utils.generic_views.localized.LocalizedModelFormSetMixin + :members: get_factory_kwargs + +.. autoclass:: gridplatform.utils.generic_views.localized.LocalizedInlineFormSetMixin + :members: get_factory_kwargs + +Commands +-------- + +.. automodule:: gridplatform.utils.management.commands.check_db_connection + +.. automodule:: gridplatform.utils.management.commands.fix_contenttypes_and_permissions + + +Managers +-------- + +.. autoclass:: gridplatform.utils.managers.DateRangeManagerMixin + :members: in_range + +.. autoclass:: gridplatform.utils.managers.TimestampRangeManagerMixin + :members: in_range + + +Middleware +---------- + +.. autoclass:: gridplatform.utils.middleware.ExceptionRemoveInfoMiddleware +.. autoclass:: gridplatform.utils.middleware.ExceptionAddInfoMiddleware +.. autoclass:: gridplatform.utils.middleware.TimezoneMiddleware + +Models +------ + +.. autoclass:: gridplatform.utils.models.StoredSubclassManager + :members: get_query_set, subclass_only, _model_subclasses + +.. autoclass:: gridplatform.utils.models.StoreSubclass + :members: clean + +.. autoclass:: gridplatform.utils.models.DateRangeModelMixin + :members: clean, timestamp_range_intersection + +.. autoclass:: gridplatform.utils.models.TimestampRangeModelMixin + :members: clean, format_timestamp_range_unicode, overlapping + +Paginator +--------- + +.. automodule:: gridplatform.utils.paginator + :members: parse_date, Http404ApiException, parse_date_or_404 + +Unit Converters +--------------- + +.. automodule:: gridplatform.utils.preferredunits + :members: UnitConverter, PhysicalUnitConverter, KvarUnitConverter, + KvarhUnitConverter, PowerFactorUnitConverter, + DisplayCelsiusMixin, RelativeCelsiusUnitConverter, + AbsoluteCelsiusUnitConverter, DisplayFahrenheitMixin, + RelativeFahrenheitUnitConverter, + AbsoluteFahrenheitUnitConverter, + AbstractENPIUnitConverter, PersonsENPIUnitConverter, + AreaENPIUnitConverter, + AbstractProductionENPIUnitConverter, + ProductionAENPIUnitConverter, + ProductionBENPIUnitConverter, + ProductionCENPIUnitConverter, + ProductionDENPIUnitConverter, + ProductionEENPIUnitConverter, ProductionUnitConverter, + EfficiencyUnitConverter + +Relative Time Delta +------------------- + +.. automodule:: gridplatform.utils.relativetimedelta + :members: wrap, RelativeTimeDelta + +Samples +------- + +.. automodule:: gridplatform.utils.samples + :members: Sample, wrap_ranged_sample, wrap_ranged_sample_sequence + +Serializers +----------- + +.. autoclass:: gridplatform.utils.serializers.SampleBase + :members: get_unit, get_display_unit, get_value + +.. autoclass:: gridplatform.utils.serializers.PointSampleSerializer +.. autoclass:: gridplatform.utils.serializers.RangedSampleSerializer + +Template Tags +------------- + +.. autofunction:: gridplatform.utils.templatetags.utils.insertnbsp +.. autofunction:: gridplatform.utils.templatetags.utils.jsonify +.. autofunction:: gridplatform.utils.templatetags.utils.buckingham_display + +Unit Conversion +--------------- + +.. automodule:: gridplatform.utils.unitconversion + :members: PhysicalQuantity, simple_convert + +Units +----- + +.. automodule:: gridplatform.utils.units + +Utility Types +------------- + +.. automodule:: gridplatform.utils.utilitytypes + + +Validators +---------- + +.. autofunction:: gridplatform.utils.validators.nonzero_validator +.. autofunction:: gridplatform.utils.validators.in_the_past_validator +.. autofunction:: gridplatform.utils.validators.clean_overlapping + + +Views +----- + +.. autofunction:: gridplatform.utils.views.json_response +.. autofunction:: gridplatform.utils.views.json_list_response + +.. autoclass:: gridplatform.utils.views.JsonResponse + :members: data + +.. autoclass:: gridplatform.utils.views.JsonResponseBadRequest + +.. autoclass:: gridplatform.utils.views.DateLocalEpoch + :members: default + +.. autofunction:: gridplatform.utils.views.date_epoch_json_response + +.. autofunction:: gridplatform.utils.views.render_to + +.. autofunction:: gridplatform.utils.views.json_list_options + +.. autoclass:: gridplatform.utils.views.FileView + :members: get + +.. autoclass:: gridplatform.utils.views.NoCustomerMixin + +.. autoclass:: gridplatform.utils.views.CustomerContextMixin + :members: get_context_data + +.. autoclass:: gridplatform.utils.views.CustomerInKwargsMixin + +.. autoclass:: gridplatform.utils.views.CustomersContextMixin + :members: get_context_data + +.. autoclass:: gridplatform.utils.views.CustomerListMixin + :members: _customer + +.. autofunction:: gridplatform.utils.views.task_status + +.. autoclass:: gridplatform.utils.views.StartTaskView + :members: get_task_kwargs, get_task, get_status_url, + get_finalize_url, start_task, form_valid, form_invalid + +.. autoclass:: gridplatform.utils.views.TaskForm + +.. autoclass:: gridplatform.utils.views.FinalizeTaskView + :members: finalize_task, form_valid, form_invalid + +.. autoclass:: gridplatform.utils.views.HomeViewBase + :members: get_redirect_url + +.. autoclass:: gridplatform.utils.views.ChooseCustomerBase + :members: get_context_data + +.. autoclass:: gridplatform.utils.views.CustomerViewBase + :members: get_redirect_url, get_redirect_with_customer_url diff --git a/documentation/source/architecture.rst b/documentation/source/architecture.rst new file mode 100644 index 0000000..289c116 --- /dev/null +++ b/documentation/source/architecture.rst @@ -0,0 +1,178 @@ +********************* +Software Architecture +********************* + +The GridPlatform is an energy management platform, meaning it supposed to be +the foundation on which to build Energy Management System (EMS) software +products. Therefore there is a natural overall layered archicture with the +GridPlatform at the bottom. + +The now legacy GridPortal 2.0 has been integrated with GridPlatform using a few +wrappers and can therefore be seen as one instance of an EMS. However, as it is +legacy it does have some of its own concepts that are not part of the +GridPlatform as well as different interpretation of such concepts. One example +is that the GridPortal 2.0 has a generic concept of ``indexes`` and the +GridPlatform has a concept of ``tariffs``. Price indexes in GridPortal 2.0 are +used similarly to how tariffs are used in the GridPlatform but are in no way +connected, nor should they be. The data models in the GridPlatform are superior +to those in GridPortal 2.0, and no further development, apart from bug fixes, are +planned for GridPortal 2.0. + +A small EMS product, simply called Energy Manager, has been built on top of the +GridPlatform. The original vision was for this to eventually replace GridPortal +2.0, however, as development was cancelled in early stages this product turned +into a GridPlatfrom proof-of-concept implementation, and was used to drive the +further development of the GridPlatform. + +The GridPlatform is intended to be heavily used via REST web services, so +future EMS software products may be implemented on top of the GridPlatform +using purely this interface, or they can built on top of it using Django like +the Energy Manager example does. Or indeed a mix of both if that makes the most +sense. + +Energy Manager and GridPortal only use the Django Interface. Asynchronous HTTP +requests made by them are made using their own Django views. + +The overall architecture can be visualised as follows: + +.. code-block:: none + + +---------------------------------+ + | Energy Manager | GridPortal 2.0 | + +--------------------------------------------------+ + | REST API | Django API | + | GridPlatform | + +--------------------------------------------------+ + + +Logging +======= + +- Web traffic logging is done by ``nginx`` and the logs can normally be found + in `/var/log/nginx`. + +- PostgreSQL logs can normally be found in `/var/log/postgreqsql` + +- Django and Celery error messages are not logged on the servers but are + e-mailed directly to the list of administrators listed in the Django settings + file. + +- GridAgent Server logs are located in the GridAgent Server directory. + +.. _architecture-cloud-architecture: + +****************** +Cloud Architecture +****************** +The GridPlatform is designed to run in a cloud infrastructure for easy +expansion of resources as it becomes necessary. It is highly scalable and is +meant to be run in a distributed fashion across many servers. However, it is +also flexible in its deployment allowing for easy single server setups as well, +and can run on any Linux system with enough resources running PostgreSQL. All +third part software used are free and open source. + +The deployment architecture consists of the following component types +responsible for running the listed software services: + + +Web server load balancer +======================== +Only used in a multiple server deployment. + + +Web server +========== + +- Nginx: Web server. + +- uWSGI: WSGI compliant application server for running the GridManager + GridPlatform Django application. + +- Memcached: Distributed object caching system. + + +Message queue server +==================== + +- RabbitMQ: AMQP compliant message queue server. + + +Database server +=============== + +- PostgreSQL + + +Heavy computation server +======================== + +- Celery: Distributed task queue. The GridManager GridPlatform celery worker + threads run on these types of servers. + +- Cache Generator: GridManager script for condensing energy measurements in + to 1 hour and 5 minute periods. + + +GridAgent Server +================ + +- Running the GridManager GridAgent Server Python application + + +GridAgent Rules Server +====================== + +Rule monitoring, execution and transmission. + +- GridAgent Rule Engine: GridManager Django application that continuously + checks the specified rule constraints that customers have specified and runs + specified actions when needed. + *Note: This is not a distributed service. Only one rule engine should be + running at any given time or actions might get triggered twice.* + +- GridAgent Rules Updater: GridManager script for transmitting specified + rules to the GridAgents. Meant to run at the beginning of each clock hour. + *Note: Only rules that can be handled solely by a single GridAgent are + transmitted.* + + +Periodic Task Server +==================== + +The services listed below are all meant to be run as only one instance each in +the cloud. They can of course be run on serveral different servers, though none +of them are very computation nor memory hungry. + +- Nord Pool Spot prices import: GridManager script for importing spot prices + from the Nord Pool FTP server. + +- Energinet.dk |CO2| index import: GridManager script for importing |CO2|/kWh + data from Energinet.dk. + + .. |CO2| replace:: CO\ :sub:`2` + +- Erroneous Peak Remover: A bug in old version of the GridManager GridPoint 3 + phase meter caused erroneous measurements being transmitted. A GridManager + detects these abnormal measurements and deletes them. + *Note: Must be run before cache generation to prevent the erroneous + measurements affecting the cached values.* + +- Clear Django sessions: A Django script for cleaning the database of any + dead sessions. + + +Sharding +======== + +To support really large amounts of data, *sharding* should be +considered. Partitioning of the data is trivial: It is naturally divided on +customers. Customer data can then be distributed across many databases, +constrained by keeping data related to the same customer in the same database. + +The web servers will then use a routing algorithm to use the correct database +for each logged in user. Many such schemas exists and libraries exists for +implementing such functionality trivial. + +As we were nowhere near an amount of data that would necessitate sharding, it +has not been implemented; though the architecture is built with it in mind, +allowing future developers to add sharding later. diff --git a/documentation/source/changes.rst b/documentation/source/changes.rst new file mode 100644 index 0000000..3d6f54c --- /dev/null +++ b/documentation/source/changes.rst @@ -0,0 +1,18 @@ +.. _changes-in-domain: + +Changes in the Domain +===================== + +Occationally, one of the following will happen: + + * A new main consumption is installed. + * An existing main consumption is discontinued. + * A new energy use is introduced. + * An existing energy use is disconnected. + * A new data source is introduced. + * A data source is replaced in some application (say a new meter is + installed, or a different tariff is applied). + +It is not enough to model the state of the domain at just a single +point in time. The state of the domain needs to be modelled with +support for historical changes. diff --git a/documentation/source/conf.py b/documentation/source/conf.py new file mode 100644 index 0000000..9ecf575 --- /dev/null +++ b/documentation/source/conf.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +# +# GridPlatform documentation build configuration file, created by +# sphinx-quickstart on Fri Oct 24 08:38:29 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'GridPlatform' +copyright = u'2014, -' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2' +# The full version, including alpha/beta/rc tags. +release = '2' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'GridPlatformdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'GridPlatform.tex', u'GridPlatform Documentation', + u'-', 'manual'), + ('domainmodel', 'GridPlatformDomainModel.tex', u'GridPlatform Domain Model', + u'-', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'gridplatform', u'GridPlatform Documentation', + [u'-'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'GridPlatform', u'GridPlatform Documentation', + u'-', 'GridPlatform', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/documentation/source/consumptions.rst b/documentation/source/consumptions.rst new file mode 100644 index 0000000..532454c --- /dev/null +++ b/documentation/source/consumptions.rst @@ -0,0 +1,117 @@ +Consumptions +============ + +This chapter covers utility consumptions that represent energy consumption in +some form. The utility consumptions that companies are billed for directly are +the main consumptions. Each main consumption can be partitioned into energy +uses. + +.. _main-consumptions: + +Main Consumptions +----------------- + +Main consumptions are individually billed sources of utilities going into a +company. Examples of main consumptions are: + + * The power consumption measured by a main electrical meter with billing + number. + * The heat consumption measured by a main district heating meter with + billing number. + * The amount of gas measured by a main gas meter with billing number. + * The amount of oil delivered to a oil storage tank with a billing number.. + +The important properties of main consumptions are that they are individually +billed, and they deal with utilties that deliver energy in some form. + +The utility type of each main consumption is unambiguous. As such knowing the +energy consumption represented by each main consumption gives the distribution +of energy on different utility types. + +For a given quantity of a given utility type at a given time, the CO₂ emissions +may be determined. + +Energy Uses +----------- + +Energy uses are main consumptions partitioned into smaller energy consumptions +each with a particular use. Examples of energy uses are: + + * The lighting in an office building. + * The power used by a conveyor belt. + * The energy used for the casting of metals. + * The power used by a compressor. + * The energy consumption of a freezer. + +Interresting properties that can be derived from energy uses include variable +costs and CO₂ emissions. + +.. _adjustments-etc: + +Adjustment Factors, Energy Performances and Normalized Consumptions +------------------------------------------------------------------- + +The consumptions of different periods of the same energy use are comparable if +these consumptions are adjusted by the right adjustment factors. Adjustment +factors are determined by what we find acceptable to increase the energy +consumption, say for instance: + + * The duration of the period may be normalized to a standard period duration. + Say one period is one week and another is 9 days we can multiply them both + with an adjustment factor to make them both correspond to a full month. + * The heating degree days in the period may be normalizided to standard + heating degree days. Say the energy used to maintain a comfortable indoor + temperature in a cold period is larger than the energy used to maintain the + same temperature in a warmer period. + * The production of one period may be larger than that of another, so to + compare the energy consumption accross such two periods for the same energy + use, they must be adjusted wich each their production counts. + +Many more adjustment factors exist. The above examples are adjusted energy +consumptions with following normalization, and their unit ends up being energy +(kWh) also when combined. We call these normalized energy consumptions. +Because the unit before and after normalization are the same, multiple +adjustment factors can be used in calculating a normalized energy consumption. + +When adjustment factors are applied without being followed by normalization, we +have an energy performance. Comparing energy performances is equally fair, but +differenses in energy performances can be less trivial to value. To reiterate +the above adjustment factors: + + * Adjusting for time gives a mean power W. + * Adjusting for heating degree days gives a mean heat loss coefficient W/°K. + * Adjusting for production gives mean production consumption kWh/pcs. + +In isolation these units make sense. When combined we risk getting meaningless +units. For instances both heating degree days and production are not +compatible with duration adjustment; i.e. W/s°K and W/pcs are meaningless +units. In these cases a normalized energy consumption is preferred. For an +already normalized consumption an energy performance may be defined by applying +an additional adjustmentfactor (or leaving out the normalization of an existing +adjustment factor). + +Similar to adjustment factors, other (additional) factors may be used to define +energy performances, including utility costs and CO₂ emissions. For example +the marginal utility cost for production (EUR/pcs) is an energy performance, +and so is the marginal CO₂ emissions for production (tonne/pcs), even burn-rate +(EUR/year) and CO₂ emission rate (tonne/year). These factors may also be used +on normalized energy consumptions to get normalized yearly costs (EUR), or +normalized yearly CO₂ emissions (tonne). + +Some adjustment factors (or other factors) represent great value to companies, +for example the production. Energy performances based on these may be promoted +to energy performance indicators. + +The adjustment factors applied need not necessarily be part of the physics +observed. As mentioned before it is enough if one finds the adjustment factor +relevant. For instance, it may be relevant how much energy is used for +lighting a factory per unit produced, though the production does not influence +the energy consumption of lighting proportionally (or at all), it may be +desireable to improve this performance indicator after all. The same goes for +man hours of work and energy used for comfort heating. + +In particular, if only adjustment factors being part of the physics observed, +and all the adjustment factors being part of the physics observed are applied, +the resulting energy performance becomes an informationless physical constant +defined by nature. For instance energy (kWh) adjusted for power (W) and +time (s) will always give 1 with no unit. diff --git a/documentation/source/costcompensations.rst b/documentation/source/costcompensations.rst new file mode 100644 index 0000000..496bc64 --- /dev/null +++ b/documentation/source/costcompensations.rst @@ -0,0 +1,30 @@ +.. _cost-compensations: + +Cost Compensations +================== + +Certain uses of energy are considered in the general interest of +society, and are eligible for tax refunds. Or in general, the tariff +on the same utility may come with a rebate for certain energy uses. +This is where cost compensations come in. + +Cost compensations are subtracted from tariff values when calculating +variable costs. + +We assume that taxes may only be refunded once for a particular energy +use. So a cost compensation may apply to all energy uses for a +certain main consumption, with explicit exceptions. That is, the +energy uses with a specific cost compensation are excluded when +applying a general cost compensation to a main consumption. + +Eventually the cost compensations of each energy use of a main +consumption along with the general cost compensation for the same main +consumption will all be applied when calculating the variable costs of +the particular main consumption. + +When calculating the variable costs of an energy use, any cost +compensation related directly to the energy use is applied. If no +such cost compensation exists, we shall fall back to the general cost +compensation of the aggregating main consumption. Finally if no +general cost compansation is defined for the main consumption no cost +compensation will be applied. diff --git a/documentation/source/datasources.rst b/documentation/source/datasources.rst new file mode 100644 index 0000000..ee3a9e9 --- /dev/null +++ b/documentation/source/datasources.rst @@ -0,0 +1,20 @@ +.. _data-sources: + +Data Sources +============ + +Data sources are streams of samples in the domain. A sample consist of a +physical quantity and a timestamp (or timestamp range). Examples of data +sources are: + + * Accumulated energy consumption measured by a particular meter (kWh), + * Tariff for a particular utility (EUR/kWh or EUR/m³), + * CO₂ emission quotient (kg/kWh), + * Temperature measured by a thermometer (°K), + * Accumulated production counted automatically on a conveyorbelt (say bottles), + * Power measured by a particular meter (W), + * Volume flow measured by a particular meter (m²/h), and so on. + +Some data sources sample continuous functions (each physical quantity belongs +to a point in time), and some sample piecewise constant functions (each +physical quantity belongs to a range of time). diff --git a/documentation/source/deployment.rst b/documentation/source/deployment.rst new file mode 100644 index 0000000..ff99b6b --- /dev/null +++ b/documentation/source/deployment.rst @@ -0,0 +1,137 @@ +********** +Deployment +********** + +Fabric is used to management server deployment. For Fabric usage please +refer to https://pypi.python.org/pypi/fabric. The fabric rules in +:file:`fabfile.py` explains how to deploy to single server targets (e.g. the +target `deploy_staging`) as well as cloud deployment (the target +`deploy_production`). In cloud deployment please note the order in which +the various services are started and stopped. For example, it is not +recommended to start the upgrade of the database while over services that +depend on it are still running. + + +Virgin deployment +================== + +If you are deploying to a new server with clean database you want to create a +staff user for administrators to use. + +As with most Django projects the first user is added using the following command: + +.. code-block:: none + + ./manage.py createsuperuser + +The command creates a user with both `is_staff = True` and `is_superuser = +True`. + + +Django admin +------------ +Staff users (i.e. users with `is_staff = True`) can log into the Django admin +website at `/django_admin`. + +The Django admin site allows the administrator to create providers and provider +users, as well as administering groups and permissions. That is all that is +supposed to be done from this site. Once provider administrators have been +created they can log in and administer the rest them using either GridPortal +2.0 or Energy Manager. + + +Web server locale setup +======================= + +Ensure that the locale specified in +:file:`gridplatform/scripts/production/start_uwsgi.sh` +is unicode/utf-8-compatible and actually exists on server. +Otherwise, when interacting with the file system (e.g. when handling file +uploads) you will experience errors on the form (if the file name contains non-ASCII characters): + +.. code-block:: none + + UnicodeEncodeError: 'ascii' codec can't encode character u'\xf3' in position 46: ordinal not in range(128) + + +Crontab +======= + +Please refer to :ref:`developer-handbook-scripts-and-commands` for descriptions +of the scripts used in the crontabs listed in this section. + +Single server +------------- +For single server deployment `crontab` contains the following: + +.. code-block:: none + +5 0 * * * $HOME/gridplatform/scripts/production/manage.sh clearsessions +15 * * * * $HOME/gridplatform/scripts/production/manage.sh hickup_detection --previous-hour --quiet && ./gridplatform/scripts/production/manage.sh generate_cache --hours_back=2 --verbosity=0 +15 7 * * * $HOME/gridplatform/scripts/production/manage.sh import_nordpool +15 12 * * * $HOME/gridplatform/scripts/production/manage.sh import_nordpool +15 14 * * * $HOME/gridplatform/scripts/production/manage.sh import_nordpool +15 16 * * * $HOME/gridplatform/scripts/production/manage.sh import_nordpool +15 22 * * * $HOME/gridplatform/scripts/production/manage.sh import_nordpool +15 7 * * * $HOME/gridplatform/scripts/production/manage.sh import_nordpool_spot_prices +15 22 * * * $HOME/gridplatform/scripts/production/manage.sh import_nordpool_spot_prices +1 0 * * * $HOME/gridplatform/scripts/production/manage.sh import_energinet_co2 +*/15 * * * * $HOME/gridplatform/scripts/production/manage.sh import_energinet_co2 $(date +\%Y-\%m-\%d) +*/15 * * * * $HOME/gridplatform/scripts/production/manage.sh send_rules +5 * * * * $HOME/gridplatform/gridagentserver/gas-check.sh +15 * * * * $HOME/gridplatform/rabbitmq-check.sh +1 0 * * * $HOME/gridplatform/scripts/production/manage.sh rebuild_group_tree +@reboot while ! $HOME/gridplatform/scripts/production/manage.sh check_db_connection ; do sleep 10; done; $HOME/start.sh + +# Portal +@reboot while ! $HOME/gridplatform/scripts/production/manage.sh check_db_connection ; do sleep 10; done; $HOME/start.sh > /dev/null +5 0 * * * $HOME/gridplatform/scripts/production/manage.sh clearsessions +15 * * * * $HOME/gridplatform/scripts/production/manage.sh hickup_detection --previous-hour --quiet && ./gridplatform/scripts/production/manage.sh generate_cache --hours_back=2 --verbosity=0 +*/15 * * * * $HOME/gridplatform/scripts/production/manage.sh send_rules +15 * * * * $HOME/gridplatform/rabbitmq-check.sh +1 0 * * * $HOME/gridplatform/scripts/production/manage.sh rebuild_group_tree + +# GAS +@reboot while ! $HOME/gridplatform/scripts/production/manage.sh check_db_connection ; do sleep 10; done; sleep 10; $HOME/restart-gas.sh +5 * * * * export DJANGO_CONFIGURATION=Prod && $HOME/gridplatform/gridagentserver/gas-check.sh +10 * * * * if [ $(ps -ho rss $(cat $HOME/gridplatform/gridagentserver/twistd.pid)) -gt 500000 ]; then $HOME/restart-gas.sh; fi + +For cloud deployment +-------------------- + +For cloud deployment, here follows the crontab for the web, engine and GridAgent servers. For a description of the cloud architecture please refer to :ref:`architecture-cloud-architecture`. + +Web server: + +.. code-block:: none + + @reboot while ! $HOME/gridplatform/scripts/production_nordic/manage.sh check_db_connection ; do sleep 10; done; cd $HOME/gridplatform/scripts/production_nordic; ./start_gunicorn.sh; ./start_celery.sh + + +Engine server: + +.. code-block:: none + + @reboot while ! $HOME/gridplatform/scripts/production_nordic/manage.sh check_db_connection ; do sleep 10; done; $HOME/gridplatform/scripts/production_nordic/manage.sh ruleengine; $HOME/gridplatform/scripts/production_nordic/start_reports.sh; $HOME/gridplatform/scripts/production_nordic/start_store_data_sanitize.sh + 15 * * * * $HOME/gridplatform/rabbitmq-check.sh + 5 0 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh clearsessions + 15 * * * * $HOME/gridplatform/scripts/production_nordic/manage.sh hickup_detection --previous-hour --quiet && ./gridplatform/scripts/production_nordic/manage.sh generate_cache --hours_back=2 --verbosity=0 + 15 7 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh import_nordpool + 15 12 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh import_nordpool + 15 14 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh import_nordpool + 15 16 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh import_nordpool + 15 22 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh import_nordpool + 15 7 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh import_nordpool_spot_prices + 15 22 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh import_nordpool_spot_prices + 1 0 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh import_energinet_co2 + */15 * * * * $HOME/gridplatform/scripts/production_nordic/manage.sh import_energinet_co2 $(date +\%Y-\%m-\%d) + */15 * * * * $HOME/gridplatform/scripts/production_nordic/manage.sh send_rules + 1 0 * * * $HOME/gridplatform/scripts/production_nordic/manage.sh rebuild_group_tree + + +GridAgent Server: + +.. code-block:: none + + @reboot while ! $HOME/gridplatform/scripts/production_nordic/manage.sh check_db_connection ; do sleep 10; done; cd $HOME/gridplatform/gridagentserver; ./start.sh + 5 * * * * export DJANGO_CONFIGURATION=Prod && $HOME/gridplatform/gridagentserver/gas-check.sh diff --git a/documentation/source/developer_handbook.rst b/documentation/source/developer_handbook.rst new file mode 100644 index 0000000..78e7eb1 --- /dev/null +++ b/documentation/source/developer_handbook.rst @@ -0,0 +1,187 @@ +****************** +Developer Handbook +****************** + + +System requirements +=================== + +The servers on which the software is currently deployed run Ubuntu 14.04 LTS, and this is also the recommended development environment. + +Using other Unix-like systems should be possible, though we cannot provide specific lists of package names to install for those. + +Windows is not supported. At least some of the third-party Python libraries used involve C extensions that are distributed in source code form, which are difficult to install under Windows.\ [#compiler]_ Various scripts are written as Bash shell-scripts. It may be *possible* to run the software under Windows, but running it in a Linux VM is likely to be a simpler solution. + +.. [#compiler] According to Python documentation, under Windows, extensions should preferably be compiled with the same version of Microsoft Visual C++ as used to compile the Python interpreter. + + +Repository root folder structure +================================ + +The code is split up into four major components: + +- :file:`documentation/`: This documentation. +- :file:`energymanager/`: Energy Manager. An example Energy Management System + based on the GridPlatform. +- :file:`gridagentserver/`: GridAgent Server code base. +- :file:`gridagentserver-protocol/`: GridAgent Server protocol code (used by GridAgent Server). +- :file:`gridplatform/`: The GridPlatform code base. +- :file:`legacy/`: GridPlatform 2.0 code base. +- :file:`qunit/`: QUnit (http://qunitjs.com/). +- :file:`requirements/`: PyPI requirement files. +- :file:`scripts/`: Scripts for easing the used of the system once deployed. +- :file:`static/`: Static website assets. +- :file:`templates/`: Top level Django templates that did not fit anywhere else. + + +Installing needed software +========================== + + +"Global" software installation +------------------------------ + +For local development, you will need: + +* Python 2.7. +* virtualenv to enable "local" installation of Python libraries. +* An appropriate C-compiler/build tools and Python development headers, to support installation of Python libraries that include C-extensions. +* PostgreSQL and development headers for building a client library. The PostgreSQL DBMS is used for deployment, and due to subtle differences between DBMS behavior, using the same locally simplifies development.\ [#dbms]_ +* Memcached and development headers for building a client library. Memcached is used for "cache" and for communicating computed results from background tasks to the web-part. +* libjpeg and development headers to support resizing uploaded images. +* The RabbitMQ message queue server, used to schedule background tasks. +* LaTeX and various TeX packages used for building PDF reports. + +.. [#dbms] This is a tradeoff. Using different database systems may help ensure that the application can later be deployed with a different DBMS for production --- but the "overhead" can be significant. Use of the Django ORM for database access which *should* preserve this portability, though database schema migrations in particular can be difficult to express without "raw" SQL. + +On a computer with Ubuntu 14.04 LTS, this can all be installed with:: + + sudo apt-get install \ + python-virtualenv \ + virtualenvwrapper \ + python-dev \ + build-essential \ + libgmp-dev \ + postgresql \ + libpq-dev \ + memcached \ + libmemcached-dev \ + libjpeg-dev \ + rabbitmq-server \ + texlive-latex-recommended \ + texlive-xetex \ + fonts-linuxlibertine \ + ttf-mscorefonts-installer \ + texlive-latex-extra \ + texlive-science \ + texlive-fonts-recommended + +On deployment, you will also need: + +* nginx (or a different HTTP-server) to serve "static" files, handle SSL and communicate with the backend WSGI server. +* A local mail server, to enable the system to send error mails and any other emails. We use Postfix. + +On a computer with Ubuntu 14.04 LTS, this can all be installed with:: + + sudo apt-get install \ + nginx \ + postfix + + +Python packages +--------------- + +Create virtual Python environment and set the current directory as "working directory" for it:: + + mkvirtualenv gridportal + setvirtualenvproject + +Various Python packages are specified in ``requirements/base.txt``, ``requirements/local.txt`` and ``requirements/production.txt``; including short comments on what they do/what we use them for. For development, the "base" and "local" packages should be installed:: + + pip install --requirement=requirements/local.txt + +This will take some time, as a number of packages are downloaded, and some C-extensions compiled. + +To later use this virtual Python environment:: + + workon gridportal + + +Setting up a database server locally +==================================== + +For development, the current user needs to be able to create and delete databases, as a "new" database is created and destroyed for unit test runs. +The easiest option is to make the current user a PostgreSQL superuser:: + + sudo -u postgres createuser --superuser $USER + +If/when the current user is PostgreSQL superuser, creating the database with the current user as owner is simple:: + + createdb --encoding=utf-8 portal + +With the Python virtual environment with Django and other packages installed active (``workon gridportal``), database the tables may be set up:: + + ./manage.py syncdb --noinput + ./manage.py migrate --all + + +.. _developer-handbook-scripts-and-commands: + +Scripts and commands +==================== + +To get started/run the software locally, you will need to use: + +* ``./manage.py runserver``: Run the Django development server. By default, it will listen on port 8000. +* ``./manage.py celery worker``: Run a Celery worker process. This is used for asynchroneous/background tasks like collecting data for graphs or compiling PDF reports. + +For other commands that are built-in or provided by third-party Django apps, refer to their respective documentation. + + +Custom Django management commands +--------------------------------- + +* ``./manage.py generate_cache``: Generate the five-minute-/hour-"cache" for accumulated data sources. +* ``./manage.py get_agent_events``: Get event log for a specified GridAgent. +* ``./manage.py hickup_detection``: Check for specific outliers/measurement errors in raw data. +* ``./manage.py import_energinet_co2``: Import CO2 data from Energinet.dk to "legacy" indexes. Requires an Energinet.dk FTP-account, with login-credentials specified in settings ``ENERGINET_CO2_USER`` and ``ENERGINET_CO2_PASS``. +* ``./manage.py setup_nordpool``: Set up "legacy" indexes for import of Nordpool spot prices. +* ``./manage.py import_nordpool``: Import Nordpool spot prices to "legacy" indexes. Requires a Nordpool FTP-account, with login-credentials specified in settings ``NORDPOOL_USER`` and ``NORDPOOL_PASS``. +* ``./manage.py import_nordpool_spot_prices``: Import Nordpool spot prices to global datasources. Requires a Nordpool FTP-account, with login-credentials specified in settings ``NORDPOOL_USER`` and ``NORDPOOL_PASS``. +* ``./manage.py ruleengine``: Run the GridPlatform rule engine. +* ``./manage.py send_rules``: Send rules that are evaluated on GridAgents to the GridAgents. +* ``./manage.py check_db_connection``: Check whether Django can connect to the database backend; exits with code 0 for success, 1 for failure. +* ``./manage.py fix_contenttypes_and_permissions``: Add/remove ``ContentType`` entries to match the current set of existing ``Model`` classes; create ``Permission`` instances that exist in code but are missing in the database. Mismatch may be caused by schema migrations that fail to fire the appropriate events on ``Model`` changes or the addition of new permissions in code. +* ``./manage.py rebuild_group_tree``: Rebuilds the measurement point group trees used in the left menu in GridPortal 2.0. There is a known issue regarding the group tree being corrupted and this a short term fix. This command is run by cron on the servers at every midnight. + + +Scripts +------- + +* ``fixture_hack.sh``: Script to wipe the local cache and database, recreate tables and populate the database with dynamic "fixture" data. +* ``compilemessages.sh``: Call the Django translation system to build ``gettext`` ``.mo`` files from ``.po`` files. +* ``rabbitmq-check.sh``: Check whether there are more than 100 pending messages in any RabbitMQ queues. This may indicate that task arrive to be run in the background faster than they are currently processed. +* ``run_all_tests.py``: Run unit tests with coverage check. +* ``test_javascript.sh``: Run QUnit unit-tests for JavaScript with PhantomJS. +* ``translate.sh``: Call the Django translation system to create ``.po``-files for the Danish locale for each Django app, open the resulting files with "missing" translations in the default editor, and compile the ``.po``-files to ``.mo``-files. + + +Makefile rules +-------------- + +* ``make dist``: Build ``gridplatform--.tar.gz`` from last commit with ``-`` as version. Use to build untagged "test" releases. +* ``make release``: Build ``gridplatform-[-].tar.gz`` from last commit with ``[-]`` as version. Use after git tag to build relases --- the "commit"-part of the version is absent when last commit *is* the tag. +* ``make makemessages``: Run ``django-admin makemessages`` with appropriate parameters to create ``.po``-files for Danish and Spanish translation for each Django app in the project. +* ``make compilemessages``: Run ``django-admin compilemessages`` to generate ``.mo``-files from ``.po``-files for each Django app in the project. +* ``make flake8``: Run the ``flake8`` checker on Python code files changed since the last commit according to git. +* ``make test``: Run unit tests for all Django apps in the project. +* ``make test-rerun``: Run only those unit tests that failed on last test run. +* ``make test-coverage``: Run unit tests with code coverage check. +* ``make selenium-test``: Run normal unit tests *and* Selenium-based tests. This requires ``chromedriver`` to be present in ``PATH`` or in the current directory. +* ``make tags``, ``make TAGS``: Build Emacs tag file for the Python code. +* ``make test-failures``: Run only those unit tests that failed on last test run. This version includes workarounds for the test runners failure to correctly identify the failing tests in case of issues with Python module imports. +* ``make parallel-test``: Run unit tests with separate test databases and as separate "jobs" per Django app tested. This allows tests to be run in parallel, e.g. as ``make parallel-test --jobs=20``. +* ``make scss``: Build ``legacy/website/static/style.css`` from ``legacy/website/static/style.scss`` and the SCSS files in ``legacy/website/static/scss/``. +* ``make html``: Compile documentation to HTML in ``documentation/build/``. +* ``make pdf``: Compile documentation to PDFs as ``GridPlatform.pdf`` and ``GridPlatformDomainModel.pdf``. +* ``make clean``: Delete Python bytecode files, unit test "rerun"-files, log files and the documentation PDF documents. diff --git a/documentation/source/domainmodel.rst b/documentation/source/domainmodel.rst new file mode 100644 index 0000000..959ff82 --- /dev/null +++ b/documentation/source/domainmodel.rst @@ -0,0 +1,13 @@ +Domain Model +============ + +.. toctree:: + :maxdepth: 2 + + datasources + consumptions + costcompensations + changes + projects + + samplesequences diff --git a/documentation/source/future_work.rst b/documentation/source/future_work.rst new file mode 100644 index 0000000..123580c --- /dev/null +++ b/documentation/source/future_work.rst @@ -0,0 +1,52 @@ +=========== +Future Work +=========== + +In this chapter we list a few things we had planned to do in the near future +that we feel might be of use to future developers. + + +Upgrade Python and Django +========================= + +We had planned to upgrade to Python 3 and the newest version of Django as soon +as possible. Both upgrades should be fairly straight forward. The Python 3 upgrade +might require a significant amount work if some of the libraries currently used +still are unavailable in versions working with Python 3 but for the most part +the code has been prepared for Python 3. + + +Refactor user model according to present Django convensions +=========================================================== + +The user model was naturally one of the first models implemented and back then +Django was at version 1.5. A lot has changed since then, especially regarding +to how custom user models are integrated, and therefore it would be wise to +refactor the model to follow current Django user model guidelines. + + +Get rid of :attr:`User.user_type` +=========================================================== + +The :attr:`gridplatform.users.models.User.user_type` attribute is legacy, and +is still used in GridPortal 2.0 by access control logic. However, the same +access control can easily be achieved using permissions. + + +Refactor the :attr:`Sample` class. +================================== + +The :class:`gridplatform.utils.samples.Sample` class already should be refactored into +two separate classes, namely :class:`PointSample` and :class:`RangedSample`. See +:file:`gridplatform/utils/samples.py` code comments for further details. + + +Re-specification and refactoring of the *Provider* concept +========================================================== + +When the provider concept was originally created only provider users needed +access to provider information. However, later it made sense that customers +users for a specific provider can see the provider information as well. + +Whoever continues the work on this code should stress the necessity of getting +provider concept properly specified and then refactor accordingly. diff --git a/documentation/source/gridagent_server.rst b/documentation/source/gridagent_server.rst new file mode 100644 index 0000000..7522391 --- /dev/null +++ b/documentation/source/gridagent_server.rst @@ -0,0 +1,92 @@ +**************** +GridAgent Server +**************** + +The GridAgent server listens for network connections from GridAgents. Its +primary purpose is to receive measurement data from the GridAgents and add it +to the database where the GridPortal may read it. + +It keeps track of the currently connected GridAgents, and is responsible for +forwarding time-based rules to connected GridAgents, for setting the time on +GridAgents, for storing information about the current GridAgent and GridPoint +state as provided by the GridAgent, and it is also capable of sending GridAgent +software updates and relay control signals for GridPoints. + +The GridAgent server access the same database as the GridPortal, using parts of +the same data model specified with the Django ORM that the GridPortal uses. + + + +GridAgent Server Protocol +========================= + +Communication is message-based. Messages have a common header with type, +length and a field for Boolean where this may simplify the payload. + +Apart from the initial handshake, communication is encrypted. We use a +pre-shared key, merged with a nonce from the agent to protect against playback +attacks (and with the MAC address from the agent for slightly improved +obscurity). + +Currently, the set of messages sent by a server is disjoint from the set of +messages sent by a client --- though the header is the same, and the type +identifiers are global, so this may be changed later. + +The protocol has a version number, sent by both sides as part of the handshake. +At present, the server must handle version discrepencies, i.e. communication +takes place with the protocol version specified by the client. + +Data is sent in big endian/network byte order format. + + +Handshake +--------- + +The server sends a 4-byte protocol version followed by a 8-byte random nonce. + +The client/agent sends a 4-byte protocol version followed by an 8-byte +identifiers. (Currently, agents use their Ethernet MAC address as identifiers, +with the 48-bit MAC address encoded as a 64-bit number; meaning that the first +two bytes of the identifier will always be zero.) + +In the current setup, the server is responsible for handling protocol version +discrepancies; either communication happens with the protocol version specified +by the client, or the server closes the connection. + + +Encryption +---------- + +Communication is encrypted using RC4. + +The encryption uses a key constructed by combining a shared secret with the +nonce and the ID provided by the client. + +The same key is used for communication from client to server and from server to +client, though these are otherwise considered separate streams with separate +state. + +After the handshake, communication is encrypted. + + +Message header +-------------- + +All messages after the handshake share a common header format: + +* 4-bytes unsigned message size +* 2 bytes padding +* 1 byte message type +* 1 byte boolean flags + +The length is the total length *including* the header. + + +Message structure +----------------- + +All the different messages and their structure are very simple to follow by +simply inspecting the Python code. Client and server messages are found +:file:`gridplatform/gridagentserver_protocol/client_messages.py` and +:file:`gridplatform/gridagentserver_protocol/server_messages.py`, respectively. + diff --git a/documentation/source/index.rst b/documentation/source/index.rst new file mode 100644 index 0000000..15cb758 --- /dev/null +++ b/documentation/source/index.rst @@ -0,0 +1,42 @@ +.. GridPlatform documentation master file, created by + sphinx-quickstart on Fri Oct 24 08:38:29 2014. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +GridManager ApS Developer Documentation +======================================== + +.. Contents: + +.. toctree:: + :maxdepth: 2 + + introduction + + domainmodel + + architecture + + security + + privacy + + developer_handbook + + deployment + + apps + + gridagent_server + + known_issues + + future_work + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/documentation/source/introduction.rst b/documentation/source/introduction.rst new file mode 100644 index 0000000..c23b6dd --- /dev/null +++ b/documentation/source/introduction.rst @@ -0,0 +1,45 @@ +************ +Introduction +************ + + +This is the GridManager ApS final documentation of the GridPlatform. It was +compiled in the last months before the final termination of the +GridManager ApS Research & Development department. + + +Disclaimer +========== +This documentation is intended as a minimalistic form of *hand over* +documentation to help future developers understand the code and the thoughts +behind it. The documentation here is basically all we had time to compile +before our time with GridManager ApS was up. + + +Target audience +=============== +The readers of this document are expected to be experienced software developers, +comfortable with the following technologies: + +- Python programming language +- Django web framework +- Celery (used for background tasks for Django) +- HTML and JavaScript +- RESTful web services +- Django REST Framework + +Preferably the reader is also experienced within the field of energy +management, and thus know the terminology used within that field. + + +What is documented and what is not +================================== +There are four software components that were developed by GridManager ApS. They are: +GridPlatform, GridAgent Server, GridPortal 2.0, and Energy Manager. + +Only GridAgent Server and GridPlatform are documented in detail here. The +GridPortal 2.0 is legacy and no documentation exists apart from what is found +as code comments in the code itself. However, if a developer with the right +technical skill set reads this documentation then he/she should also be able to +understand the GridPortal 2.0 design and code simply by inspecting it, as both +are software systems for use in the energy management domain. diff --git a/documentation/source/known_issues.rst b/documentation/source/known_issues.rst new file mode 100644 index 0000000..55967f0 --- /dev/null +++ b/documentation/source/known_issues.rst @@ -0,0 +1,24 @@ +============ +Known issues +============ + + +GridPortal 2.0 Super user can break measurement point groups +============================================================ + +Customer *superusers* that are bound to groups and create new *root* groups or +move existing groups to be *root* groups may lead to the absolute order of +*root* groups for the customer to **not** be well-defined. The reason for this is +that the order saved will be constructed taking only those existing groups +that are *currently visible* into account. This can lead to several groups +specifying the same position at which point the relative order among those is +unspecified and may vary when loaded/reloaded in different pages or at +different times. Displaying the *children* of such conflicting groups may also +mix/associate them wrongly. The feature of restricting a user to a certain +group is inherently broken if that user is a super user. + +To rebuild all the trees run `./manage.py rebuild_group_tree` or use the following Python statement: + +:: + + Collection.tree.rebuild() diff --git a/documentation/source/privacy.rst b/documentation/source/privacy.rst new file mode 100644 index 0000000..42665ad --- /dev/null +++ b/documentation/source/privacy.rst @@ -0,0 +1,50 @@ +******* +Privacy +******* + +We encrypt sensitive information, and we take care to avoid having the +encryption keys stored or communicated over the network. + +As the primary function of the GridPlatform is to perform calculations on +measurement it would be major performance problem if measurements were to be +encrypted. To avoid this, all textual company information is instead +considered to be confidential. That is, if you hacked the servers and dumped +the database, then you would get all the measurements but you would not know +who they belong to or in any way what they are for. Also, even if a develop +makes an access control logic error and by mistake gives a user from one customer +access to objects from another customer, the user will not be able to see the +encrypted data that do not belong to his company. In fact, it will cause an +exception to be raised and this will in turn cause the GridPlatform to send +the administrators an e-mail containing a stack trace describing exactly +where the violation occurred. + +So the privacy strategy is: + +- All textual and other information that may be used to identify a customer is + encrypted; with one encryption key per customer. Not even user names are left + unencrypted. So instead of storing user names directly in the database we are + storing a hashed version of the user name, so when a user logs in, the user + name is hashed and then matched against the user names in the database. +- The keys to decrypt data are stored encrypted; one copy per user with access; + encrypted with a private/public key pair associated with each user. +- The private key per user is stored encrypted, with the users login password + as passphrase. +- On login, users must provide their user name and passwords; which enables us + to load the relevant keys. +- To keep keys accessible during an active session, they are stored as part of + the session state --- but encrypted, with a randomly generated key provided + to the client in a cookie, to keep beside the session identifier. + + +Implementation notes +==================== + +Encrypted fields on models are accessed using the attribute name +``_plain`` instead of just ``fieldname`` and then +encryption/decryption is handled automatically. + +The ``EncryptionMiddleware`` is used to manage having encryption state in a +thread-local while processing requests, and otherwise split between encrypted +session-state and a cookie. + +Objects with encrypted fields must override method ``get_encryption_id()`` to provide an encryption key identifier. diff --git a/documentation/source/projects.rst b/documentation/source/projects.rst new file mode 100644 index 0000000..8fde252 --- /dev/null +++ b/documentation/source/projects.rst @@ -0,0 +1,28 @@ +Projects +======== + +For energy performances, energy performance indicators, and normalized energy +consumptions it is possible to define a project. A project has a goal, which +is an percentwise improvement of the involved energy performance, energy +performance indicator or normalized energy consumption. + +If the goal is (or can be translated into) a yearly cost reduction and the +investment costs of the project is well-known it is possible to calculated an +expected payback period, which may be used to prioritize which projects to +execute next. + +Projects are executed by first measuring a benchmark energy performance or +normalized energy consumption. Then implement the action of the project. And +finally measure the resulting energy performance or normalized energy +consumption. + +The change in percent between the benchmark and the result gives the achieved +improvement. If the achieved improvement is better than the goal originally +set out, the goal has been achieved. + +After the project has been completed, and costs are well-defined it is possible +to calculate the actual payback period, which may be longer or shorter than +the expected payback period. + +That the goal remains acheived can be automatically checked by measuring new +results periodically, and comparing these results to the benchmark and goal. diff --git a/documentation/source/samplesequences.rst b/documentation/source/samplesequences.rst new file mode 100644 index 0000000..3b02fbb --- /dev/null +++ b/documentation/source/samplesequences.rst @@ -0,0 +1,174 @@ +Sequences of Samples and their Operations +========================================= + +Data sources continuously bring sequences of samples into the system: + + * Utility consumption (m³, kWh), + * Pulse (impulse), + * CO₂ conversions (tonne/kWh, tonne/m³), + * Tariffs (EUR/kWh, EUR/m³) + +Main consumptions and energy uses define other sequences of samples in +terms of: + + * Variable costs (EUR), + * Utility consumption (m³, kWh), + * Energy consumption (kWh), + * CO₂ emissions, + * Energy performances, + * Normalized consumptions, + * Normalized variable costs, and so on. + +The sequences of samples can be classified according to what +operations can be applied to them and how they can be combined. + +Sequences of Accumulating Ranged Samples +---------------------------------------- + +These are the most forgiving kind of sample sequences. Each sample +covers a time range and holds a physical quantity. Sequences of +accumulating ranged samples fit well into bar charts. + +The samples of multiple such sequences having the same time range can +be added or subtracted to form a new sequence of accumulating ranged +samples. + +Samples of smaller time ranges may be accumulated over larger time +ranges, forming new samples with the larger time ranges. Doing so on +a sequence of accumulating ranged samples result in a new such +sequence. + +For sequences of accumulating ranged samples accumulation across all +the samples within a given time range is generally well-defined. +Given compatible units, this enables multiple sequences of +accumulating ranged samples to be displayed in the same pie chart. + +Typical units for these sequences include m³, kWh, impulse, EUR, h, +and tonne. + +.. _sequences-of-conversion-ranged-samples: + +Sequences of Conversion Ranged Samples +-------------------------------------- + +In their data structure these will resemble sequences of accumulating +ranged samples quite a lot. And while adding (or subtracting) samples +with the same time range of sequences of conversion ranged samples +indeed result in new such sequences, and is well defined, accumulating +samples (or any other form of aggregation) across time ranges is not +well-defined. + +Sequences of conversion ranged samples are typically illustrated as a +piece-wise constant function in a graph. + +Typical units for these sequences include EUR/m³, EUR/kWh, kWh/m³, +m³/impulse, kWh/impulse, tonne/kWh and tonne/m³. + +Note that while the units of conversion ranged samples in general seem +to be fractions, the implication does not go both ways. There are +ranged samples whose units are fractions that can't be said to be +conversion ranged samples. See sequences of fractional ranged +samples. + +Sequences of conversion ranged samples may be sample-wise multiplied +with a sequence of accumulation ranged samples, resulting in a new +sequence of accumulation ranged samples, having the units that would +result from the multiplication (e.g. a sequence of conversion ranged +sample with unit EUR/m³ multiplied with a sequence of accumulation +ranged samples with unit m³ gives a sequence of accumulation ranged +samples with the unit EUR). The time range of multiplied samples must +match exactly. If the sequence of accumulated ranged samples is in a +too fine time range resolution, it should be accumulated to the matching +time resolution as described earlier before multiplication. + +Sequences of Fractional Ranged Samples +-------------------------------------- + +Given two sequences of accumulating ranged samples, we can sample-wise +divide one with the other (if the sample of other is not zero). A +great deal of information is lost in this process, yet the result is +often easy for humans to interpret. + +Because of the information loss, no aggregation of samples across +periods is well-defined. Sample-wise addition of two sequences of +fractional ranged samples is also not well-defined. Data sources on +this form in general should be avoided as they provide the system with +very little information to work with. + +Typical semantics of these sequences of fractional ranged samples include: + + * Marginal energy consumption (kWh/pcs), + * Heat-loss coefficient (W/°K), + * Cool-down temperature of distribution medium for district heating (°K), + * Mean power (W), + * Mean flow (m³/h), + * Marginal CO₂ emissions (tonne/pcs), + * Mean power factor (kWh/kVAh), and so on. + +While aggregation of samples is out of the question, it is possible to +calculate sequences of fractional ranged samples in any time range +resolution in which the input sequences of accumulated ranged samples +are available. For example mean power can both be calculated hour by +hour, and day by day. + +Sequences of fractional ranged samples may be used as sequences of +conversion ranged samples in normalization of consumptions and costs. +For instance marginal energy consumption (kWh/pcs) can be used to +convert normal productions (pcs) to normalized energy consumption +(kWh). + +.. _sequences-of-continuous-point-samples: + +Sequences of Continuous Point Samples +------------------------------------- + +These sequences sample underlying continuous functions, and may stem +from data sources, or be calculated from other sequences of continuous +point samples. + +Sequences of continuous point samples are graphed by continuous +function by linear interpolation. + +Typical semantics of sequences of continuous point samples include: + + * Power (W), + * Electrical current (A), + * Voltage (V), + * Temperature (°K), + * Power factor (kW/kVA), + * Reactive power (VAr), + * Volume flow (m³/h), and so on. + +.. _sequences-of-ranged-samples-aggregating-sequences-of-continuous-point-samples: + +Sequences of Ranged Samples Aggregating Sequences of Continuous Point Samples +----------------------------------------------------------------------------- + +Sequences of continuous point samples can be converted to sequences of +aggregate ranged samples, by aggregation across time ranges +corresponding to the time ranges of the ranged samples in the +resulting sequence of aggregate ranged samples. Well-defined +aggregate functions for this include average, minimum and maximum. + +If the desired sequence of aggregate ranged samples alternatively can +be defined as a sequence of fractional ranged samples this is to be +preferred for its higher precision. For instance mean power should +be defined by a sequence of fractional ranged samples, so the result +is the actual mean, and not just a sampled mean, where as mean outdoor +temperature often cannot be defined by such a sequence of fractional +ranged samples (though it would be possible to create such a meter). + +Typical semantics of sequences of ranged samples aggregating sequences +of continuous point samples include: + + * Minimum outdoor temperature (°K), + * Maximum outdoor temperature (°K), + * Average outdoor temperature (°K). + +Another interesting class of aggregate functions to consider is +conditional-time-weighed sums. The resulting sequence of ranged +samples aggregating sequences of continuous point samples is in fact a +sequence of accumulating ranged samples. Examples include: + + * Heating degree days (°K*days) + * Cooling degree days (°K*days) diff --git a/documentation/source/security.rst b/documentation/source/security.rst new file mode 100644 index 0000000..51d4dbc --- /dev/null +++ b/documentation/source/security.rst @@ -0,0 +1,45 @@ +******** +Security +******** + +Various security mechanisms are used in order to maximise the security of the +GridPlatform. They are explained in this chapter. + + +Secure Socket Layer (SSL) +========================= +When deploying GridPlatform to a production environment, the web servers must +always be set up with valid SSL certificates and web server communication must +only allow SSL connections from clients. + + +Cross Site Request Forgery (CSRF) protection +============================================ +CRSF protection is part of the Django framework. Refer to the Django documentation for details (https://docs.djangoproject.com/en/dev/ref/csrf/). + + +Model Permissions +================= +The permission and groups available in ``django.contrib.auth`` are use +implement access control. Refer to the Django documentation for details. + + +Other Access Control mechanisms +=============================== + +The user model has a ``user_type`` field, which in GridPortal 2.0 is used for access control purposes. + + +API tokens +========== + +To allow secure access to the GridPlatform via the REST API an API key scheme +has been implemented. API users can be created using the Energy Manager +administration site and a key generated for them. The key is only shown on +creation, and if in any way forgotten a new must be generated for that user. + +These keys are as confidential as user names as password as they enable the +owner to login and decrypt the data belonging to the customer associated with that user. + +In the case of provider API users the user has the ability to decrypt all data +for all customers belonging to that provider. diff --git a/emoncms/.gitignore b/emoncms/.gitignore new file mode 100644 index 0000000..41e0b05 --- /dev/null +++ b/emoncms/.gitignore @@ -0,0 +1,30 @@ +.project +debian/emoncms* +settings.php +Modules/sync +Modules/event +Modules/energyaudit +Modules/auto +Modules/energy +Modules/energyform +Modules/energydata +Modules/energygroup +Modules/raspberrypi +Modules/site +Modules/command +Modules/sap +Modules/rss +Modules/adminusers +Modules/feedconvert +Modules/report +Modules/notify +Modules/converttotimestore +Modules/mqtt +Modules/packetgen +Modules/openbem +Modules/scheduler +Modules/nodes +Modules/wifi +Modules/app +Modules/config +emoncms.log diff --git a/emoncms/.htaccess b/emoncms/.htaccess new file mode 100644 index 0000000..1b7b7ae --- /dev/null +++ b/emoncms/.htaccess @@ -0,0 +1,196 @@ +# +# Apache/PHP/Emoncms settings: +# + +# Don't show directory listings for URLs which map to a directory. +Options -Indexes + +# Make Emoncms handle any 404 errors. +ErrorDocument 404 /index.php + +# Set the default handler. +DirectoryIndex index.php + +# Various rewrite rules. + + RewriteEngine on + + # Rewrite URLs of the form 'x' to the form 'index.php?q=x'. + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} !=/favicon.ico + RewriteRule ^(.*)$ index.php?q=$1 [L,QSA] + + +# ------------------------------------------------------------------------------ +# The following are taken from html5 boilerplate +# url: https://github.com/h5bp/html5-boilerplate/blob/master/.htaccess +# ------------------------------------------------------------------------------ + +# ------------------------------------------------------------------------------ +# | Proper MIME types for all files | +# ------------------------------------------------------------------------------ + + + + # Audio + AddType audio/mp4 m4a f4a f4b + AddType audio/ogg oga ogg opus + + # Data interchange + AddType application/json json map + AddType application/ld+json jsonld + + # JavaScript + # Normalize to standard type. + # http://tools.ietf.org/html/rfc4329#section-7.2 + AddType application/javascript js + + # Video + AddType video/mp4 f4v f4p m4v mp4 + AddType video/ogg ogv + AddType video/webm webm + AddType video/x-flv flv + + # Web fonts + AddType application/font-woff woff + AddType application/vnd.ms-fontobject eot + + # Browsers usually ignore the font MIME types and simply sniff the bytes + # to figure out the font type. + # http://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern + + # Chrome however, shows a warning if any other MIME types are used for + # the following fonts. + + AddType application/x-font-ttf ttc ttf + AddType font/opentype otf + + # Make SVGZ fonts work on the iPad. + # https://twitter.com/FontSquirrel/status/14855840545 + AddType image/svg+xml svgz + AddEncoding gzip svgz + + # Other + AddType application/octet-stream safariextz + AddType application/x-chrome-extension crx + AddType application/x-opera-extension oex + AddType application/x-web-app-manifest+json webapp + AddType application/x-xpinstall xpi + AddType application/xml atom rdf rss xml + AddType image/webp webp + AddType image/x-icon cur + AddType text/cache-manifest appcache manifest + AddType text/vtt vtt + AddType text/x-component htc + AddType text/x-vcard vcf + + + +# ------------------------------------------------------------------------------ +# | UTF-8 encoding | +# ------------------------------------------------------------------------------ + +# Use UTF-8 encoding for anything served as `text/html` or `text/plain`. +AddDefaultCharset utf-8 + +# Force UTF-8 for certain file formats. + + AddCharset utf-8 .atom .css .js .json .jsonld .rss .vtt .webapp .xml + + +# ------------------------------------------------------------------------------ +# | Compression | +# ------------------------------------------------------------------------------ + + + + # Force compression for mangled headers. + # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping + + + SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding + RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding + + + + # Compress all output labeled with one of the following MIME-types + # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` + # and can remove the `` and `` lines + # as `AddOutputFilterByType` is still in the core directives). + + AddOutputFilterByType DEFLATE application/atom+xml \ + application/javascript \ + application/json \ + application/ld+json \ + application/rss+xml \ + application/vnd.ms-fontobject \ + application/x-font-ttf \ + application/x-web-app-manifest+json \ + application/xhtml+xml \ + application/xml \ + font/opentype \ + image/svg+xml \ + image/x-icon \ + text/css \ + text/html \ + text/plain \ + text/x-component \ + text/xml + + + + +# ------------------------------------------------------------------------------ +# | File access | +# ------------------------------------------------------------------------------ + +# Block access to directories without a default document. +# You should leave the following uncommented, as you shouldn't allow anyone to +# surf through every directory on your server (which may includes rather private +# places such as the CMS's directories). + + + Options -Indexes + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +# Block access to hidden files and directories. +# This includes directories used by version control systems such as Git and SVN. + + + RewriteCond %{SCRIPT_FILENAME} -d [OR] + RewriteCond %{SCRIPT_FILENAME} -f + RewriteRule "(^|/)\." - [F] + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +# Block access to files that can expose sensitive information. + +# By default, block access to backup and source files that may be left by some +# text editors and can pose a security risk when anyone has access to them. +# http://feross.org/cmsploit/ + +# IMPORTANT: Update the `` regular expression from below to include +# any files that might end up on your production server and can expose sensitive +# information about your website. These files may include: configuration files, +# files that contain metadata about the project (e.g.: project dependencies), +# build scripts, etc.. + + + + # Apache < 2.3 + + Order allow,deny + Deny from all + Satisfy All + + + # Apache ≥ 2.3 + + Require all denied + + + \ No newline at end of file diff --git a/emoncms/.jshintrc b/emoncms/.jshintrc new file mode 100644 index 0000000..a7454cd --- /dev/null +++ b/emoncms/.jshintrc @@ -0,0 +1,13 @@ +{ + "browser": true, + "esnext": true, + "globals": { + "$": false + }, + "globalstrict": true, + "quotmark": "double", + "smarttabs": true, + "trailing": true, + "undef": true, + "unused": true +} diff --git a/emoncms/COPYRIGHT.txt b/emoncms/COPYRIGHT.txt new file mode 100644 index 0000000..f60df5c --- /dev/null +++ b/emoncms/COPYRIGHT.txt @@ -0,0 +1,24 @@ + Emoncms - open source energy visualisation + Part of the openenergymonitor.org project + + Copyright (C) 2011,2012,2013,2014 the OpenEnergyMonitor researchers (see individual contributions from github commits) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or any later version. + + 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + Contact: + + Trystan Lea + trystan.lea@gmail.com + http://openenergymonitor.org + diff --git a/emoncms/LICENSE.txt b/emoncms/LICENSE.txt new file mode 100644 index 0000000..4ec8c3f --- /dev/null +++ b/emoncms/LICENSE.txt @@ -0,0 +1,619 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/emoncms/Lib/bootstrap-datetimepicker-0.0.11/css/bootstrap-datetimepicker.min.css b/emoncms/Lib/bootstrap-datetimepicker-0.0.11/css/bootstrap-datetimepicker.min.css new file mode 100644 index 0000000..36394e2 --- /dev/null +++ b/emoncms/Lib/bootstrap-datetimepicker-0.0.11/css/bootstrap-datetimepicker.min.css @@ -0,0 +1,8 @@ +/*! + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-datetimepicker-widget{top:0;left:0;width:250px;padding:4px;margin-top:1px;z-index:3000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.bootstrap-datetimepicker-widget:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:6px}.bootstrap-datetimepicker-widget:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:7px}.bootstrap-datetimepicker-widget.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget>ul{list-style-type:none;margin:0}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:100%;font-weight:bold;font-size:1.2em}.bootstrap-datetimepicker-widget table[data-hour-format="12"] .separator{width:4px;padding:0;margin:0}.bootstrap-datetimepicker-widget .datepicker>div{display:none}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget td,.bootstrap-datetimepicker-widget th{text-align:center;width:20px;height:20px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.bootstrap-datetimepicker-widget td.day:hover,.bootstrap-datetimepicker-widget td.hour:hover,.bootstrap-datetimepicker-widget td.minute:hover,.bootstrap-datetimepicker-widget td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget td.old,.bootstrap-datetimepicker-widget td.new{color:#999}.bootstrap-datetimepicker-widget td.active,.bootstrap-datetimepicker-widget td.active:hover{color:#fff;background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget td.active:hover,.bootstrap-datetimepicker-widget td.active:hover:hover,.bootstrap-datetimepicker-widget td.active:active,.bootstrap-datetimepicker-widget td.active:hover:active,.bootstrap-datetimepicker-widget td.active.active,.bootstrap-datetimepicker-widget td.active:hover.active,.bootstrap-datetimepicker-widget td.active.disabled,.bootstrap-datetimepicker-widget td.active:hover.disabled,.bootstrap-datetimepicker-widget td.active[disabled],.bootstrap-datetimepicker-widget td.active:hover[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.bootstrap-datetimepicker-widget td.active:active,.bootstrap-datetimepicker-widget td.active:hover:active,.bootstrap-datetimepicker-widget td.active.active,.bootstrap-datetimepicker-widget td.active:hover.active{background-color:#039 \9}.bootstrap-datetimepicker-widget td.disabled,.bootstrap-datetimepicker-widget td.disabled:hover{background:0;color:#999;cursor:not-allowed}.bootstrap-datetimepicker-widget td span{display:block;width:47px;height:54px;line-height:54px;float:left;margin:2px;cursor:pointer;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.bootstrap-datetimepicker-widget td span:hover{background:#eee}.bootstrap-datetimepicker-widget td span.active{color:#fff;background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget td span.active:hover,.bootstrap-datetimepicker-widget td span.active:active,.bootstrap-datetimepicker-widget td span.active.active,.bootstrap-datetimepicker-widget td span.active.disabled,.bootstrap-datetimepicker-widget td span.active[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.bootstrap-datetimepicker-widget td span.active:active,.bootstrap-datetimepicker-widget td span.active.active{background-color:#039 \9}.bootstrap-datetimepicker-widget td span.old{color:#999}.bootstrap-datetimepicker-widget td span.disabled,.bootstrap-datetimepicker-widget td span.disabled:hover{background:0;color:#999;cursor:not-allowed}.bootstrap-datetimepicker-widget th.switch{width:145px}.bootstrap-datetimepicker-widget th.next,.bootstrap-datetimepicker-widget th.prev{font-size:21px}.bootstrap-datetimepicker-widget th.disabled,.bootstrap-datetimepicker-widget th.disabled:hover{background:0;color:#999;cursor:not-allowed}.bootstrap-datetimepicker-widget thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget thead tr:first-child th:hover{background:#eee}.input-append.date .add-on i,.input-prepend.date .add-on i{display:block;cursor:pointer;width:16px;height:16px}.bootstrap-datetimepicker-widget.left-oriented:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.left-oriented:after{left:auto;right:7px} \ No newline at end of file diff --git a/emoncms/Lib/bootstrap-datetimepicker-0.0.11/js/bootstrap-datetimepicker.min.js b/emoncms/Lib/bootstrap-datetimepicker-0.0.11/js/bootstrap-datetimepicker.min.js new file mode 100644 index 0000000..a30f776 --- /dev/null +++ b/emoncms/Lib/bootstrap-datetimepicker-0.0.11/js/bootstrap-datetimepicker.min.js @@ -0,0 +1,26 @@ +/** + * @license + * ========================================================= + * bootstrap-datetimepicker.js + * http://www.eyecon.ro/bootstrap-datepicker + * ========================================================= + * Copyright 2012 Stefan Petre + * + * Contributions: + * - Andrew Rowls + * - Thiago de Arruda + * + * 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. + * ========================================================= + */ +(function($){var smartPhone=window.orientation!=undefined;var DateTimePicker=function(element,options){this.id=dpgId++;this.init(element,options)};var dateToDate=function(dt){if(typeof dt==="string"){return new Date(dt)}return dt};DateTimePicker.prototype={constructor:DateTimePicker,init:function(element,options){var icon;if(!(options.pickTime||options.pickDate))throw new Error("Must choose at least one picker");this.options=options;this.$element=$(element);this.language=options.language in dates?options.language:"en";this.pickDate=options.pickDate;this.pickTime=options.pickTime;this.isInput=this.$element.is("input");this.component=false;if(this.$element.find(".input-append")||this.$element.find(".input-prepend"))this.component=this.$element.find(".add-on");this.format=options.format;if(!this.format){if(this.isInput)this.format=this.$element.data("format");else this.format=this.$element.find("input").data("format");if(!this.format)this.format="MM/dd/yyyy"}this._compileFormat();if(this.component){icon=this.component.find("i")}if(this.pickTime){if(icon&&icon.length)this.timeIcon=icon.data("time-icon");if(!this.timeIcon)this.timeIcon="icon-time";icon.addClass(this.timeIcon)}if(this.pickDate){if(icon&&icon.length)this.dateIcon=icon.data("date-icon");if(!this.dateIcon)this.dateIcon="icon-calendar";icon.removeClass(this.timeIcon);icon.addClass(this.dateIcon)}this.widget=$(getTemplate(this.timeIcon,options.pickDate,options.pickTime,options.pick12HourFormat,options.pickSeconds,options.collapse)).appendTo("body");this.minViewMode=options.minViewMode||this.$element.data("date-minviewmode")||0;if(typeof this.minViewMode==="string"){switch(this.minViewMode){case"months":this.minViewMode=1;break;case"years":this.minViewMode=2;break;default:this.minViewMode=0;break}}this.viewMode=options.viewMode||this.$element.data("date-viewmode")||0;if(typeof this.viewMode==="string"){switch(this.viewMode){case"months":this.viewMode=1;break;case"years":this.viewMode=2;break;default:this.viewMode=0;break}}this.startViewMode=this.viewMode;this.weekStart=options.weekStart||this.$element.data("date-weekstart")||0;this.weekEnd=this.weekStart===0?6:this.weekStart-1;this.setStartDate(options.startDate||this.$element.data("date-startdate"));this.setEndDate(options.endDate||this.$element.data("date-enddate"));this.fillDow();this.fillMonths();this.fillHours();this.fillMinutes();this.fillSeconds();this.update();this.showMode();this._attachDatePickerEvents()},show:function(e){this.widget.show();this.height=this.component?this.component.outerHeight():this.$element.outerHeight();this.place();this.$element.trigger({type:"show",date:this._date});this._attachDatePickerGlobalEvents();if(e){e.stopPropagation();e.preventDefault()}},disable:function(){this.$element.find("input").prop("disabled",true);this._detachDatePickerEvents()},enable:function(){this.$element.find("input").prop("disabled",false);this._attachDatePickerEvents()},hide:function(){var collapse=this.widget.find(".collapse");for(var i=0;i");while(dowCnt'+dates[this.language].daysMin[dowCnt++%7]+"")}this.widget.find(".datepicker-days thead").append(html)},fillMonths:function(){var html="";var i=0;while(i<12){html+=''+dates[this.language].monthsShort[i++]+""}this.widget.find(".datepicker-months td").append(html)},fillDate:function(){var year=this.viewDate.getUTCFullYear();var month=this.viewDate.getUTCMonth();var currentDate=UTCDate(this._date.getUTCFullYear(),this._date.getUTCMonth(),this._date.getUTCDate(),0,0,0,0);var startYear=typeof this.startDate==="object"?this.startDate.getUTCFullYear():-Infinity;var startMonth=typeof this.startDate==="object"?this.startDate.getUTCMonth():-1;var endYear=typeof this.endDate==="object"?this.endDate.getUTCFullYear():Infinity;var endMonth=typeof this.endDate==="object"?this.endDate.getUTCMonth():12;this.widget.find(".datepicker-days").find(".disabled").removeClass("disabled");this.widget.find(".datepicker-months").find(".disabled").removeClass("disabled");this.widget.find(".datepicker-years").find(".disabled").removeClass("disabled");this.widget.find(".datepicker-days th:eq(1)").text(dates[this.language].months[month]+" "+year);var prevMonth=UTCDate(year,month-1,28,0,0,0,0);var day=DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(),prevMonth.getUTCMonth());prevMonth.setUTCDate(day);prevMonth.setUTCDate(day-(prevMonth.getUTCDay()-this.weekStart+7)%7);if(year==startYear&&month<=startMonth||year=endMonth||year>endYear){this.widget.find(".datepicker-days th:eq(2)").addClass("disabled")}var nextMonth=new Date(prevMonth.valueOf());nextMonth.setUTCDate(nextMonth.getUTCDate()+42);nextMonth=nextMonth.valueOf();var html=[];var row;var clsName;while(prevMonth.valueOf()");html.push(row)}clsName="";if(prevMonth.getUTCFullYear()year||prevMonth.getUTCFullYear()==year&&prevMonth.getUTCMonth()>month){clsName+=" new"}if(prevMonth.valueOf()===currentDate.valueOf()){clsName+=" active"}if(prevMonth.valueOf()+864e5<=this.startDate){clsName+=" disabled"}if(prevMonth.valueOf()>this.endDate){clsName+=" disabled"}row.append(''+prevMonth.getUTCDate()+"");prevMonth.setUTCDate(prevMonth.getUTCDate()+1)}this.widget.find(".datepicker-days tbody").empty().append(html);var currentYear=this._date.getUTCFullYear();var months=this.widget.find(".datepicker-months").find("th:eq(1)").text(year).end().find("span").removeClass("active");if(currentYear===year){months.eq(this._date.getUTCMonth()).addClass("active")}if(currentYear-1endYear){this.widget.find(".datepicker-months th:eq(2)").addClass("disabled")}for(var i=0;i<12;i++){if(year==startYear&&startMonth>i||yearendYear){$(months[i]).addClass("disabled")}}html="";year=parseInt(year/10,10)*10;var yearCont=this.widget.find(".datepicker-years").find("th:eq(1)").text(year+"-"+(year+9)).end().find("td");this.widget.find(".datepicker-years").find("th").removeClass("disabled");if(startYear>year){this.widget.find(".datepicker-years").find("th:eq(0)").addClass("disabled")}if(endYearendYear?" disabled":"")+'">'+year+"";year+=1}yearCont.html(html)},fillHours:function(){var table=this.widget.find(".timepicker .timepicker-hours table");table.parent().hide();var html="";if(this.options.pick12HourFormat){var current=1;for(var i=0;i<3;i+=1){html+="";for(var j=0;j<4;j+=1){var c=current.toString();html+=''+padLeft(c,2,"0")+"";current++}html+=""}}else{var current=0;for(var i=0;i<6;i+=1){html+="";for(var j=0;j<4;j+=1){var c=current.toString();html+=''+padLeft(c,2,"0")+"";current++}html+=""}}table.html(html)},fillMinutes:function(){var table=this.widget.find(".timepicker .timepicker-minutes table");table.parent().hide();var html="";var current=0;for(var i=0;i<5;i++){html+="";for(var j=0;j<4;j+=1){var c=current.toString();html+=''+padLeft(c,2,"0")+"";current+=3}html+=""}table.html(html)},fillSeconds:function(){var table=this.widget.find(".timepicker .timepicker-seconds table");table.parent().hide();var html="";var current=0;for(var i=0;i<5;i++){html+="";for(var j=0;j<4;j+=1){var c=current.toString();html+=''+padLeft(c,2,"0")+"";current+=3}html+=""}table.html(html)},fillTime:function(){if(!this._date)return;var timeComponents=this.widget.find(".timepicker span[data-time-component]");var table=timeComponents.closest("table");var is12HourFormat=this.options.pick12HourFormat;var hour=this._date.getUTCHours();var period="AM";if(is12HourFormat){if(hour>=12)period="PM";if(hour===0)hour=12;else if(hour!=12)hour=hour%12;this.widget.find(".timepicker [data-action=togglePeriod]").text(period)}hour=padLeft(hour.toString(),2,"0");var minute=padLeft(this._date.getUTCMinutes().toString(),2,"0");var second=padLeft(this._date.getUTCSeconds().toString(),2,"0");timeComponents.filter("[data-time-component=hours]").text(hour);timeComponents.filter("[data-time-component=minutes]").text(minute);timeComponents.filter("[data-time-component=seconds]").text(second)},click:function(e){e.stopPropagation();e.preventDefault();this._unset=false;var target=$(e.target).closest("span, td, th");if(target.length===1){if(!target.is(".disabled")){switch(target[0].nodeName.toLowerCase()){case"th":switch(target[0].className){case"switch":this.showMode(1);break;case"prev":case"next":var vd=this.viewDate;var navFnc=DPGlobal.modes[this.viewMode].navFnc;var step=DPGlobal.modes[this.viewMode].navStep;if(target[0].className==="prev")step=step*-1;vd["set"+navFnc](vd["get"+navFnc]()+step);this.fillDate();this.set();break}break;case"span":if(target.is(".month")){var month=target.parent().find("span").index(target);this.viewDate.setUTCMonth(month)}else{var year=parseInt(target.text(),10)||0;this.viewDate.setUTCFullYear(year)}if(this.viewMode!==0){this._date=UTCDate(this.viewDate.getUTCFullYear(),this.viewDate.getUTCMonth(),this.viewDate.getUTCDate(),this._date.getUTCHours(),this._date.getUTCMinutes(),this._date.getUTCSeconds(),this._date.getUTCMilliseconds());this.notifyChange()}this.showMode(-1);this.fillDate();this.set();break;case"td":if(target.is(".day")){var day=parseInt(target.text(),10)||1;var month=this.viewDate.getUTCMonth();var year=this.viewDate.getUTCFullYear();if(target.is(".old")){if(month===0){month=11;year-=1}else{month-=1}}else if(target.is(".new")){if(month==11){month=0;year+=1}else{month+=1}}this._date=UTCDate(year,month,day,this._date.getUTCHours(),this._date.getUTCMinutes(),this._date.getUTCSeconds(),this._date.getUTCMilliseconds());this.viewDate=UTCDate(year,month,Math.min(28,day),0,0,0,0);this.fillDate();this.set();this.notifyChange()}break}}}},actions:{incrementHours:function(e){this._date.setUTCHours(this._date.getUTCHours()+1)},incrementMinutes:function(e){this._date.setUTCMinutes(this._date.getUTCMinutes()+1)},incrementSeconds:function(e){this._date.setUTCSeconds(this._date.getUTCSeconds()+1)},decrementHours:function(e){this._date.setUTCHours(this._date.getUTCHours()-1)},decrementMinutes:function(e){this._date.setUTCMinutes(this._date.getUTCMinutes()-1)},decrementSeconds:function(e){this._date.setUTCSeconds(this._date.getUTCSeconds()-1)},togglePeriod:function(e){var hour=this._date.getUTCHours();if(hour>=12)hour-=12;else hour+=12;this._date.setUTCHours(hour)},showPicker:function(){this.widget.find(".timepicker > div:not(.timepicker-picker)").hide();this.widget.find(".timepicker .timepicker-picker").show()},showHours:function(){this.widget.find(".timepicker .timepicker-picker").hide();this.widget.find(".timepicker .timepicker-hours").show()},showMinutes:function(){this.widget.find(".timepicker .timepicker-picker").hide();this.widget.find(".timepicker .timepicker-minutes").show()},showSeconds:function(){this.widget.find(".timepicker .timepicker-picker").hide();this.widget.find(".timepicker .timepicker-seconds").show()},selectHour:function(e){var tgt=$(e.target);var value=parseInt(tgt.text(),10);if(this.options.pick12HourFormat){var current=this._date.getUTCHours();if(current>=12){if(value!=12)value=(value+12)%24}else{if(value===12)value=0;else value=value%12}}this._date.setUTCHours(value);this.actions.showPicker.call(this)},selectMinute:function(e){var tgt=$(e.target);var value=parseInt(tgt.text(),10);this._date.setUTCMinutes(value);this.actions.showPicker.call(this)},selectSecond:function(e){var tgt=$(e.target);var value=parseInt(tgt.text(),10);this._date.setUTCSeconds(value);this.actions.showPicker.call(this)}},doAction:function(e){e.stopPropagation();e.preventDefault();if(!this._date)this._date=UTCDate(1970,0,0,0,0,0,0);var action=$(e.currentTarget).data("action");var rv=this.actions[action].apply(this,arguments);this.set();this.fillTime();this.notifyChange();return rv},stopEvent:function(e){e.stopPropagation();e.preventDefault()},keydown:function(e){var self=this,k=e.which,input=$(e.target);if(k==8||k==46){setTimeout(function(){self._resetMaskPos(input)})}},keypress:function(e){var k=e.which;if(k==8||k==46){return}var input=$(e.target);var c=String.fromCharCode(k);var val=input.val()||"";val+=c;var mask=this._mask[this._maskPos];if(!mask){return false}if(mask.end!=val.length){return}if(!mask.pattern.test(val.slice(mask.start))){val=val.slice(0,val.length-1);while((mask=this._mask[this._maskPos])&&mask.character){val+=mask.character;this._maskPos++}val+=c;if(mask.end!=val.length){input.val(val);return false}else{if(!mask.pattern.test(val.slice(mask.start))){input.val(val.slice(0,mask.start));return false}else{input.val(val);this._maskPos++;return false}}}else{this._maskPos++}},change:function(e){var input=$(e.target);var val=input.val();if(this._formatPattern.test(val)){this.update();this.setValue(this._date.getTime());this.notifyChange();this.set()}else if(val&&val.trim()){this.setValue(this._date.getTime());if(this._date)this.set();else input.val("")}else{if(this._date){this.setValue(null);this.notifyChange();this._unset=true}}this._resetMaskPos(input)},showMode:function(dir){if(dir){this.viewMode=Math.max(this.minViewMode,Math.min(2,this.viewMode+dir))}this.widget.find(".datepicker > div").hide().filter(".datepicker-"+DPGlobal.modes[this.viewMode].clsName).show()},destroy:function(){this._detachDatePickerEvents();this._detachDatePickerGlobalEvents();this.widget.remove();this.$element.removeData("datetimepicker");this.component.removeData("datetimepicker")},formatDate:function(d){return this.format.replace(formatReplacer,function(match){var methodName,property,rv,len=match.length;if(match==="ms")len=1;property=dateFormatComponents[match].property;if(property==="Hours12"){rv=d.getUTCHours();if(rv===0)rv=12;else if(rv!==12)rv=rv%12}else if(property==="Period12"){if(d.getUTCHours()>=12)return"PM";else return"AM"}else{methodName="get"+property;rv=d[methodName]()}if(methodName==="getUTCMonth")rv=rv+1;if(methodName==="getUTCYear")rv=rv+1900-2e3;return padLeft(rv.toString(),len,"0")})},parseDate:function(str){var match,i,property,methodName,value,parsed={};if(!(match=this._formatPattern.exec(str)))return null;for(i=1;ival.length){this._maskPos=i;break}else if(this._mask[i].end===val.length){this._maskPos=i+1;break}}},_finishParsingDate:function(parsed){var year,month,date,hours,minutes,seconds,milliseconds;year=parsed.UTCFullYear;if(parsed.UTCYear)year=2e3+parsed.UTCYear;if(!year)year=1970;if(parsed.UTCMonth)month=parsed.UTCMonth-1;else month=0;date=parsed.UTCDate||1;hours=parsed.UTCHours||0;minutes=parsed.UTCMinutes||0;seconds=parsed.UTCSeconds||0;milliseconds=parsed.UTCMilliseconds||0;if(parsed.Hours12){hours=parsed.Hours12}if(parsed.Period12){if(/pm/i.test(parsed.Period12)){if(hours!=12)hours=(hours+12)%24}else{hours=hours%12}}return UTCDate(year,month,date,hours,minutes,seconds,milliseconds)},_compileFormat:function(){var match,component,components=[],mask=[],str=this.format,propertiesByIndex={},i=0,pos=0;while(match=formatComponent.exec(str)){component=match[0];if(component in dateFormatComponents){i++;propertiesByIndex[i]=dateFormatComponents[component].property;components.push("\\s*"+dateFormatComponents[component].getPattern(this)+"\\s*");mask.push({pattern:new RegExp(dateFormatComponents[component].getPattern(this)),property:dateFormatComponents[component].property,start:pos,end:pos+=component.length})}else{components.push(escapeRegExp(component));mask.push({pattern:new RegExp(escapeRegExp(component)),character:component,start:pos,end:++pos})}str=str.slice(component.length)}this._mask=mask;this._maskPos=0;this._formatPattern=new RegExp("^\\s*"+components.join("")+"\\s*$");this._propertiesByIndex=propertiesByIndex},_attachDatePickerEvents:function(){var self=this;this.widget.on("click",".datepicker *",$.proxy(this.click,this));this.widget.on("click","[data-action]",$.proxy(this.doAction,this));this.widget.on("mousedown",$.proxy(this.stopEvent,this));if(this.pickDate&&this.pickTime){this.widget.on("click.togglePicker",".accordion-toggle",function(e){e.stopPropagation();var $this=$(this);var $parent=$this.closest("ul");var expanded=$parent.find(".collapse.in");var closed=$parent.find(".collapse:not(.in)");if(expanded&&expanded.length){var collapseData=expanded.data("collapse");if(collapseData&&collapseData.transitioning)return;expanded.collapse("hide");closed.collapse("show");$this.find("i").toggleClass(self.timeIcon+" "+self.dateIcon);self.$element.find(".add-on i").toggleClass(self.timeIcon+" "+self.dateIcon)}})}if(this.isInput){this.$element.on({focus:$.proxy(this.show,this),change:$.proxy(this.change,this)});if(this.options.maskInput){this.$element.on({keydown:$.proxy(this.keydown,this),keypress:$.proxy(this.keypress,this)})}}else{this.$element.on({change:$.proxy(this.change,this)},"input");if(this.options.maskInput){this.$element.on({keydown:$.proxy(this.keydown,this),keypress:$.proxy(this.keypress,this)},"input")}if(this.component){this.component.on("click",$.proxy(this.show,this))}else{this.$element.on("click",$.proxy(this.show,this))}}},_attachDatePickerGlobalEvents:function(){$(window).on("resize.datetimepicker"+this.id,$.proxy(this.place,this));if(!this.isInput){$(document).on("mousedown.datetimepicker"+this.id,$.proxy(this.hide,this))}},_detachDatePickerEvents:function(){this.widget.off("click",".datepicker *",this.click);this.widget.off("click","[data-action]");this.widget.off("mousedown",this.stopEvent);if(this.pickDate&&this.pickTime){this.widget.off("click.togglePicker")}if(this.isInput){this.$element.off({focus:this.show,change:this.change});if(this.options.maskInput){this.$element.off({keydown:this.keydown,keypress:this.keypress})}}else{this.$element.off({change:this.change},"input");if(this.options.maskInput){this.$element.off({keydown:this.keydown,keypress:this.keypress},"input")}if(this.component){this.component.off("click",this.show)}else{this.$element.off("click",this.show)}}},_detachDatePickerGlobalEvents:function(){$(window).off("resize.datetimepicker"+this.id);if(!this.isInput){$(document).off("mousedown.datetimepicker"+this.id)}},_isInFixed:function(){if(this.$element){var parents=this.$element.parents();var inFixed=false;for(var i=0;i'+"
    "+""+'
    '+DPGlobal.template+"
    "+""+'
  • '+""+'
    '+TPGlobal.getTemplate(is12Hours,showSeconds)+"
    "+""+"
"+""}else if(pickTime){return'"}else{return'"}}function UTCDate(){return new Date(Date.UTC.apply(Date,arguments))}var DPGlobal={modes:[{clsName:"days",navFnc:"UTCMonth",navStep:1},{clsName:"months",navFnc:"UTCFullYear",navStep:1},{clsName:"years",navFnc:"UTCFullYear",navStep:10}],isLeapYear:function(year){return year%4===0&&year%100!==0||year%400===0},getDaysInMonth:function(year,month){return[31,DPGlobal.isLeapYear(year)?29:28,31,30,31,30,31,31,30,31,30,31][month]},headTemplate:""+""+'‹'+''+'›'+""+"",contTemplate:''};DPGlobal.template='
'+''+DPGlobal.headTemplate+""+"
"+"
"+'
'+''+DPGlobal.headTemplate+DPGlobal.contTemplate+"
"+"
"+'
'+''+DPGlobal.headTemplate+DPGlobal.contTemplate+"
"+"
";var TPGlobal={hourTemplate:'',minuteTemplate:'',secondTemplate:''};TPGlobal.getTemplate=function(is12Hours,showSeconds){return'
'+'"+""+''+''+''+(showSeconds?''+'':"")+(is12Hours?'':"")+""+""+" "+''+" "+(showSeconds?''+"":"")+(is12Hours?''+"":"")+""+""+''+''+''+(showSeconds?''+'':"")+(is12Hours?'':"")+""+"
"+TPGlobal.hourTemplate+":"+TPGlobal.minuteTemplate+":"+TPGlobal.secondTemplate+""+''+"
"+"
"+'
'+''+"
"+"
"+'
'+''+"
"+"
"+(showSeconds?'
'+''+"
"+"
":"")}})(window.jQuery); \ No newline at end of file diff --git a/emoncms/Lib/bootstrap/css/bootstrap-responsive.css b/emoncms/Lib/bootstrap/css/bootstrap-responsive.css new file mode 100644 index 0000000..5215a5d --- /dev/null +++ b/emoncms/Lib/bootstrap/css/bootstrap-responsive.css @@ -0,0 +1,1109 @@ +/*! + * Bootstrap Responsive v2.3.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +@-ms-viewport { + width: device-width; +} + +.hidden { + display: none; + visibility: hidden; +} + +.visible-phone { + display: none !important; +} + +.visible-tablet { + display: none !important; +} + +.hidden-desktop { + display: none !important; +} + +.visible-desktop { + display: inherit !important; +} + +@media (min-width: 768px) and (max-width: 979px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important ; + } + .visible-tablet { + display: inherit !important; + } + .hidden-tablet { + display: none !important; + } +} + +@media (max-width: 767px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important; + } + .visible-phone { + display: inherit !important; + } + .hidden-phone { + display: none !important; + } +} + +.visible-print { + display: none !important; +} + +@media print { + .visible-print { + display: inherit !important; + } + .hidden-print { + display: none !important; + } +} + +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 30px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.564102564102564%; + *margin-left: 2.5109110747408616%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.564102564102564%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.45299145299145%; + *width: 91.39979996362975%; + } + .row-fluid .span10 { + width: 82.90598290598291%; + *width: 82.8527914166212%; + } + .row-fluid .span9 { + width: 74.35897435897436%; + *width: 74.30578286961266%; + } + .row-fluid .span8 { + width: 65.81196581196582%; + *width: 65.75877432260411%; + } + .row-fluid .span7 { + width: 57.26495726495726%; + *width: 57.21176577559556%; + } + .row-fluid .span6 { + width: 48.717948717948715%; + *width: 48.664757228587014%; + } + .row-fluid .span5 { + width: 40.17094017094017%; + *width: 40.11774868157847%; + } + .row-fluid .span4 { + width: 31.623931623931625%; + *width: 31.570740134569924%; + } + .row-fluid .span3 { + width: 23.076923076923077%; + *width: 23.023731587561375%; + } + .row-fluid .span2 { + width: 14.52991452991453%; + *width: 14.476723040552828%; + } + .row-fluid .span1 { + width: 5.982905982905983%; + *width: 5.929714493544281%; + } + .row-fluid .offset12 { + margin-left: 105.12820512820512%; + *margin-left: 105.02182214948171%; + } + .row-fluid .offset12:first-child { + margin-left: 102.56410256410257%; + *margin-left: 102.45771958537915%; + } + .row-fluid .offset11 { + margin-left: 96.58119658119658%; + *margin-left: 96.47481360247316%; + } + .row-fluid .offset11:first-child { + margin-left: 94.01709401709402%; + *margin-left: 93.91071103837061%; + } + .row-fluid .offset10 { + margin-left: 88.03418803418803%; + *margin-left: 87.92780505546462%; + } + .row-fluid .offset10:first-child { + margin-left: 85.47008547008548%; + *margin-left: 85.36370249136206%; + } + .row-fluid .offset9 { + margin-left: 79.48717948717949%; + *margin-left: 79.38079650845607%; + } + .row-fluid .offset9:first-child { + margin-left: 76.92307692307693%; + *margin-left: 76.81669394435352%; + } + .row-fluid .offset8 { + margin-left: 70.94017094017094%; + *margin-left: 70.83378796144753%; + } + .row-fluid .offset8:first-child { + margin-left: 68.37606837606839%; + *margin-left: 68.26968539734497%; + } + .row-fluid .offset7 { + margin-left: 62.393162393162385%; + *margin-left: 62.28677941443899%; + } + .row-fluid .offset7:first-child { + margin-left: 59.82905982905982%; + *margin-left: 59.72267685033642%; + } + .row-fluid .offset6 { + margin-left: 53.84615384615384%; + *margin-left: 53.739770867430444%; + } + .row-fluid .offset6:first-child { + margin-left: 51.28205128205128%; + *margin-left: 51.175668303327875%; + } + .row-fluid .offset5 { + margin-left: 45.299145299145295%; + *margin-left: 45.1927623204219%; + } + .row-fluid .offset5:first-child { + margin-left: 42.73504273504273%; + *margin-left: 42.62865975631933%; + } + .row-fluid .offset4 { + margin-left: 36.75213675213675%; + *margin-left: 36.645753773413354%; + } + .row-fluid .offset4:first-child { + margin-left: 34.18803418803419%; + *margin-left: 34.081651209310785%; + } + .row-fluid .offset3 { + margin-left: 28.205128205128204%; + *margin-left: 28.0987452264048%; + } + .row-fluid .offset3:first-child { + margin-left: 25.641025641025642%; + *margin-left: 25.53464266230224%; + } + .row-fluid .offset2 { + margin-left: 19.65811965811966%; + *margin-left: 19.551736679396257%; + } + .row-fluid .offset2:first-child { + margin-left: 17.094017094017094%; + *margin-left: 16.98763411529369%; + } + .row-fluid .offset1 { + margin-left: 11.11111111111111%; + *margin-left: 11.004728132387708%; + } + .row-fluid .offset1:first-child { + margin-left: 8.547008547008547%; + *margin-left: 8.440625568285142%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 30px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1156px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1056px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 956px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 856px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 756px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 656px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 556px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 456px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 356px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 256px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 156px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 56px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } + .row-fluid .thumbnails { + margin-left: 0; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.7624309392265194%; + *margin-left: 2.709239449864817%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.7624309392265194%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.43646408839778%; + *width: 91.38327259903608%; + } + .row-fluid .span10 { + width: 82.87292817679558%; + *width: 82.81973668743387%; + } + .row-fluid .span9 { + width: 74.30939226519337%; + *width: 74.25620077583166%; + } + .row-fluid .span8 { + width: 65.74585635359117%; + *width: 65.69266486422946%; + } + .row-fluid .span7 { + width: 57.18232044198895%; + *width: 57.12912895262725%; + } + .row-fluid .span6 { + width: 48.61878453038674%; + *width: 48.56559304102504%; + } + .row-fluid .span5 { + width: 40.05524861878453%; + *width: 40.00205712942283%; + } + .row-fluid .span4 { + width: 31.491712707182323%; + *width: 31.43852121782062%; + } + .row-fluid .span3 { + width: 22.92817679558011%; + *width: 22.87498530621841%; + } + .row-fluid .span2 { + width: 14.3646408839779%; + *width: 14.311449394616199%; + } + .row-fluid .span1 { + width: 5.801104972375691%; + *width: 5.747913483013988%; + } + .row-fluid .offset12 { + margin-left: 105.52486187845304%; + *margin-left: 105.41847889972962%; + } + .row-fluid .offset12:first-child { + margin-left: 102.76243093922652%; + *margin-left: 102.6560479605031%; + } + .row-fluid .offset11 { + margin-left: 96.96132596685082%; + *margin-left: 96.8549429881274%; + } + .row-fluid .offset11:first-child { + margin-left: 94.1988950276243%; + *margin-left: 94.09251204890089%; + } + .row-fluid .offset10 { + margin-left: 88.39779005524862%; + *margin-left: 88.2914070765252%; + } + .row-fluid .offset10:first-child { + margin-left: 85.6353591160221%; + *margin-left: 85.52897613729868%; + } + .row-fluid .offset9 { + margin-left: 79.8342541436464%; + *margin-left: 79.72787116492299%; + } + .row-fluid .offset9:first-child { + margin-left: 77.07182320441989%; + *margin-left: 76.96544022569647%; + } + .row-fluid .offset8 { + margin-left: 71.2707182320442%; + *margin-left: 71.16433525332079%; + } + .row-fluid .offset8:first-child { + margin-left: 68.50828729281768%; + *margin-left: 68.40190431409427%; + } + .row-fluid .offset7 { + margin-left: 62.70718232044199%; + *margin-left: 62.600799341718584%; + } + .row-fluid .offset7:first-child { + margin-left: 59.94475138121547%; + *margin-left: 59.838368402492065%; + } + .row-fluid .offset6 { + margin-left: 54.14364640883978%; + *margin-left: 54.037263430116376%; + } + .row-fluid .offset6:first-child { + margin-left: 51.38121546961326%; + *margin-left: 51.27483249088986%; + } + .row-fluid .offset5 { + margin-left: 45.58011049723757%; + *margin-left: 45.47372751851417%; + } + .row-fluid .offset5:first-child { + margin-left: 42.81767955801105%; + *margin-left: 42.71129657928765%; + } + .row-fluid .offset4 { + margin-left: 37.01657458563536%; + *margin-left: 36.91019160691196%; + } + .row-fluid .offset4:first-child { + margin-left: 34.25414364640884%; + *margin-left: 34.14776066768544%; + } + .row-fluid .offset3 { + margin-left: 28.45303867403315%; + *margin-left: 28.346655695309746%; + } + .row-fluid .offset3:first-child { + margin-left: 25.69060773480663%; + *margin-left: 25.584224756083227%; + } + .row-fluid .offset2 { + margin-left: 19.88950276243094%; + *margin-left: 19.783119783707537%; + } + .row-fluid .offset2:first-child { + margin-left: 17.12707182320442%; + *margin-left: 17.02068884448102%; + } + .row-fluid .offset1 { + margin-left: 11.32596685082873%; + *margin-left: 11.219583872105325%; + } + .row-fluid .offset1:first-child { + margin-left: 8.56353591160221%; + *margin-left: 8.457152932878806%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 710px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 648px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 586px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 524px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 462px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 400px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 338px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 276px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 214px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 152px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 90px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 28px; + } +} + +@media (max-width: 767px) { + body { + padding-right: 20px; + padding-left: 20px; + } + .navbar-fixed-top, + .navbar-fixed-bottom, + .navbar-static-top { + margin-right: -20px; + margin-left: -20px; + } + .container-fluid { + padding: 0; + } + .dl-horizontal dt { + float: none; + width: auto; + clear: none; + text-align: left; + } + .dl-horizontal dd { + margin-left: 0; + } + .container { + width: auto; + } + .row-fluid { + width: 100%; + } + .row, + .thumbnails { + margin-left: 0; + } + .thumbnails > li { + float: none; + margin-left: 0; + } + [class*="span"], + .uneditable-input[class*="span"], + .row-fluid [class*="span"] { + display: block; + float: none; + width: 100%; + margin-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .span12, + .row-fluid .span12 { + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="offset"]:first-child { + margin-left: 0; + } + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; + width: auto; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 0; + } + .modal { + position: fixed; + top: 20px; + right: 20px; + left: 20px; + width: auto; + margin: 0; + } + .modal.fade { + top: -100px; + } + .modal.fade.in { + top: 20px; + } +} + +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 20px; + } + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-right: 10px; + padding-left: 10px; + } + .media .pull-left, + .media .pull-right { + display: block; + float: none; + margin-bottom: 10px; + } + .media-object { + margin-right: 0; + margin-left: 0; + } + .modal { + top: 10px; + right: 10px; + left: 10px; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top, + .navbar-fixed-bottom { + position: static; + } + .navbar-fixed-top { + margin-bottom: 20px; + } + .navbar-fixed-bottom { + margin-top: 20px; + } + .navbar-fixed-top .navbar-inner, + .navbar-fixed-bottom .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-right: 10px; + padding-left: 10px; + margin: 0 0 0 -5px; + } + .nav-collapse { + clear: both; + } + .nav-collapse .nav { + float: none; + margin: 0 0 10px; + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: #777777; + text-shadow: none; + } + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 9px 15px; + font-weight: bold; + color: #777777; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .nav > li > a:focus, + .nav-collapse .dropdown-menu a:hover, + .nav-collapse .dropdown-menu a:focus { + background-color: #f2f2f2; + } + .navbar-inverse .nav-collapse .nav > li > a, + .navbar-inverse .nav-collapse .dropdown-menu a { + color: #999999; + } + .navbar-inverse .nav-collapse .nav > li > a:hover, + .navbar-inverse .nav-collapse .nav > li > a:focus, + .navbar-inverse .nav-collapse .dropdown-menu a:hover, + .navbar-inverse .nav-collapse .dropdown-menu a:focus { + background-color: #111111; + } + .nav-collapse.in .btn-group { + padding: 0; + margin-top: 5px; + } + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + display: none; + float: none; + max-width: none; + padding: 0; + margin: 0 15px; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .nav-collapse .open > .dropdown-menu { + display: block; + } + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .nav > li > .dropdown-menu:before, + .nav-collapse .nav > li > .dropdown-menu:after { + display: none; + } + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + padding: 10px 15px; + margin: 10px 0; + border-top: 1px solid #f2f2f2; + border-bottom: 1px solid #f2f2f2; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar-inverse .nav-collapse .navbar-form, + .navbar-inverse .nav-collapse .navbar-search { + border-top-color: #111111; + border-bottom-color: #111111; + } + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + .nav-collapse, + .nav-collapse.collapse { + height: 0; + overflow: hidden; + } + .navbar .btn-navbar { + display: block; + } + .navbar-static .navbar-inner { + padding-right: 10px; + padding-left: 10px; + } +} + +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } +} diff --git a/emoncms/Lib/bootstrap/css/bootstrap-responsive.min.css b/emoncms/Lib/bootstrap/css/bootstrap-responsive.min.css new file mode 100644 index 0000000..0597860 --- /dev/null +++ b/emoncms/Lib/bootstrap/css/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.3.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/emoncms/Lib/bootstrap/css/bootstrap.css b/emoncms/Lib/bootstrap/css/bootstrap.css new file mode 100644 index 0000000..b255056 --- /dev/null +++ b/emoncms/Lib/bootstrap/css/bootstrap.css @@ -0,0 +1,6158 @@ +/*! + * Bootstrap v2.3.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + width: auto\9; + height: auto; + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +#map_canvas img, +.google-maps img { + max-width: none; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; +} + +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-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 0.5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 20px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover, +a:focus { + color: #005580; + text-decoration: underline; +} + +.img-rounded { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.img-circle { + -webkit-border-radius: 500px; + -moz-border-radius: 500px; + border-radius: 500px; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + line-height: 0; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; +} + +.container, +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.127659574468085%; + *margin-left: 2.074468085106383%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.127659574468085%; +} + +.row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; +} + +.row-fluid .span11 { + width: 91.48936170212765%; + *width: 91.43617021276594%; +} + +.row-fluid .span10 { + width: 82.97872340425532%; + *width: 82.92553191489361%; +} + +.row-fluid .span9 { + width: 74.46808510638297%; + *width: 74.41489361702126%; +} + +.row-fluid .span8 { + width: 65.95744680851064%; + *width: 65.90425531914893%; +} + +.row-fluid .span7 { + width: 57.44680851063829%; + *width: 57.39361702127659%; +} + +.row-fluid .span6 { + width: 48.93617021276595%; + *width: 48.88297872340425%; +} + +.row-fluid .span5 { + width: 40.42553191489362%; + *width: 40.37234042553192%; +} + +.row-fluid .span4 { + width: 31.914893617021278%; + *width: 31.861702127659576%; +} + +.row-fluid .span3 { + width: 23.404255319148934%; + *width: 23.351063829787233%; +} + +.row-fluid .span2 { + width: 14.893617021276595%; + *width: 14.840425531914894%; +} + +.row-fluid .span1 { + width: 6.382978723404255%; + *width: 6.329787234042553%; +} + +.row-fluid .offset12 { + margin-left: 104.25531914893617%; + *margin-left: 104.14893617021275%; +} + +.row-fluid .offset12:first-child { + margin-left: 102.12765957446808%; + *margin-left: 102.02127659574467%; +} + +.row-fluid .offset11 { + margin-left: 95.74468085106382%; + *margin-left: 95.6382978723404%; +} + +.row-fluid .offset11:first-child { + margin-left: 93.61702127659574%; + *margin-left: 93.51063829787232%; +} + +.row-fluid .offset10 { + margin-left: 87.23404255319149%; + *margin-left: 87.12765957446807%; +} + +.row-fluid .offset10:first-child { + margin-left: 85.1063829787234%; + *margin-left: 84.99999999999999%; +} + +.row-fluid .offset9 { + margin-left: 78.72340425531914%; + *margin-left: 78.61702127659572%; +} + +.row-fluid .offset9:first-child { + margin-left: 76.59574468085106%; + *margin-left: 76.48936170212764%; +} + +.row-fluid .offset8 { + margin-left: 70.2127659574468%; + *margin-left: 70.10638297872339%; +} + +.row-fluid .offset8:first-child { + margin-left: 68.08510638297872%; + *margin-left: 67.9787234042553%; +} + +.row-fluid .offset7 { + margin-left: 61.70212765957446%; + *margin-left: 61.59574468085106%; +} + +.row-fluid .offset7:first-child { + margin-left: 59.574468085106375%; + *margin-left: 59.46808510638297%; +} + +.row-fluid .offset6 { + margin-left: 53.191489361702125%; + *margin-left: 53.085106382978715%; +} + +.row-fluid .offset6:first-child { + margin-left: 51.063829787234035%; + *margin-left: 50.95744680851063%; +} + +.row-fluid .offset5 { + margin-left: 44.68085106382979%; + *margin-left: 44.57446808510638%; +} + +.row-fluid .offset5:first-child { + margin-left: 42.5531914893617%; + *margin-left: 42.4468085106383%; +} + +.row-fluid .offset4 { + margin-left: 36.170212765957444%; + *margin-left: 36.06382978723405%; +} + +.row-fluid .offset4:first-child { + margin-left: 34.04255319148936%; + *margin-left: 33.93617021276596%; +} + +.row-fluid .offset3 { + margin-left: 27.659574468085104%; + *margin-left: 27.5531914893617%; +} + +.row-fluid .offset3:first-child { + margin-left: 25.53191489361702%; + *margin-left: 25.425531914893618%; +} + +.row-fluid .offset2 { + margin-left: 19.148936170212764%; + *margin-left: 19.04255319148936%; +} + +.row-fluid .offset2:first-child { + margin-left: 17.02127659574468%; + *margin-left: 16.914893617021278%; +} + +.row-fluid .offset1 { + margin-left: 10.638297872340425%; + *margin-left: 10.53191489361702%; +} + +.row-fluid .offset1:first-child { + margin-left: 8.51063829787234%; + *margin-left: 8.404255319148938%; +} + +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} + +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + line-height: 0; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 10px; +} + +.lead { + margin-bottom: 20px; + font-size: 21px; + font-weight: 200; + line-height: 30px; +} + +small { + font-size: 85%; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +cite { + font-style: normal; +} + +.muted { + color: #999999; +} + +a.muted:hover, +a.muted:focus { + color: #808080; +} + +.text-warning { + color: #c09853; +} + +a.text-warning:hover, +a.text-warning:focus { + color: #a47e3c; +} + +.text-error { + color: #b94a48; +} + +a.text-error:hover, +a.text-error:focus { + color: #953b39; +} + +.text-info { + color: #3a87ad; +} + +a.text-info:hover, +a.text-info:focus { + color: #2d6987; +} + +.text-success { + color: #468847; +} + +a.text-success:hover, +a.text-success:focus { + color: #356635; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 10px 0; + font-family: inherit; + font-weight: bold; + line-height: 20px; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + line-height: 1; + color: #999999; +} + +h1, +h2, +h3 { + line-height: 40px; +} + +h1 { + font-size: 38.5px; +} + +h2 { + font-size: 31.5px; +} + +h3 { + font-size: 24.5px; +} + +h4 { + font-size: 17.5px; +} + +h5 { + font-size: 14px; +} + +h6 { + font-size: 11.9px; +} + +h1 small { + font-size: 24.5px; +} + +h2 small { + font-size: 17.5px; +} + +h3 small { + font-size: 14px; +} + +h4 small { + font-size: 14px; +} + +.page-header { + padding-bottom: 9px; + margin: 20px 0 30px; + border-bottom: 1px solid #eeeeee; +} + +ul, +ol { + padding: 0; + margin: 0 0 10px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +li { + line-height: 20px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; +} + +ul.inline > li, +ol.inline > li { + display: inline-block; + *display: inline; + padding-right: 5px; + padding-left: 5px; + *zoom: 1; +} + +dl { + margin-bottom: 20px; +} + +dt, +dd { + line-height: 20px; +} + +dt { + font-weight: bold; +} + +dd { + margin-left: 10px; +} + +.dl-horizontal { + *zoom: 1; +} + +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + line-height: 0; + content: ""; +} + +.dl-horizontal:after { + clear: both; +} + +.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; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 17.5px; + font-weight: 300; + line-height: 1.25; +} + +blockquote small { + display: block; + line-height: 20px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +blockquote.pull-right small:before { + content: ''; +} + +blockquote.pull-right small:after { + content: '\00A0 \2014'; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 20px; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + white-space: nowrap; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 20px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 20px; +} + +pre code { + padding: 0; + color: inherit; + white-space: pre; + white-space: pre-wrap; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 20px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: 40px; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 15px; + color: #999999; +} + +label, +input, +button, +select, +textarea { + font-size: 14px; + font-weight: normal; + line-height: 20px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; +} + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 20px; + padding: 4px 6px; + margin-bottom: 10px; + font-size: 14px; + line-height: 20px; + color: #555555; + vertical-align: middle; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +input, +textarea, +.uneditable-input { + width: 206px; +} + +textarea { + height: auto; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + *margin-top: 0; + line-height: normal; +} + +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} + +select, +input[type="file"] { + height: 30px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 30px; +} + +select { + width: 220px; + background-color: #ffffff; + border: 1px solid #cccccc; +} + +select[multiple], +select[size] { + height: auto; +} + +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.uneditable-input, +.uneditable-textarea { + color: #999999; + cursor: not-allowed; + background-color: #fcfcfc; + border-color: #cccccc; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +input:-moz-placeholder, +textarea:-moz-placeholder { + color: #999999; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #999999; +} + +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #999999; +} + +.radio, +.checkbox { + min-height: 20px; + padding-left: 20px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +.controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 926px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 846px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 766px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 686px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 606px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 526px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 446px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 366px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 286px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 206px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 126px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 46px; +} + +.controls-row { + *zoom: 1; +} + +.controls-row:before, +.controls-row:after { + display: table; + line-height: 0; + content: ""; +} + +.controls-row:after { + clear: both; +} + +.controls-row [class*="span"], +.row-fluid .controls-row [class*="span"] { + float: left; +} + +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning .control-label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error .control-label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success .control-label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +.control-group.info .control-label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3a87ad; +} + +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3a87ad; +} + +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3a87ad; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #2d6987; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; +} + +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3a87ad; + background-color: #d9edf7; + border-color: #3a87ad; +} + +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:invalid:focus, +textarea:focus:invalid:focus, +select:focus:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 19px 20px 20px; + margin-top: 20px; + margin-bottom: 20px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + line-height: 0; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.help-block, +.help-inline { + color: #595959; +} + +.help-block { + display: block; + margin-bottom: 10px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-append, +.input-prepend { + display: inline-block; + margin-bottom: 10px; + font-size: 0; + white-space: nowrap; + vertical-align: middle; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input, +.input-append .dropdown-menu, +.input-prepend .dropdown-menu, +.input-append .popover, +.input-prepend .popover { + font-size: 14px; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: top; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append input:focus, +.input-prepend input:focus, +.input-append select:focus, +.input-prepend select:focus, +.input-append .uneditable-input:focus, +.input-prepend .uneditable-input:focus { + z-index: 2; +} + +.input-append .add-on, +.input-prepend .add-on { + display: inline-block; + width: auto; + height: 20px; + min-width: 16px; + padding: 4px 5px; + font-size: 14px; + font-weight: normal; + line-height: 20px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-append .add-on, +.input-prepend .add-on, +.input-append .btn, +.input-prepend .btn, +.input-append .btn-group > .dropdown-toggle, +.input-prepend .btn-group > .dropdown-toggle { + vertical-align: top; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-append .active, +.input-prepend .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input + .btn-group .btn:last-child, +.input-append select + .btn-group .btn:last-child, +.input-append .uneditable-input + .btn-group .btn:last-child { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append .add-on, +.input-append .btn, +.input-append .btn-group { + margin-left: -1px; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child, +.input-append .btn-group:last-child > .dropdown-toggle { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append input + .btn-group .btn, +.input-prepend.input-append select + .btn-group .btn, +.input-prepend.input-append .uneditable-input + .btn-group .btn { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .btn-group:first-child { + margin-left: 0; +} + +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +/* Allow for input prepend/append in search forms */ + +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.form-search .input-append .search-query { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search .input-append .btn { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .search-query { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .btn { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + vertical-align: middle; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 10px; +} + +legend + .control-group { + margin-top: 20px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 20px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + line-height: 0; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 160px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 180px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 180px; +} + +.form-horizontal .help-block { + margin-bottom: 0; +} + +.form-horizontal input + .help-block, +.form-horizontal select + .help-block, +.form-horizontal textarea + .help-block, +.form-horizontal .uneditable-input + .help-block, +.form-horizontal .input-prepend + .help-block, +.form-horizontal .input-append + .help-block { + margin-top: 10px; +} + +.form-horizontal .form-actions { + padding-left: 180px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 20px; +} + +.table th, +.table td { + padding: 8px; + line-height: 20px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table .table { + background-color: #ffffff; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapse; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child > th:first-child, +.table-bordered tbody:first-child tr:first-child > td:first-child, +.table-bordered tbody:first-child tr:first-child > th:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered thead:first-child tr:first-child > th:last-child, +.table-bordered tbody:first-child tr:first-child > td:last-child, +.table-bordered tbody:first-child tr:first-child > th:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:first-child, +.table-bordered tbody:last-child tr:last-child > td:first-child, +.table-bordered tbody:last-child tr:last-child > th:first-child, +.table-bordered tfoot:last-child tr:last-child > td:first-child, +.table-bordered tfoot:last-child tr:last-child > th:first-child { + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:last-child, +.table-bordered tbody:last-child tr:last-child > td:last-child, +.table-bordered tbody:last-child tr:last-child > th:last-child, +.table-bordered tfoot:last-child tr:last-child > td:last-child, +.table-bordered tfoot:last-child tr:last-child > th:last-child { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { + -webkit-border-bottom-left-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-bottomleft: 0; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 0; + border-bottom-right-radius: 0; + -moz-border-radius-bottomright: 0; +} + +.table-bordered caption + thead tr:first-child th:first-child, +.table-bordered caption + tbody tr:first-child td:first-child, +.table-bordered colgroup + thead tr:first-child th:first-child, +.table-bordered colgroup + tbody tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered caption + thead tr:first-child th:last-child, +.table-bordered caption + tbody tr:first-child td:last-child, +.table-bordered colgroup + thead tr:first-child th:last-child, +.table-bordered colgroup + tbody tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-striped tbody > tr:nth-child(odd) > td, +.table-striped tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} + +.table-hover tbody tr:hover > td, +.table-hover tbody tr:hover > th { + background-color: #f5f5f5; +} + +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { + display: table-cell; + float: none; + margin-left: 0; +} + +.table td.span1, +.table th.span1 { + float: none; + width: 44px; + margin-left: 0; +} + +.table td.span2, +.table th.span2 { + float: none; + width: 124px; + margin-left: 0; +} + +.table td.span3, +.table th.span3 { + float: none; + width: 204px; + margin-left: 0; +} + +.table td.span4, +.table th.span4 { + float: none; + width: 284px; + margin-left: 0; +} + +.table td.span5, +.table th.span5 { + float: none; + width: 364px; + margin-left: 0; +} + +.table td.span6, +.table th.span6 { + float: none; + width: 444px; + margin-left: 0; +} + +.table td.span7, +.table th.span7 { + float: none; + width: 524px; + margin-left: 0; +} + +.table td.span8, +.table th.span8 { + float: none; + width: 604px; + margin-left: 0; +} + +.table td.span9, +.table th.span9 { + float: none; + width: 684px; + margin-left: 0; +} + +.table td.span10, +.table th.span10 { + float: none; + width: 764px; + margin-left: 0; +} + +.table td.span11, +.table th.span11 { + float: none; + width: 844px; + margin-left: 0; +} + +.table td.span12, +.table th.span12 { + float: none; + width: 924px; + margin-left: 0; +} + +.table tbody tr.success > td { + background-color: #dff0d8; +} + +.table tbody tr.error > td { + background-color: #f2dede; +} + +.table tbody tr.warning > td { + background-color: #fcf8e3; +} + +.table tbody tr.info > td { + background-color: #d9edf7; +} + +.table-hover tbody tr.success:hover > td { + background-color: #d0e9c6; +} + +.table-hover tbody tr.error:hover > td { + background-color: #ebcccc; +} + +.table-hover tbody tr.warning:hover > td { + background-color: #faf2cc; +} + +.table-hover tbody tr.info:hover > td { + background-color: #c4e3f3; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + margin-top: 1px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +/* White icons with optional class, or on hover/focus/active states of certain elements */ + +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:focus > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > li > a:focus > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:focus > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"], +.dropdown-submenu:focus > a > [class*=" icon-"] { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + width: 16px; + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + width: 16px; + background-position: -384px -120px; +} + +.icon-folder-open { + width: 16px; + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +} + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.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; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + outline: 0; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} + +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.open { + *z-index: 1000; +} + +.open > .dropdown-menu { + display: block; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: ""; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} + +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + -webkit-border-radius: 5px 5px 5px 0; + -moz-border-radius: 5px 5px 5px 0; + border-radius: 5px 5px 5px 0; +} + +.dropdown-submenu > a:after { + display: block; + float: right; + width: 0; + height: 0; + margin-top: 5px; + margin-right: -10px; + border-color: transparent; + border-left-color: #cccccc; + border-style: solid; + border-width: 5px 0 5px 5px; + content: " "; +} + +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.dropdown .dropdown-menu .nav-header { + padding-right: 20px; + padding-left: 20px; +} + +.typeahead { + z-index: 1051; + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 20px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 12px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 14px; + line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #cccccc; + *border: 0; + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:focus, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 11px 19px; + font-size: 17.5px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; +} + +.btn-small { + padding: 2px 10px; + font-size: 11.9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { + margin-top: 0; +} + +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 0 6px; + font-size: 10.5px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.btn-block + .btn-block { + margin-top: 5px; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn-primary { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #006dcc; + *background-color: #0044cc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-repeat: repeat-x; + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} + +.btn-warning { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #faa732; + *background-color: #f89406; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #da4f49; + *background-color: #bd362f; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #5bb75b; + *background-color: #51a351; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(to bottom, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #363636; + *background-color: #222222; + background-image: -moz-linear-gradient(top, #444444, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); + background-image: -webkit-linear-gradient(top, #444444, #222222); + background-image: -o-linear-gradient(top, #444444, #222222); + background-image: linear-gradient(to bottom, #444444, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:focus, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-link { + color: #0088cc; + cursor: pointer; + border-color: transparent; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-link:hover, +.btn-link:focus { + color: #005580; + text-decoration: underline; + background-color: transparent; +} + +.btn-link[disabled]:hover, +.btn-link[disabled]:focus { + color: #333333; + text-decoration: none; +} + +.btn-group { + position: relative; + display: inline-block; + *display: inline; + *margin-left: .3em; + font-size: 0; + white-space: nowrap; + vertical-align: middle; + *zoom: 1; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 10px; + margin-bottom: 10px; + font-size: 0; +} + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group { + margin-left: 5px; +} + +.btn-group > .btn { + position: relative; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn + .btn { + margin-left: -1px; +} + +.btn-group > .btn, +.btn-group > .dropdown-menu, +.btn-group > .popover { + font-size: 14px; +} + +.btn-group > .btn-mini { + font-size: 10.5px; +} + +.btn-group > .btn-small { + font-size: 11.9px; +} + +.btn-group > .btn-large { + font-size: 17.5px; +} + +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .btn + .dropdown-toggle { + *padding-top: 5px; + padding-right: 8px; + *padding-bottom: 5px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini + .dropdown-toggle { + *padding-top: 2px; + padding-right: 5px; + *padding-bottom: 2px; + padding-left: 5px; +} + +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large + .dropdown-toggle { + *padding-top: 7px; + padding-right: 12px; + *padding-bottom: 7px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0044cc; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} + +.btn .caret { + margin-top: 8px; + margin-left: 0; +} + +.btn-large .caret { + margin-top: 6px; +} + +.btn-large .caret { + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.btn-mini .caret, +.btn-small .caret { + margin-top: 8px; +} + +.dropup .btn-large .caret { + border-bottom-width: 5px; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.btn-group-vertical { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group-vertical > .btn { + display: block; + float: none; + max-width: 100%; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group-vertical > .btn + .btn { + margin-top: -1px; + margin-left: 0; +} + +.btn-group-vertical > .btn:first-child { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.btn-group-vertical > .btn:last-child { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.btn-group-vertical > .btn-large:first-child { + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; +} + +.btn-group-vertical > .btn-large:last-child { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 20px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert, +.alert h4 { + color: #c09853; +} + +.alert h4 { + margin: 0; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 20px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-success h4 { + color: #468847; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-danger h4, +.alert-error h4 { + color: #b94a48; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-info h4 { + color: #3a87ad; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 20px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > li > a > img { + max-width: none; +} + +.nav > .pull-right { + float: right; +} + +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 20px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + line-height: 0; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 20px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover, +.nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover, +.nav-pills > .active > a:focus { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.nav-tabs.nav-stacked > li > a:hover, +.nav-tabs.nav-stacked > li > a:focus { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.nav .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +/* move down carets for tabs */ + +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} + +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} + +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.nav > .dropdown.active > a:hover, +.nav > .dropdown.active > a:focus { + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover, +.nav > li.dropdown.open.active > a:focus { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret, +.nav li.dropdown.open a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + line-height: 0; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover, +.tabs-below > .nav-tabs > li > a:focus { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover, +.tabs-below > .nav-tabs > .active > a:focus { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover, +.tabs-left > .nav-tabs > li > a:focus { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover, +.tabs-left > .nav-tabs .active > a:focus { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover, +.tabs-right > .nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover, +.tabs-right > .nav-tabs .active > a:focus { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.nav > .disabled > a { + color: #999999; +} + +.nav > .disabled > a:hover, +.nav > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 20px; + overflow: visible; +} + +.navbar-inner { + min-height: 40px; + padding-right: 20px; + padding-left: 20px; + background-color: #fafafa; + background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); + background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); + background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); + background-repeat: repeat-x; + border: 1px solid #d4d4d4; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + *zoom: 1; + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); +} + +.navbar-inner:before, +.navbar-inner:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-inner:after { + clear: both; +} + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; + overflow: visible; +} + +.navbar .brand { + display: block; + float: left; + padding: 10px 20px 10px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + color: #777777; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .brand:hover, +.navbar .brand:focus { + text-decoration: none; +} + +.navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #777777; +} + +.navbar-link { + color: #777777; +} + +.navbar-link:hover, +.navbar-link:focus { + color: #333333; +} + +.navbar .divider-vertical { + height: 40px; + margin: 0 9px; + border-right: 1px solid #ffffff; + border-left: 1px solid #f2f2f2; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn, +.navbar .input-prepend .btn-group, +.navbar .input-append .btn-group { + margin-top: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .btn { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 5px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 5px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 14px; + margin-bottom: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.navbar-static-top { + position: static; + margin-bottom: 0; +} + +.navbar-static-top .navbar-inner { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} + +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar-fixed-bottom .navbar-inner { + -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; + margin-right: 0; +} + +.navbar .nav > li { + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 10px 15px 10px; + color: #777777; + text-decoration: none; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + color: #333333; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: #555555; + text-decoration: none; + background-color: #e5e5e5; + -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #ededed; + *background-color: #e5e5e5; + background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); + background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); + background-repeat: repeat-x; + border-color: #e5e5e5 #e5e5e5 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:focus, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + color: #ffffff; + background-color: #e5e5e5; + *background-color: #d9d9d9; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #cccccc \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .nav > li > .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .nav > li > .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: #555555; + background-color: #e5e5e5; +} + +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:before, +.navbar .nav > li > .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:after, +.navbar .nav > li > .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { + right: 100%; + left: auto; + margin-right: -1px; + margin-left: 0; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.navbar-inverse .navbar-inner { + background-color: #1b1b1b; + background-image: -moz-linear-gradient(top, #222222, #111111); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); + background-image: -webkit-linear-gradient(top, #222222, #111111); + background-image: -o-linear-gradient(top, #222222, #111111); + background-image: linear-gradient(to bottom, #222222, #111111); + background-repeat: repeat-x; + border-color: #252525; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); +} + +.navbar-inverse .brand, +.navbar-inverse .nav > li > a { + color: #999999; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .brand:hover, +.navbar-inverse .nav > li > a:hover, +.navbar-inverse .brand:focus, +.navbar-inverse .nav > li > a:focus { + color: #ffffff; +} + +.navbar-inverse .brand { + color: #999999; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .nav .active > a, +.navbar-inverse .nav .active > a:hover, +.navbar-inverse .nav .active > a:focus { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover, +.navbar-inverse .navbar-link:focus { + color: #ffffff; +} + +.navbar-inverse .divider-vertical { + border-right-color: #222222; + border-left-color: #111111; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .nav li.dropdown > a:hover .caret, +.navbar-inverse .nav li.dropdown > a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .navbar-search .search-query { + color: #ffffff; + background-color: #515151; + border-color: #111111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-inverse .navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:focus, +.navbar-inverse .navbar-search .search-query.focused { + padding: 5px 15px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-inverse .btn-navbar { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e0e0e; + *background-color: #040404; + background-image: -moz-linear-gradient(top, #151515, #040404); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); + background-image: -webkit-linear-gradient(top, #151515, #040404); + background-image: -o-linear-gradient(top, #151515, #040404); + background-image: linear-gradient(to bottom, #151515, #040404); + background-repeat: repeat-x; + border-color: #040404 #040404 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:focus, +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active, +.navbar-inverse .btn-navbar.disabled, +.navbar-inverse .btn-navbar[disabled] { + color: #ffffff; + background-color: #040404; + *background-color: #000000; +} + +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #000000 \9; +} + +.breadcrumb { + padding: 8px 15px; + margin: 0 0 20px; + list-style: none; + background-color: #f5f5f5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.breadcrumb > li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb > li > .divider { + padding: 0 5px; + color: #ccc; +} + +.breadcrumb > .active { + color: #999999; +} + +.pagination { + margin: 20px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination ul > li { + display: inline; +} + +.pagination ul > li > a, +.pagination ul > li > span { + float: left; + padding: 4px 12px; + line-height: 20px; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + border-left-width: 0; +} + +.pagination ul > li > a:hover, +.pagination ul > li > a:focus, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: #f5f5f5; +} + +.pagination ul > .active > a, +.pagination ul > .active > span { + color: #999999; + cursor: default; +} + +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pagination-large ul > li > a, +.pagination-large ul > li > span { + padding: 11px 19px; + font-size: 17.5px; +} + +.pagination-large ul > li:first-child > a, +.pagination-large ul > li:first-child > span { + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.pagination-large ul > li:last-child > a, +.pagination-large ul > li:last-child > span { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.pagination-mini ul > li:first-child > a, +.pagination-small ul > li:first-child > a, +.pagination-mini ul > li:first-child > span, +.pagination-small ul > li:first-child > span { + -webkit-border-bottom-left-radius: 3px; + border-bottom-left-radius: 3px; + -webkit-border-top-left-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-topleft: 3px; +} + +.pagination-mini ul > li:last-child > a, +.pagination-small ul > li:last-child > a, +.pagination-mini ul > li:last-child > span, +.pagination-small ul > li:last-child > span { + -webkit-border-top-right-radius: 3px; + border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 3px; +} + +.pagination-small ul > li > a, +.pagination-small ul > li > span { + padding: 2px 10px; + font-size: 11.9px; +} + +.pagination-mini ul > li > a, +.pagination-mini ul > li > span { + padding: 0 6px; + font-size: 10.5px; +} + +.pager { + margin: 20px 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + line-height: 0; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: 1050; + width: 560px; + margin-left: -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 10%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-header h3 { + margin: 0; + line-height: 30px; +} + +.modal-body { + position: relative; + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + line-height: 0; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.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; +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 11px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.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: 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + 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-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.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; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +.popover-title:empty { + display: none; +} + +.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 { + border-width: 10px; + content: ""; +} + +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; +} + +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-top-color: #ffffff; + 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, 0.25); + border-left-width: 0; +} + +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + border-right-color: #ffffff; + border-left-width: 0; +} + +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; +} + +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-bottom-color: #ffffff; + border-top-width: 0; +} + +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; +} + +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + border-left-color: #ffffff; + border-right-width: 0; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + line-height: 0; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 20px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 20px; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +a.thumbnail:hover, +a.thumbnail:focus { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; + color: #555555; +} + +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} + +.media, +.media .media { + margin-top: 15px; +} + +.media:first-child { + margin-top: 0; +} + +.media-object { + display: block; +} + +.media-heading { + margin: 0 0 5px; +} + +.media > .pull-left { + margin-right: 10px; +} + +.media > .pull-right { + margin-left: 10px; +} + +.media-list { + margin-left: 0; + list-style: none; +} + +.label, +.badge { + display: inline-block; + padding: 2px 4px; + font-size: 11.844px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.label { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding-right: 9px; + padding-left: 9px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +.label:empty, +.badge:empty { + display: none; +} + +a.label:hover, +a.label:focus, +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #b94a48; +} + +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} + +.label-warning, +.badge-warning { + background-color: #f89406; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} + +.label-success, +.badge-success { + background-color: #468847; +} + +.label-success[href], +.badge-success[href] { + background-color: #356635; +} + +.label-info, +.badge-info { + background-color: #3a87ad; +} + +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} + +.label-inverse, +.badge-inverse { + background-color: #333333; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} + +.btn .label, +.btn .badge { + position: relative; + top: -1px; +} + +.btn-mini .label, +.btn-mini .badge { + top: 0; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 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: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(to bottom, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress .bar + .bar { + -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar, +.progress .bar-danger { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar, +.progress-striped .bar-danger { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar, +.progress .bar-success { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(to bottom, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); +} + +.progress-success.progress-striped .bar, +.progress-striped .bar-success { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar, +.progress .bar-info { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(to bottom, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar, +.progress-striped .bar-info { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar, +.progress .bar-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); +} + +.progress-warning.progress-striped .bar, +.progress-striped .bar-warning { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 20px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 20px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + line-height: 1; +} + +.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: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-indicators { + position: absolute; + top: 15px; + right: 15px; + z-index: 5; + margin: 0; + list-style: none; +} + +.carousel-indicators li { + display: block; + float: left; + width: 10px; + height: 10px; + margin-left: 5px; + text-indent: -999px; + background-color: #ccc; + background-color: rgba(255, 255, 255, 0.25); + border-radius: 5px; +} + +.carousel-indicators .active { + background-color: #fff; +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 15px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + line-height: 20px; + color: #ffffff; +} + +.carousel-caption h4 { + margin: 0 0 5px; +} + +.carousel-caption p { + margin-bottom: 0; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: 30px; + color: inherit; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit li { + line-height: 30px; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} + +.affix { + position: fixed; +} diff --git a/emoncms/Lib/bootstrap/css/bootstrap.min.css b/emoncms/Lib/bootstrap/css/bootstrap.min.css new file mode 100644 index 0000000..fd5ed73 --- /dev/null +++ b/emoncms/Lib/bootstrap/css/bootstrap.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.3.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}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-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.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}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.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;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.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}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.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:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;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-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.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;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.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{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;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,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 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:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.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:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} diff --git a/emoncms/Lib/bootstrap/img/glyphicons-halflings-white.png b/emoncms/Lib/bootstrap/img/glyphicons-halflings-white.png new file mode 100644 index 0000000..3bf6484 Binary files /dev/null and b/emoncms/Lib/bootstrap/img/glyphicons-halflings-white.png differ diff --git a/emoncms/Lib/bootstrap/img/glyphicons-halflings.png b/emoncms/Lib/bootstrap/img/glyphicons-halflings.png new file mode 100644 index 0000000..a996999 Binary files /dev/null and b/emoncms/Lib/bootstrap/img/glyphicons-halflings.png differ diff --git a/emoncms/Lib/bootstrap/js/bootstrap.js b/emoncms/Lib/bootstrap/js/bootstrap.js new file mode 100644 index 0000000..a81171b --- /dev/null +++ b/emoncms/Lib/bootstrap/js/bootstrap.js @@ -0,0 +1,2268 @@ +/* =================================================== + * bootstrap-transition.js v2.3.0 + * http://twitter.github.com/bootstrap/javascript.html#transitions + * =================================================== + * Copyright 2012 Twitter, Inc. + * + * 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. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $(function () { + + $.support.transition = (function () { + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] + } + } + + }()) + + return transitionEnd && { + end: transitionEnd + } + + })() + + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-alert.js v2.3.0 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * 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. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT NO CONFLICT + * ================= */ + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + /* ALERT DATA-API + * ============== */ + + $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) + +}(window.jQuery);/* ============================================================ + * bootstrap-button.js v2.3.0 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * 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. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON NO CONFLICT + * ================== */ + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + /* BUTTON DATA-API + * =============== */ + + $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-carousel.js v2.3.0 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * 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. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + if (this.interval) clearInterval(this.interval); + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , getActiveIndex: function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + return this.$items.index(this.$active) + } + + , to: function (pos) { + var activeIndex = this.getActiveIndex() + , that = this + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activeIndex == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle() + } + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.item.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + e = $.Event('slide', { + relatedTarget: $next[0] + , direction: direction + }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + , action = typeof option == 'string' ? option : options.slide + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL NO CONFLICT + * ==================== */ + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + /* CAROUSEL DATA-API + * ================= */ + + $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = $.extend({}, $target.data(), $this.data()) + , slideIndex + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('carousel').pause().to(slideIndex).cycle() + } + + e.preventDefault() + }) + +}(window.jQuery);/* ============================================================= + * bootstrap-collapse.js v2.3.0 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * 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. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning || this.$element.hasClass('in')) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + $.support.transition && this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning || !this.$element.hasClass('in')) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSE PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSE NO CONFLICT + * ==================== */ + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + /* COLLAPSE DATA-API + * ================= */ + + $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + $(target).collapse(option) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-dropdown.js v2.3.0 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * 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. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + $parent.toggleClass('open') + } + + $this.focus() + + return false + } + + , keydown: function (e) { + var $this + , $items + , $active + , $parent + , isActive + , index + + if (!/(38|40|27)/.test(e.keyCode)) return + + $this = $(this) + + e.preventDefault() + e.stopPropagation() + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + if (!isActive || (isActive && e.keyCode == 27)) { + if (e.which == 27) $parent.find(toggle).focus() + return $this.click() + } + + $items = $('[role=menu] li:not(.divider):visible a', $parent) + + if (!$items.length) return + + index = $items.index($items.filter(':focus')) + + if (e.keyCode == 38 && index > 0) index-- // up + if (e.keyCode == 40 && index < $items.length - 1) index++ // down + if (!~index) index = 0 + + $items + .eq(index) + .focus() + } + + } + + function clearMenus() { + $(toggle).each(function () { + getParent($(this)).removeClass('open') + }) + } + + function getParent($this) { + var selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = selector && $(selector) + + if (!$parent || !$parent.length) $parent = $this.parent() + + return $parent + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.dropdown + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* DROPDOWN NO CONFLICT + * ==================== */ + + $.fn.dropdown.noConflict = function () { + $.fn.dropdown = old + return this + } + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(document) + .on('click.dropdown.data-api', clearMenus) + .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('.dropdown-menu', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle) + .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) + +}(window.jQuery); +/* ========================================================= + * bootstrap-modal.js v2.3.0 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * 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. + * ========================================================= */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function (element, options) { + this.options = options + this.$element = $(element) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + this.options.remote && this.$element.find('.modal-body').load(this.options.remote) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + , e = $.Event('show') + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + this.isShown = true + + this.escape() + + this.backdrop(function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(document.body) //don't move modals dom position + } + + that.$element.show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element + .addClass('in') + .attr('aria-hidden', false) + + that.enforceFocus() + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) : + that.$element.focus().trigger('shown') + + }) + } + + , hide: function (e) { + e && e.preventDefault() + + var that = this + + e = $.Event('hide') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + this.escape() + + $(document).off('focusin.modal') + + this.$element + .removeClass('in') + .attr('aria-hidden', true) + + $.support.transition && this.$element.hasClass('fade') ? + this.hideWithTransition() : + this.hideModal() + } + + , enforceFocus: function () { + var that = this + $(document).on('focusin.modal', function (e) { + if (that.$element[0] !== e.target && !that.$element.has(e.target).length) { + that.$element.focus() + } + }) + } + + , escape: function () { + var that = this + if (this.isShown && this.options.keyboard) { + this.$element.on('keyup.dismiss.modal', function ( e ) { + e.which == 27 && that.hide() + }) + } else if (!this.isShown) { + this.$element.off('keyup.dismiss.modal') + } + } + + , hideWithTransition: function () { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + that.hideModal() + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + that.hideModal() + }) + } + + , hideModal: function () { + var that = this + this.$element.hide() + this.backdrop(function () { + that.removeBackdrop() + that.$element.trigger('hidden') + }) + } + + , removeBackdrop: function () { + this.$backdrop.remove() + this.$backdrop = null + } + + , backdrop: function (callback) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $('").css({position:"absolute",top:0,left:0,bottom:0,right:0,"font-size":"smaller",color:"#545454"}).insertAfter(this.element)),n=this.text[t]=e("
").addClass(t).css({position:"absolute",top:0,left:0,bottom:0,right:0}).appendTo(this.textContainer)),n},n.prototype.getTextInfo=function(t,n,r,i,s){var o,u,a,f;n=""+n,typeof r=="object"?o=r.style+" "+r.variant+" "+r.weight+" "+r.size+"px/"+r.lineHeight+"px "+r.family:o=r,u=this._textCache[t],u==null&&(u=this._textCache[t]={}),a=u[o],a==null&&(a=u[o]={}),f=a[n];if(f==null){var l=e("
").html(n).css({position:"absolute","max-width":s,top:-9999}).appendTo(this.getTextLayer(t));typeof r=="object"?l.css({font:o,color:r.color}):typeof r=="string"&&l.addClass(r),f=a[n]={width:l.outerWidth(!0),height:l.outerHeight(!0),element:l,positions:[]},l.detach()}return f},n.prototype.addText=function(e,t,n,r,i,s,o,u,a){var f=this.getTextInfo(e,r,i,s,o),l=f.positions;u=="center"?t-=f.width/2:u=="right"&&(t-=f.width),a=="middle"?n-=f.height/2:a=="bottom"&&(n-=f.height);for(var c=0,h;h=l[c];c++)if(h.x==t&&h.y==n){h.active=!0;return}h={active:!0,rendered:!1,element:l.length?f.element.clone():f.element,x:t,y:n},l.push(h),h.element.css({top:Math.round(n),left:Math.round(t),"text-align":u})},n.prototype.removeText=function(e,n,r,i,s,o){if(i==null){var u=this._textCache[e];if(u!=null)for(var a in u)if(t.call(u,a)){var f=u[a];for(var l in f)if(t.call(f,l)){var c=f[l].positions;for(var h=0,p;p=c[h];h++)p.active=!1}}}else{var c=this.getTextInfo(e,i,s,o).positions;for(var h=0,p;p=c[h];h++)p.x==n&&p.y==r&&(p.active=!1)}},e.plot=function(t,n,i){var s=new r(e(t),n,i,e.plot.plugins);return s},e.plot.version="0.8.1",e.plot.plugins=[],e.fn.plot=function(t,n){return this.each(function(){e.plot(this,t,n)})}}(jQuery); \ No newline at end of file diff --git a/emoncms/Lib/flot/jquery.flot.navigate.js b/emoncms/Lib/flot/jquery.flot.navigate.js new file mode 100644 index 0000000..10256b8 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.navigate.js @@ -0,0 +1,346 @@ +/* Flot plugin for adding the ability to pan and zoom the plot. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The default behaviour is double click and scrollwheel up/down to zoom in, drag +to pan. The plugin defines plot.zoom({ center }), plot.zoomOut() and +plot.pan( offset ) so you easily can add custom controls. It also fires +"plotpan" and "plotzoom" events, useful for synchronizing plots. + +The plugin supports these options: + + zoom: { + interactive: false + trigger: "dblclick" // or "click" for single click + amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out) + } + + pan: { + interactive: false + cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer" + frameRate: 20 + } + + xaxis, yaxis, x2axis, y2axis: { + zoomRange: null // or [ number, number ] (min range, max range) or false + panRange: null // or [ number, number ] (min, max) or false + } + +"interactive" enables the built-in drag/click behaviour. If you enable +interactive for pan, then you'll have a basic plot that supports moving +around; the same for zoom. + +"amount" specifies the default amount to zoom in (so 1.5 = 150%) relative to +the current viewport. + +"cursor" is a standard CSS mouse cursor string used for visual feedback to the +user when dragging. + +"frameRate" specifies the maximum number of times per second the plot will +update itself while the user is panning around on it (set to null to disable +intermediate pans, the plot will then not update until the mouse button is +released). + +"zoomRange" is the interval in which zooming can happen, e.g. with zoomRange: +[1, 100] the zoom will never scale the axis so that the difference between min +and max is smaller than 1 or larger than 100. You can set either end to null +to ignore, e.g. [1, null]. If you set zoomRange to false, zooming on that axis +will be disabled. + +"panRange" confines the panning to stay within a range, e.g. with panRange: +[-10, 20] panning stops at -10 in one end and at 20 in the other. Either can +be null, e.g. [-10, null]. If you set panRange to false, panning on that axis +will be disabled. + +Example API usage: + + plot = $.plot(...); + + // zoom default amount in on the pixel ( 10, 20 ) + plot.zoom({ center: { left: 10, top: 20 } }); + + // zoom out again + plot.zoomOut({ center: { left: 10, top: 20 } }); + + // zoom 200% in on the pixel (10, 20) + plot.zoom({ amount: 2, center: { left: 10, top: 20 } }); + + // pan 100 pixels to the left and 20 down + plot.pan({ left: -100, top: 20 }) + +Here, "center" specifies where the center of the zooming should happen. Note +that this is defined in pixel space, not the space of the data points (you can +use the p2c helpers on the axes in Flot to help you convert between these). + +"amount" is the amount to zoom the viewport relative to the current range, so +1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out). You +can set the default in the options. + +*/ + +// First two dependencies, jquery.event.drag.js and +// jquery.mousewheel.js, we put them inline here to save people the +// effort of downloading them. + +/* +jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com) +Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt +*/ +(function(a){function e(h){var k,j=this,l=h.data||{};if(l.elem)j=h.dragTarget=l.elem,h.dragProxy=d.proxy||j,h.cursorOffsetX=l.pageX-l.left,h.cursorOffsetY=l.pageY-l.top,h.offsetX=h.pageX-h.cursorOffsetX,h.offsetY=h.pageY-h.cursorOffsetY;else if(d.dragging||l.which>0&&h.which!=l.which||a(h.target).is(l.not))return;switch(h.type){case"mousedown":return a.extend(l,a(j).offset(),{elem:j,target:h.target,pageX:h.pageX,pageY:h.pageY}),b.add(document,"mousemove mouseup",e,l),i(j,!1),d.dragging=null,!1;case!d.dragging&&"mousemove":if(g(h.pageX-l.pageX)+g(h.pageY-l.pageY) max) { + // make sure min < max + var tmp = min; + min = max; + max = tmp; + } + + //Check that we are in panRange + if (pr) { + if (pr[0] != null && min < pr[0]) { + min = pr[0]; + } + if (pr[1] != null && max > pr[1]) { + max = pr[1]; + } + } + + var range = max - min; + if (zr && + ((zr[0] != null && range < zr[0]) || + (zr[1] != null && range > zr[1]))) + return; + + opts.min = min; + opts.max = max; + }); + + plot.setupGrid(); + plot.draw(); + + if (!args.preventEvent) + plot.getPlaceholder().trigger("plotzoom", [ plot, args ]); + }; + + plot.pan = function (args) { + var delta = { + x: +args.left, + y: +args.top + }; + + if (isNaN(delta.x)) + delta.x = 0; + if (isNaN(delta.y)) + delta.y = 0; + + $.each(plot.getAxes(), function (_, axis) { + var opts = axis.options, + min, max, d = delta[axis.direction]; + + min = axis.c2p(axis.p2c(axis.min) + d), + max = axis.c2p(axis.p2c(axis.max) + d); + + var pr = opts.panRange; + if (pr === false) // no panning on this axis + return; + + if (pr) { + // check whether we hit the wall + if (pr[0] != null && pr[0] > min) { + d = pr[0] - min; + min += d; + max += d; + } + + if (pr[1] != null && pr[1] < max) { + d = pr[1] - max; + min += d; + max += d; + } + } + + opts.min = min; + opts.max = max; + }); + + plot.setupGrid(); + plot.draw(); + + if (!args.preventEvent) + plot.getPlaceholder().trigger("plotpan", [ plot, args ]); + }; + + function shutdown(plot, eventHolder) { + eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick); + eventHolder.unbind("mousewheel", onMouseWheel); + eventHolder.unbind("dragstart", onDragStart); + eventHolder.unbind("drag", onDrag); + eventHolder.unbind("dragend", onDragEnd); + if (panTimeout) + clearTimeout(panTimeout); + } + + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'navigate', + version: '1.3' + }); +})(jQuery); diff --git a/emoncms/Lib/flot/jquery.flot.navigate.min.js b/emoncms/Lib/flot/jquery.flot.navigate.min.js new file mode 100644 index 0000000..0420f16 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.navigate.min.js @@ -0,0 +1,86 @@ +/* Flot plugin for adding the ability to pan and zoom the plot. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The default behaviour is double click and scrollwheel up/down to zoom in, drag +to pan. The plugin defines plot.zoom({ center }), plot.zoomOut() and +plot.pan( offset ) so you easily can add custom controls. It also fires +"plotpan" and "plotzoom" events, useful for synchronizing plots. + +The plugin supports these options: + + zoom: { + interactive: false + trigger: "dblclick" // or "click" for single click + amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out) + } + + pan: { + interactive: false + cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer" + frameRate: 20 + } + + xaxis, yaxis, x2axis, y2axis: { + zoomRange: null // or [ number, number ] (min range, max range) or false + panRange: null // or [ number, number ] (min, max) or false + } + +"interactive" enables the built-in drag/click behaviour. If you enable +interactive for pan, then you'll have a basic plot that supports moving +around; the same for zoom. + +"amount" specifies the default amount to zoom in (so 1.5 = 150%) relative to +the current viewport. + +"cursor" is a standard CSS mouse cursor string used for visual feedback to the +user when dragging. + +"frameRate" specifies the maximum number of times per second the plot will +update itself while the user is panning around on it (set to null to disable +intermediate pans, the plot will then not update until the mouse button is +released). + +"zoomRange" is the interval in which zooming can happen, e.g. with zoomRange: +[1, 100] the zoom will never scale the axis so that the difference between min +and max is smaller than 1 or larger than 100. You can set either end to null +to ignore, e.g. [1, null]. If you set zoomRange to false, zooming on that axis +will be disabled. + +"panRange" confines the panning to stay within a range, e.g. with panRange: +[-10, 20] panning stops at -10 in one end and at 20 in the other. Either can +be null, e.g. [-10, null]. If you set panRange to false, panning on that axis +will be disabled. + +Example API usage: + + plot = $.plot(...); + + // zoom default amount in on the pixel ( 10, 20 ) + plot.zoom({ center: { left: 10, top: 20 } }); + + // zoom out again + plot.zoomOut({ center: { left: 10, top: 20 } }); + + // zoom 200% in on the pixel (10, 20) + plot.zoom({ amount: 2, center: { left: 10, top: 20 } }); + + // pan 100 pixels to the left and 20 down + plot.pan({ left: -100, top: 20 }) + +Here, "center" specifies where the center of the zooming should happen. Note +that this is defined in pixel space, not the space of the data points (you can +use the p2c helpers on the axes in Flot to help you convert between these). + +"amount" is the amount to zoom the viewport relative to the current range, so +1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out). You +can set the default in the options. + +*/// First two dependencies, jquery.event.drag.js and +// jquery.mousewheel.js, we put them inline here to save people the +// effort of downloading them. +/* +jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com) +Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt +*/(function(e){function t(i){var l,h=this,p=i.data||{};if(p.elem)h=i.dragTarget=p.elem,i.dragProxy=a.proxy||h,i.cursorOffsetX=p.pageX-p.left,i.cursorOffsetY=p.pageY-p.top,i.offsetX=i.pageX-i.cursorOffsetX,i.offsetY=i.pageY-i.cursorOffsetY;else if(a.dragging||p.which>0&&i.which!=p.which||e(i.target).is(p.not))return;switch(i.type){case"mousedown":return e.extend(p,e(h).offset(),{elem:h,target:i.target,pageX:i.pageX,pageY:i.pageY}),o.add(document,"mousemove mouseup",t,p),s(h,!1),a.dragging=null,!1;case!a.dragging&&"mousemove":if(r(i.pageX-p.pageX)+r(i.pageY-p.pageY)i){var u=r;r=i,i=u}o&&(o[0]!=null&&ro[1]&&(i=o[1]));var a=i-r;if(s&&(s[0]!=null&&as[1]))return;n.min=r,n.max=i}),t.setupGrid(),t.draw(),n.preventEvent||t.getPlaceholder().trigger("plotzoom",[t,n])},t.pan=function(n){var r={x:+n.left,y:+n.top};isNaN(r.x)&&(r.x=0),isNaN(r.y)&&(r.y=0),e.each(t.getAxes(),function(e,t){var n=t.options,i,s,o=r[t.direction];i=t.c2p(t.p2c(t.min)+o),s=t.c2p(t.p2c(t.max)+o);var u=n.panRange;if(u===!1)return;u&&(u[0]!=null&&u[0]>i&&(o=u[0]-i,i+=o,s+=o),u[1]!=null&&u[1] 1) { + options.series.pie.tilt = 1; + } else if (options.series.pie.tilt < 0) { + options.series.pie.tilt = 0; + } + } + }); + + plot.hooks.bindEvents.push(function(plot, eventHolder) { + var options = plot.getOptions(); + if (options.series.pie.show) { + if (options.grid.hoverable) { + eventHolder.unbind("mousemove").mousemove(onMouseMove); + } + if (options.grid.clickable) { + eventHolder.unbind("click").click(onClick); + } + } + }); + + plot.hooks.processDatapoints.push(function(plot, series, data, datapoints) { + var options = plot.getOptions(); + if (options.series.pie.show) { + processDatapoints(plot, series, data, datapoints); + } + }); + + plot.hooks.drawOverlay.push(function(plot, octx) { + var options = plot.getOptions(); + if (options.series.pie.show) { + drawOverlay(plot, octx); + } + }); + + plot.hooks.draw.push(function(plot, newCtx) { + var options = plot.getOptions(); + if (options.series.pie.show) { + draw(plot, newCtx); + } + }); + + function processDatapoints(plot, series, datapoints) { + if (!processed) { + processed = true; + canvas = plot.getCanvas(); + target = $(canvas).parent(); + options = plot.getOptions(); + plot.setData(combine(plot.getData())); + } + } + + function combine(data) { + + var total = 0, + combined = 0, + numCombined = 0, + color = options.series.pie.combine.color, + newdata = []; + + // Fix up the raw data from Flot, ensuring the data is numeric + + for (var i = 0; i < data.length; ++i) { + + var value = data[i].data; + + // If the data is an array, we'll assume that it's a standard + // Flot x-y pair, and are concerned only with the second value. + + // Note how we use the original array, rather than creating a + // new one; this is more efficient and preserves any extra data + // that the user may have stored in higher indexes. + + if ($.isArray(value) && value.length == 1) { + value = value[0]; + } + + if ($.isArray(value)) { + // Equivalent to $.isNumeric() but compatible with jQuery < 1.7 + if (!isNaN(parseFloat(value[1])) && isFinite(value[1])) { + value[1] = +value[1]; + } else { + value[1] = 0; + } + } else if (!isNaN(parseFloat(value)) && isFinite(value)) { + value = [1, +value]; + } else { + value = [1, 0]; + } + + data[i].data = [value]; + } + + // Sum up all the slices, so we can calculate percentages for each + + for (var i = 0; i < data.length; ++i) { + total += data[i].data[0][1]; + } + + // Count the number of slices with percentages below the combine + // threshold; if it turns out to be just one, we won't combine. + + for (var i = 0; i < data.length; ++i) { + var value = data[i].data[0][1]; + if (value / total <= options.series.pie.combine.threshold) { + combined += value; + numCombined++; + if (!color) { + color = data[i].color; + } + } + } + + for (var i = 0; i < data.length; ++i) { + var value = data[i].data[0][1]; + if (numCombined < 2 || value / total > options.series.pie.combine.threshold) { + newdata.push({ + data: [[1, value]], + color: data[i].color, + label: data[i].label, + angle: value * Math.PI * 2 / total, + percent: value / (total / 100) + }); + } + } + + if (numCombined > 1) { + newdata.push({ + data: [[1, combined]], + color: color, + label: options.series.pie.combine.label, + angle: combined * Math.PI * 2 / total, + percent: combined / (total / 100) + }); + } + + return newdata; + } + + function draw(plot, newCtx) { + + if (!target) { + return; // if no series were passed + } + + var canvasWidth = plot.getPlaceholder().width(), + canvasHeight = plot.getPlaceholder().height(), + legendWidth = target.children().filter(".legend").children().width() || 0; + + ctx = newCtx; + + // WARNING: HACK! REWRITE THIS CODE AS SOON AS POSSIBLE! + + // When combining smaller slices into an 'other' slice, we need to + // add a new series. Since Flot gives plugins no way to modify the + // list of series, the pie plugin uses a hack where the first call + // to processDatapoints results in a call to setData with the new + // list of series, then subsequent processDatapoints do nothing. + + // The plugin-global 'processed' flag is used to control this hack; + // it starts out false, and is set to true after the first call to + // processDatapoints. + + // Unfortunately this turns future setData calls into no-ops; they + // call processDatapoints, the flag is true, and nothing happens. + + // To fix this we'll set the flag back to false here in draw, when + // all series have been processed, so the next sequence of calls to + // processDatapoints once again starts out with a slice-combine. + // This is really a hack; in 0.9 we need to give plugins a proper + // way to modify series before any processing begins. + + processed = false; + + // calculate maximum radius and center point + + maxRadius = Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2; + centerTop = canvasHeight / 2 + options.series.pie.offset.top; + centerLeft = canvasWidth / 2; + + if (options.series.pie.offset.left == "auto") { + if (options.legend.position.match("w")) { + centerLeft += legendWidth / 2; + } else { + centerLeft -= legendWidth / 2; + } + } else { + centerLeft += options.series.pie.offset.left; + } + + if (centerLeft < maxRadius) { + centerLeft = maxRadius; + } else if (centerLeft > canvasWidth - maxRadius) { + centerLeft = canvasWidth - maxRadius; + } + + var slices = plot.getData(), + attempts = 0; + + // Keep shrinking the pie's radius until drawPie returns true, + // indicating that all the labels fit, or we try too many times. + + do { + if (attempts > 0) { + maxRadius *= REDRAW_SHRINK; + } + attempts += 1; + clear(); + if (options.series.pie.tilt <= 0.8) { + drawShadow(); + } + } while (!drawPie() && attempts < REDRAW_ATTEMPTS) + + if (attempts >= REDRAW_ATTEMPTS) { + clear(); + target.prepend("
Could not draw pie with labels contained inside canvas
"); + } + + if (plot.setSeries && plot.insertLegend) { + plot.setSeries(slices); + plot.insertLegend(); + } + + // we're actually done at this point, just defining internal functions at this point + + function clear() { + ctx.clearRect(0, 0, canvasWidth, canvasHeight); + target.children().filter(".pieLabel, .pieLabelBackground").remove(); + } + + function drawShadow() { + + var shadowLeft = options.series.pie.shadow.left; + var shadowTop = options.series.pie.shadow.top; + var edge = 10; + var alpha = options.series.pie.shadow.alpha; + var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; + + if (radius >= canvasWidth / 2 - shadowLeft || radius * options.series.pie.tilt >= canvasHeight / 2 - shadowTop || radius <= edge) { + return; // shadow would be outside canvas, so don't draw it + } + + ctx.save(); + ctx.translate(shadowLeft,shadowTop); + ctx.globalAlpha = alpha; + ctx.fillStyle = "#000"; + + // center and rotate to starting position + + ctx.translate(centerLeft,centerTop); + ctx.scale(1, options.series.pie.tilt); + + //radius -= edge; + + for (var i = 1; i <= edge; i++) { + ctx.beginPath(); + ctx.arc(0, 0, radius, 0, Math.PI * 2, false); + ctx.fill(); + radius -= i; + } + + ctx.restore(); + } + + function drawPie() { + + var startAngle = Math.PI * options.series.pie.startAngle; + var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; + + // center and rotate to starting position + + ctx.save(); + ctx.translate(centerLeft,centerTop); + ctx.scale(1, options.series.pie.tilt); + //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera + + // draw slices + + ctx.save(); + var currentAngle = startAngle; + for (var i = 0; i < slices.length; ++i) { + slices[i].startAngle = currentAngle; + drawSlice(slices[i].angle, slices[i].color, true); + } + ctx.restore(); + + // draw slice outlines + + if (options.series.pie.stroke.width > 0) { + ctx.save(); + ctx.lineWidth = options.series.pie.stroke.width; + currentAngle = startAngle; + for (var i = 0; i < slices.length; ++i) { + drawSlice(slices[i].angle, options.series.pie.stroke.color, false); + } + ctx.restore(); + } + + // draw donut hole + + drawDonutHole(ctx); + + ctx.restore(); + + // Draw the labels, returning true if they fit within the plot + + if (options.series.pie.label.show) { + return drawLabels(); + } else return true; + + function drawSlice(angle, color, fill) { + + if (angle <= 0 || isNaN(angle)) { + return; + } + + if (fill) { + ctx.fillStyle = color; + } else { + ctx.strokeStyle = color; + ctx.lineJoin = "round"; + } + + ctx.beginPath(); + if (Math.abs(angle - Math.PI * 2) > 0.000000001) { + ctx.moveTo(0, 0); // Center of the pie + } + + //ctx.arc(0, 0, radius, 0, angle, false); // This doesn't work properly in Opera + ctx.arc(0, 0, radius,currentAngle, currentAngle + angle / 2, false); + ctx.arc(0, 0, radius,currentAngle + angle / 2, currentAngle + angle, false); + ctx.closePath(); + //ctx.rotate(angle); // This doesn't work properly in Opera + currentAngle += angle; + + if (fill) { + ctx.fill(); + } else { + ctx.stroke(); + } + } + + function drawLabels() { + + var currentAngle = startAngle; + var radius = options.series.pie.label.radius > 1 ? options.series.pie.label.radius : maxRadius * options.series.pie.label.radius; + + for (var i = 0; i < slices.length; ++i) { + if (slices[i].percent >= options.series.pie.label.threshold * 100) { + if (!drawLabel(slices[i], currentAngle, i)) { + return false; + } + } + currentAngle += slices[i].angle; + } + + return true; + + function drawLabel(slice, startAngle, index) { + + if (slice.data[0][1] == 0) { + return true; + } + + // format label text + + var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter; + + if (lf) { + text = lf(slice.label, slice); + } else { + text = slice.label; + } + + if (plf) { + text = plf(text, slice); + } + + var halfAngle = ((startAngle + slice.angle) + startAngle) / 2; + var x = centerLeft + Math.round(Math.cos(halfAngle) * radius); + var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt; + + var html = "" + text + ""; + target.append(html); + + var label = target.children("#pieLabel" + index); + var labelTop = (y - label.height() / 2); + var labelLeft = (x - label.width() / 2); + + label.css("top", labelTop); + label.css("left", labelLeft); + + // check to make sure that the label is not outside the canvas + + if (0 - labelTop > 0 || 0 - labelLeft > 0 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) { + return false; + } + + if (options.series.pie.label.background.opacity != 0) { + + // put in the transparent background separately to avoid blended labels and label boxes + + var c = options.series.pie.label.background.color; + + if (c == null) { + c = slice.color; + } + + var pos = "top:" + labelTop + "px;left:" + labelLeft + "px;"; + $("
") + .css("opacity", options.series.pie.label.background.opacity) + .insertBefore(label); + } + + return true; + } // end individual label function + } // end drawLabels function + } // end drawPie function + } // end draw function + + // Placed here because it needs to be accessed from multiple locations + + function drawDonutHole(layer) { + if (options.series.pie.innerRadius > 0) { + + // subtract the center + + layer.save(); + var innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius; + layer.globalCompositeOperation = "destination-out"; // this does not work with excanvas, but it will fall back to using the stroke color + layer.beginPath(); + layer.fillStyle = options.series.pie.stroke.color; + layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false); + layer.fill(); + layer.closePath(); + layer.restore(); + + // add inner stroke + + layer.save(); + layer.beginPath(); + layer.strokeStyle = options.series.pie.stroke.color; + layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false); + layer.stroke(); + layer.closePath(); + layer.restore(); + + // TODO: add extra shadow inside hole (with a mask) if the pie is tilted. + } + } + + //-- Additional Interactive related functions -- + + function isPointInPoly(poly, pt) { + for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i) + ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1])) + && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0]) + && (c = !c); + return c; + } + + function findNearbySlice(mouseX, mouseY) { + + var slices = plot.getData(), + options = plot.getOptions(), + radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius, + x, y; + + for (var i = 0; i < slices.length; ++i) { + + var s = slices[i]; + + if (s.pie.show) { + + ctx.save(); + ctx.beginPath(); + ctx.moveTo(0, 0); // Center of the pie + //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here. + ctx.arc(0, 0, radius, s.startAngle, s.startAngle + s.angle / 2, false); + ctx.arc(0, 0, radius, s.startAngle + s.angle / 2, s.startAngle + s.angle, false); + ctx.closePath(); + x = mouseX - centerLeft; + y = mouseY - centerTop; + + if (ctx.isPointInPath) { + if (ctx.isPointInPath(mouseX - centerLeft, mouseY - centerTop)) { + ctx.restore(); + return { + datapoint: [s.percent, s.data], + dataIndex: 0, + series: s, + seriesIndex: i + }; + } + } else { + + // excanvas for IE doesn;t support isPointInPath, this is a workaround. + + var p1X = radius * Math.cos(s.startAngle), + p1Y = radius * Math.sin(s.startAngle), + p2X = radius * Math.cos(s.startAngle + s.angle / 4), + p2Y = radius * Math.sin(s.startAngle + s.angle / 4), + p3X = radius * Math.cos(s.startAngle + s.angle / 2), + p3Y = radius * Math.sin(s.startAngle + s.angle / 2), + p4X = radius * Math.cos(s.startAngle + s.angle / 1.5), + p4Y = radius * Math.sin(s.startAngle + s.angle / 1.5), + p5X = radius * Math.cos(s.startAngle + s.angle), + p5Y = radius * Math.sin(s.startAngle + s.angle), + arrPoly = [[0, 0], [p1X, p1Y], [p2X, p2Y], [p3X, p3Y], [p4X, p4Y], [p5X, p5Y]], + arrPoint = [x, y]; + + // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt? + + if (isPointInPoly(arrPoly, arrPoint)) { + ctx.restore(); + return { + datapoint: [s.percent, s.data], + dataIndex: 0, + series: s, + seriesIndex: i + }; + } + } + + ctx.restore(); + } + } + + return null; + } + + function onMouseMove(e) { + triggerClickHoverEvent("plothover", e); + } + + function onClick(e) { + triggerClickHoverEvent("plotclick", e); + } + + // trigger click or hover event (they send the same parameters so we share their code) + + function triggerClickHoverEvent(eventname, e) { + + var offset = plot.offset(); + var canvasX = parseInt(e.pageX - offset.left); + var canvasY = parseInt(e.pageY - offset.top); + var item = findNearbySlice(canvasX, canvasY); + + if (options.grid.autoHighlight) { + + // clear auto-highlights + + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.auto == eventname && !(item && h.series == item.series)) { + unhighlight(h.series); + } + } + } + + // highlight the slice + + if (item) { + highlight(item.series, eventname); + } + + // trigger any hover bind events + + var pos = { pageX: e.pageX, pageY: e.pageY }; + target.trigger(eventname, [pos, item]); + } + + function highlight(s, auto) { + //if (typeof s == "number") { + // s = series[s]; + //} + + var i = indexOfHighlight(s); + + if (i == -1) { + highlights.push({ series: s, auto: auto }); + plot.triggerRedrawOverlay(); + } else if (!auto) { + highlights[i].auto = false; + } + } + + function unhighlight(s) { + if (s == null) { + highlights = []; + plot.triggerRedrawOverlay(); + } + + //if (typeof s == "number") { + // s = series[s]; + //} + + var i = indexOfHighlight(s); + + if (i != -1) { + highlights.splice(i, 1); + plot.triggerRedrawOverlay(); + } + } + + function indexOfHighlight(s) { + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.series == s) + return i; + } + return -1; + } + + function drawOverlay(plot, octx) { + + var options = plot.getOptions(); + + var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; + + octx.save(); + octx.translate(centerLeft, centerTop); + octx.scale(1, options.series.pie.tilt); + + for (var i = 0; i < highlights.length; ++i) { + drawHighlight(highlights[i].series); + } + + drawDonutHole(octx); + + octx.restore(); + + function drawHighlight(series) { + + if (series.angle <= 0 || isNaN(series.angle)) { + return; + } + + //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString(); + octx.fillStyle = "rgba(255, 255, 255, " + options.series.pie.highlight.opacity + ")"; // this is temporary until we have access to parseColor + octx.beginPath(); + if (Math.abs(series.angle - Math.PI * 2) > 0.000000001) { + octx.moveTo(0, 0); // Center of the pie + } + octx.arc(0, 0, radius, series.startAngle, series.startAngle + series.angle / 2, false); + octx.arc(0, 0, radius, series.startAngle + series.angle / 2, series.startAngle + series.angle, false); + octx.closePath(); + octx.fill(); + } + } + } // end init (plugin body) + + // define pie specific options and their default values + + var options = { + series: { + pie: { + show: false, + radius: "auto", // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value) + innerRadius: 0, /* for donut */ + startAngle: 3/2, + tilt: 1, + shadow: { + left: 5, // shadow left offset + top: 15, // shadow top offset + alpha: 0.02 // shadow alpha + }, + offset: { + top: 0, + left: "auto" + }, + stroke: { + color: "#fff", + width: 1 + }, + label: { + show: "auto", + formatter: function(label, slice) { + return "
" + label + "
" + Math.round(slice.percent) + "%
"; + }, // formatter function + radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value) + background: { + color: null, + opacity: 0 + }, + threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow) + }, + combine: { + threshold: -1, // percentage at which to combine little slices into one larger slice + color: null, // color to give the new slice (auto-generated if null) + label: "Other" // label to give the new slice + }, + highlight: { + //color: "#fff", // will add this functionality once parseColor is available + opacity: 0.5 + } + } + } + }; + + $.plot.plugins.push({ + init: init, + options: options, + name: "pie", + version: "1.1" + }); + +})(jQuery); diff --git a/emoncms/Lib/flot/jquery.flot.pie.min.js b/emoncms/Lib/flot/jquery.flot.pie.min.js new file mode 100644 index 0000000..3de8f44 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.pie.min.js @@ -0,0 +1,56 @@ +/* Flot plugin for rendering pie charts. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin assumes that each series has a single data value, and that each +value is a positive integer or zero. Negative numbers don't make sense for a +pie chart, and have unpredictable results. The values do NOT need to be +passed in as percentages; the plugin will calculate the total and per-slice +percentages internally. + +* Created by Brian Medendorp + +* Updated with contributions from btburnett3, Anthony Aragues and Xavi Ivars + +The plugin supports these options: + + series: { + pie: { + show: true/false + radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto' + innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect + startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result + tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show) + offset: { + top: integer value to move the pie up or down + left: integer value to move the pie left or right, or 'auto' + }, + stroke: { + color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF') + width: integer pixel width of the stroke + }, + label: { + show: true/false, or 'auto' + formatter: a user-defined function that modifies the text/style of the label text + radius: 0-1 for percentage of fullsize, or a specified pixel length + background: { + color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000') + opacity: 0-1 + }, + threshold: 0-1 for the percentage value at which to hide labels (if they're too small) + }, + combine: { + threshold: 0-1 for the percentage value at which to combine slices (if they're too small) + color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined + label: any text value of what the combined slice should be labeled + } + highlight: { + opacity: 0-1 + } + } + } + +More detail and specific examples can be found in the included HTML file. + +*/(function(e){function r(r){function p(t,n,r){l||(l=!0,s=t.getCanvas(),o=e(s).parent(),i=t.getOptions(),t.setData(d(t.getData())))}function d(t){var n=0,r=0,s=0,o=i.series.pie.combine.color,u=[];for(var a=0;ai.series.pie.combine.threshold)&&u.push({data:[[1,f]],color:t[a].color,label:t[a].label,angle:f*Math.PI*2/n,percent:f/(n/100)})}return s>1&&u.push({data:[[1,r]],color:o,label:i.series.pie.combine.label,angle:r*Math.PI*2/n,percent:r/(n/100)}),u}function v(r,s){function y(){c.clearRect(0,0,h,p),o.children().filter(".pieLabel, .pieLabelBackground").remove()}function b(){var e=i.series.pie.shadow.left,t=i.series.pie.shadow.top,n=10,r=i.series.pie.shadow.alpha,s=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius;if(s>=h/2-e||s*i.series.pie.tilt>=p/2-t||s<=n)return;c.save(),c.translate(e,t),c.globalAlpha=r,c.fillStyle="#000",c.translate(a,f),c.scale(1,i.series.pie.tilt);for(var o=1;o<=n;o++)c.beginPath(),c.arc(0,0,s,0,Math.PI*2,!1),c.fill(),s-=o;c.restore()}function w(){function l(e,t,i){if(e<=0||isNaN(e))return;i?c.fillStyle=t:(c.strokeStyle=t,c.lineJoin="round"),c.beginPath(),Math.abs(e-Math.PI*2)>1e-9&&c.moveTo(0,0),c.arc(0,0,n,r,r+e/2,!1),c.arc(0,0,n,r+e/2,r+e,!1),c.closePath(),r+=e,i?c.fill():c.stroke()}function d(){function l(t,n,s){if(t.data[0][1]==0)return!0;var u=i.legend.labelFormatter,l,c=i.series.pie.label.formatter;u?l=u(t.label,t):l=t.label,c&&(l=c(l,t));var d=(n+t.angle+n)/2,v=a+Math.round(Math.cos(d)*r),m=f+Math.round(Math.sin(d)*r)*i.series.pie.tilt,g=""+l+"";o.append(g);var y=o.children("#pieLabel"+s),b=m-y.height()/2,w=v-y.width()/2;y.css("top",b),y.css("left",w);if(0-b>0||0-w>0||p-(b+y.height())<0||h-(w+y.width())<0)return!1;if(i.series.pie.label.background.opacity!=0){var E=i.series.pie.label.background.color;E==null&&(E=t.color);var S="top:"+b+"px;left:"+w+"px;";e("
").css("opacity",i.series.pie.label.background.opacity).insertBefore(y)}return!0}var n=t,r=i.series.pie.label.radius>1?i.series.pie.label.radius:u*i.series.pie.label.radius;for(var s=0;s=i.series.pie.label.threshold*100&&!l(v[s],n,s))return!1;n+=v[s].angle}return!0}var t=Math.PI*i.series.pie.startAngle,n=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius;c.save(),c.translate(a,f),c.scale(1,i.series.pie.tilt),c.save();var r=t;for(var s=0;s0){c.save(),c.lineWidth=i.series.pie.stroke.width,r=t;for(var s=0;sh-u&&(a=h-u);var v=r.getData(),g=0;do g>0&&(u*=n),g+=1,y(),i.series.pie.tilt<=.8&&b();while(!w()&&g=t&&(y(),o.prepend("
Could not draw pie with labels contained inside canvas
")),r.setSeries&&r.insertLegend&&(r.setSeries(v),r.insertLegend())}function m(e){if(i.series.pie.innerRadius>0){e.save();var t=i.series.pie.innerRadius>1?i.series.pie.innerRadius:u*i.series.pie.innerRadius;e.globalCompositeOperation="destination-out",e.beginPath(),e.fillStyle=i.series.pie.stroke.color,e.arc(0,0,t,0,Math.PI*2,!1),e.fill(),e.closePath(),e.restore(),e.save(),e.beginPath(),e.strokeStyle=i.series.pie.stroke.color,e.arc(0,0,t,0,Math.PI*2,!1),e.stroke(),e.closePath(),e.restore()}}function g(e,t){for(var n=!1,r=-1,i=e.length,s=i-1;++r1?i.series.pie.radius:u*i.series.pie.radius,o,l;for(var h=0;h1e-9&&t.moveTo(0,0),t.arc(0,0,r,e.startAngle,e.startAngle+e.angle/2,!1),t.arc(0,0,r,e.startAngle+e.angle/2,e.startAngle+e.angle,!1),t.closePath(),t.fill()}var n=e.getOptions(),r=n.series.pie.radius>1?n.series.pie.radius:u*n.series.pie.radius;t.save(),t.translate(a,f),t.scale(1,n.series.pie.tilt);for(var i=0;i1?t.series.pie.tilt=1:t.series.pie.tilt<0&&(t.series.pie.tilt=0))}),r.hooks.bindEvents.push(function(e,t){var n=e.getOptions();n.series.pie.show&&(n.grid.hoverable&&t.unbind("mousemove").mousemove(b),n.grid.clickable&&t.unbind("click").click(w))}),r.hooks.processDatapoints.push(function(e,t,n,r){var i=e.getOptions();i.series.pie.show&&p(e,t,n,r)}),r.hooks.drawOverlay.push(function(e,t){var n=e.getOptions();n.series.pie.show&&N(e,t)}),r.hooks.draw.push(function(e,t){var n=e.getOptions();n.series.pie.show&&v(e,t)})}var t=10,n=.95,i={series:{pie:{show:!1,radius:"auto",innerRadius:0,startAngle:1.5,tilt:1,shadow:{left:5,top:15,alpha:.02},offset:{top:0,left:"auto"},stroke:{color:"#fff",width:1},label:{show:"auto",formatter:function(e,t){return"
"+e+"
"+Math.round(t.percent)+"%
"},radius:1,background:{color:null,opacity:0},threshold:0},combine:{threshold:-1,color:null,label:"Other"},highlight:{opacity:.5}}}};e.plot.plugins.push({init:r,options:i,name:"pie",version:"1.1"})})(jQuery); \ No newline at end of file diff --git a/emoncms/Lib/flot/jquery.flot.resize.js b/emoncms/Lib/flot/jquery.flot.resize.js new file mode 100644 index 0000000..6b2c5d4 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.resize.js @@ -0,0 +1,60 @@ +/* Flot plugin for automatically redrawing plots as the placeholder resizes. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +It works by listening for changes on the placeholder div (through the jQuery +resize event plugin) - if the size changes, it will redraw the plot. + +There are no options. If you need to disable the plugin for some plots, you +can just fix the size of their placeholders. + +*/ + +/* Inline dependency: + * jQuery resize event - v1.1 - 3/14/2010 + * http://benalman.com/projects/jquery-resize-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ + +(function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this); + +(function ($) { + var options = { }; // no options + + function init(plot) { + function onResize() { + var placeholder = plot.getPlaceholder(); + + // somebody might have hidden us and we can't plot + // when we don't have the dimensions + if (placeholder.width() == 0 || placeholder.height() == 0) + return; + + plot.resize(); + plot.setupGrid(); + plot.draw(); + } + + function bindEvents(plot, eventHolder) { + plot.getPlaceholder().resize(onResize); + } + + function shutdown(plot, eventHolder) { + plot.getPlaceholder().unbind("resize", onResize); + } + + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'resize', + version: '1.0' + }); +})(jQuery); diff --git a/emoncms/Lib/flot/jquery.flot.resize.min.js b/emoncms/Lib/flot/jquery.flot.resize.min.js new file mode 100644 index 0000000..b2ddec1 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.resize.min.js @@ -0,0 +1,19 @@ +/* Flot plugin for automatically redrawing plots as the placeholder resizes. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +It works by listening for changes on the placeholder div (through the jQuery +resize event plugin) - if the size changes, it will redraw the plot. + +There are no options. If you need to disable the plugin for some plots, you +can just fix the size of their placeholders. + +*//* Inline dependency: + * jQuery resize event - v1.1 - 3/14/2010 + * http://benalman.com/projects/jquery-resize-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */(function(e,t,n){function c(){s=t[o](function(){r.each(function(){var t=e(this),n=t.width(),r=t.height(),i=e.data(this,a);(n!==i.w||r!==i.h)&&t.trigger(u,[i.w=n,i.h=r])}),c()},i[f])}var r=e([]),i=e.resize=e.extend(e.resize,{}),s,o="setTimeout",u="resize",a=u+"-special-event",f="delay",l="throttleWindow";i[f]=250,i[l]=!0,e.event.special[u]={setup:function(){if(!i[l]&&this[o])return!1;var t=e(this);r=r.add(t),e.data(this,a,{w:t.width(),h:t.height()}),r.length===1&&c()},teardown:function(){if(!i[l]&&this[o])return!1;var t=e(this);r=r.not(t),t.removeData(a),r.length||clearTimeout(s)},add:function(t){function s(t,i,s){var o=e(this),u=e.data(this,a);u.w=i!==n?i:o.width(),u.h=s!==n?s:o.height(),r.apply(this,arguments)}if(!i[l]&&this[o])return!1;var r;if(e.isFunction(t))return r=t,s;r=t.handler,t.handler=s}}})(jQuery,this),function(e){function n(e){function t(){var t=e.getPlaceholder();if(t.width()==0||t.height()==0)return;e.resize(),e.setupGrid(),e.draw()}function n(e,n){e.getPlaceholder().resize(t)}function r(e,n){e.getPlaceholder().unbind("resize",t)}e.hooks.bindEvents.push(n),e.hooks.shutdown.push(r)}var t={};e.plot.plugins.push({init:n,options:t,name:"resize",version:"1.0"})}(jQuery); \ No newline at end of file diff --git a/emoncms/Lib/flot/jquery.flot.selection.js b/emoncms/Lib/flot/jquery.flot.selection.js new file mode 100644 index 0000000..f8fa668 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.selection.js @@ -0,0 +1,360 @@ +/* Flot plugin for selecting regions of a plot. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + +selection: { + mode: null or "x" or "y" or "xy", + color: color, + shape: "round" or "miter" or "bevel", + minSize: number of pixels +} + +Selection support is enabled by setting the mode to one of "x", "y" or "xy". +In "x" mode, the user will only be able to specify the x range, similarly for +"y" mode. For "xy", the selection becomes a rectangle where both ranges can be +specified. "color" is color of the selection (if you need to change the color +later on, you can get to it with plot.getOptions().selection.color). "shape" +is the shape of the corners of the selection. + +"minSize" is the minimum size a selection can be in pixels. This value can +be customized to determine the smallest size a selection can be and still +have the selection rectangle be displayed. When customizing this value, the +fact that it refers to pixels, not axis units must be taken into account. +Thus, for example, if there is a bar graph in time mode with BarWidth set to 1 +minute, setting "minSize" to 1 will not make the minimum selection size 1 +minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent +"plotunselected" events from being fired when the user clicks the mouse without +dragging. + +When selection support is enabled, a "plotselected" event will be emitted on +the DOM element you passed into the plot function. The event handler gets a +parameter with the ranges selected on the axes, like this: + + placeholder.bind( "plotselected", function( event, ranges ) { + alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to) + // similar for yaxis - with multiple axes, the extra ones are in + // x2axis, x3axis, ... + }); + +The "plotselected" event is only fired when the user has finished making the +selection. A "plotselecting" event is fired during the process with the same +parameters as the "plotselected" event, in case you want to know what's +happening while it's happening, + +A "plotunselected" event with no arguments is emitted when the user clicks the +mouse to remove the selection. As stated above, setting "minSize" to 0 will +destroy this behavior. + +The plugin allso adds the following methods to the plot object: + +- setSelection( ranges, preventEvent ) + + Set the selection rectangle. The passed in ranges is on the same form as + returned in the "plotselected" event. If the selection mode is "x", you + should put in either an xaxis range, if the mode is "y" you need to put in + an yaxis range and both xaxis and yaxis if the selection mode is "xy", like + this: + + setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } }); + + setSelection will trigger the "plotselected" event when called. If you don't + want that to happen, e.g. if you're inside a "plotselected" handler, pass + true as the second parameter. If you are using multiple axes, you can + specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of + xaxis, the plugin picks the first one it sees. + +- clearSelection( preventEvent ) + + Clear the selection rectangle. Pass in true to avoid getting a + "plotunselected" event. + +- getSelection() + + Returns the current selection in the same format as the "plotselected" + event. If there's currently no selection, the function returns null. + +*/ + +(function ($) { + function init(plot) { + var selection = { + first: { x: -1, y: -1}, second: { x: -1, y: -1}, + show: false, + active: false + }; + + // FIXME: The drag handling implemented here should be + // abstracted out, there's some similar code from a library in + // the navigation plugin, this should be massaged a bit to fit + // the Flot cases here better and reused. Doing this would + // make this plugin much slimmer. + var savedhandlers = {}; + + var mouseUpHandler = null; + + function onMouseMove(e) { + if (selection.active) { + updateSelection(e); + + plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]); + } + } + + function onMouseDown(e) { + if (e.which != 1) // only accept left-click + return; + + // cancel out any text selections + document.body.focus(); + + // prevent text selection and drag in old-school browsers + if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) { + savedhandlers.onselectstart = document.onselectstart; + document.onselectstart = function () { return false; }; + } + if (document.ondrag !== undefined && savedhandlers.ondrag == null) { + savedhandlers.ondrag = document.ondrag; + document.ondrag = function () { return false; }; + } + + setSelectionPos(selection.first, e); + + selection.active = true; + + // this is a bit silly, but we have to use a closure to be + // able to whack the same handler again + mouseUpHandler = function (e) { onMouseUp(e); }; + + $(document).one("mouseup", mouseUpHandler); + } + + function onMouseUp(e) { + mouseUpHandler = null; + + // revert drag stuff for old-school browsers + if (document.onselectstart !== undefined) + document.onselectstart = savedhandlers.onselectstart; + if (document.ondrag !== undefined) + document.ondrag = savedhandlers.ondrag; + + // no more dragging + selection.active = false; + updateSelection(e); + + if (selectionIsSane()) + triggerSelectedEvent(); + else { + // this counts as a clear + plot.getPlaceholder().trigger("plotunselected", [ ]); + plot.getPlaceholder().trigger("plotselecting", [ null ]); + } + + return false; + } + + function getSelection() { + if (!selectionIsSane()) + return null; + + if (!selection.show) return null; + + var r = {}, c1 = selection.first, c2 = selection.second; + $.each(plot.getAxes(), function (name, axis) { + if (axis.used) { + var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]); + r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) }; + } + }); + return r; + } + + function triggerSelectedEvent() { + var r = getSelection(); + + plot.getPlaceholder().trigger("plotselected", [ r ]); + + // backwards-compat stuff, to be removed in future + if (r.xaxis && r.yaxis) + plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]); + } + + function clamp(min, value, max) { + return value < min ? min: (value > max ? max: value); + } + + function setSelectionPos(pos, e) { + var o = plot.getOptions(); + var offset = plot.getPlaceholder().offset(); + var plotOffset = plot.getPlotOffset(); + pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width()); + pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height()); + + if (o.selection.mode == "y") + pos.x = pos == selection.first ? 0 : plot.width(); + + if (o.selection.mode == "x") + pos.y = pos == selection.first ? 0 : plot.height(); + } + + function updateSelection(pos) { + if (pos.pageX == null) + return; + + setSelectionPos(selection.second, pos); + if (selectionIsSane()) { + selection.show = true; + plot.triggerRedrawOverlay(); + } + else + clearSelection(true); + } + + function clearSelection(preventEvent) { + if (selection.show) { + selection.show = false; + plot.triggerRedrawOverlay(); + if (!preventEvent) + plot.getPlaceholder().trigger("plotunselected", [ ]); + } + } + + // function taken from markings support in Flot + function extractRange(ranges, coord) { + var axis, from, to, key, axes = plot.getAxes(); + + for (var k in axes) { + axis = axes[k]; + if (axis.direction == coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n == 1) + key = coord + "axis"; // support x1axis as xaxis + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { from: from, to: to, axis: axis }; + } + + function setSelection(ranges, preventEvent) { + var axis, range, o = plot.getOptions(); + + if (o.selection.mode == "y") { + selection.first.x = 0; + selection.second.x = plot.width(); + } + else { + range = extractRange(ranges, "x"); + + selection.first.x = range.axis.p2c(range.from); + selection.second.x = range.axis.p2c(range.to); + } + + if (o.selection.mode == "x") { + selection.first.y = 0; + selection.second.y = plot.height(); + } + else { + range = extractRange(ranges, "y"); + + selection.first.y = range.axis.p2c(range.from); + selection.second.y = range.axis.p2c(range.to); + } + + selection.show = true; + plot.triggerRedrawOverlay(); + if (!preventEvent && selectionIsSane()) + triggerSelectedEvent(); + } + + function selectionIsSane() { + var minSize = plot.getOptions().selection.minSize; + return Math.abs(selection.second.x - selection.first.x) >= minSize && + Math.abs(selection.second.y - selection.first.y) >= minSize; + } + + plot.clearSelection = clearSelection; + plot.setSelection = setSelection; + plot.getSelection = getSelection; + + plot.hooks.bindEvents.push(function(plot, eventHolder) { + var o = plot.getOptions(); + if (o.selection.mode != null) { + eventHolder.mousemove(onMouseMove); + eventHolder.mousedown(onMouseDown); + } + }); + + + plot.hooks.drawOverlay.push(function (plot, ctx) { + // draw selection + if (selection.show && selectionIsSane()) { + var plotOffset = plot.getPlotOffset(); + var o = plot.getOptions(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var c = $.color.parse(o.selection.color); + + ctx.strokeStyle = c.scale('a', 0.8).toString(); + ctx.lineWidth = 1; + ctx.lineJoin = o.selection.shape; + ctx.fillStyle = c.scale('a', 0.4).toString(); + + var x = Math.min(selection.first.x, selection.second.x) + 0.5, + y = Math.min(selection.first.y, selection.second.y) + 0.5, + w = Math.abs(selection.second.x - selection.first.x) - 1, + h = Math.abs(selection.second.y - selection.first.y) - 1; + + ctx.fillRect(x, y, w, h); + ctx.strokeRect(x, y, w, h); + + ctx.restore(); + } + }); + + plot.hooks.shutdown.push(function (plot, eventHolder) { + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mousedown", onMouseDown); + + if (mouseUpHandler) + $(document).unbind("mouseup", mouseUpHandler); + }); + + } + + $.plot.plugins.push({ + init: init, + options: { + selection: { + mode: null, // one of null, "x", "y" or "xy" + color: "#e8cfac", + shape: "round", // one of "round", "miter", or "bevel" + minSize: 5 // minimum number of pixels + } + }, + name: 'selection', + version: '1.1' + }); +})(jQuery); diff --git a/emoncms/Lib/flot/jquery.flot.selection.min.js b/emoncms/Lib/flot/jquery.flot.selection.min.js new file mode 100644 index 0000000..bbfb975 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.selection.min.js @@ -0,0 +1,79 @@ +/* Flot plugin for selecting regions of a plot. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + +selection: { + mode: null or "x" or "y" or "xy", + color: color, + shape: "round" or "miter" or "bevel", + minSize: number of pixels +} + +Selection support is enabled by setting the mode to one of "x", "y" or "xy". +In "x" mode, the user will only be able to specify the x range, similarly for +"y" mode. For "xy", the selection becomes a rectangle where both ranges can be +specified. "color" is color of the selection (if you need to change the color +later on, you can get to it with plot.getOptions().selection.color). "shape" +is the shape of the corners of the selection. + +"minSize" is the minimum size a selection can be in pixels. This value can +be customized to determine the smallest size a selection can be and still +have the selection rectangle be displayed. When customizing this value, the +fact that it refers to pixels, not axis units must be taken into account. +Thus, for example, if there is a bar graph in time mode with BarWidth set to 1 +minute, setting "minSize" to 1 will not make the minimum selection size 1 +minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent +"plotunselected" events from being fired when the user clicks the mouse without +dragging. + +When selection support is enabled, a "plotselected" event will be emitted on +the DOM element you passed into the plot function. The event handler gets a +parameter with the ranges selected on the axes, like this: + + placeholder.bind( "plotselected", function( event, ranges ) { + alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to) + // similar for yaxis - with multiple axes, the extra ones are in + // x2axis, x3axis, ... + }); + +The "plotselected" event is only fired when the user has finished making the +selection. A "plotselecting" event is fired during the process with the same +parameters as the "plotselected" event, in case you want to know what's +happening while it's happening, + +A "plotunselected" event with no arguments is emitted when the user clicks the +mouse to remove the selection. As stated above, setting "minSize" to 0 will +destroy this behavior. + +The plugin allso adds the following methods to the plot object: + +- setSelection( ranges, preventEvent ) + + Set the selection rectangle. The passed in ranges is on the same form as + returned in the "plotselected" event. If the selection mode is "x", you + should put in either an xaxis range, if the mode is "y" you need to put in + an yaxis range and both xaxis and yaxis if the selection mode is "xy", like + this: + + setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } }); + + setSelection will trigger the "plotselected" event when called. If you don't + want that to happen, e.g. if you're inside a "plotselected" handler, pass + true as the second parameter. If you are using multiple axes, you can + specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of + xaxis, the plugin picks the first one it sees. + +- clearSelection( preventEvent ) + + Clear the selection rectangle. Pass in true to avoid getting a + "plotunselected" event. + +- getSelection() + + Returns the current selection in the same format as the "plotselected" + event. If there's currently no selection, the function returns null. + +*/(function(e){function t(t){function s(e){n.active&&(h(e),t.getPlaceholder().trigger("plotselecting",[a()]))}function o(t){if(t.which!=1)return;document.body.focus(),document.onselectstart!==undefined&&r.onselectstart==null&&(r.onselectstart=document.onselectstart,document.onselectstart=function(){return!1}),document.ondrag!==undefined&&r.ondrag==null&&(r.ondrag=document.ondrag,document.ondrag=function(){return!1}),c(n.first,t),n.active=!0,i=function(e){u(e)},e(document).one("mouseup",i)}function u(e){return i=null,document.onselectstart!==undefined&&(document.onselectstart=r.onselectstart),document.ondrag!==undefined&&(document.ondrag=r.ondrag),n.active=!1,h(e),m()?f():(t.getPlaceholder().trigger("plotunselected",[]),t.getPlaceholder().trigger("plotselecting",[null])),!1}function a(){if(!m())return null;if(!n.show)return null;var r={},i=n.first,s=n.second;return e.each(t.getAxes(),function(e,t){if(t.used){var n=t.c2p(i[t.direction]),o=t.c2p(s[t.direction]);r[e]={from:Math.min(n,o),to:Math.max(n,o)}}}),r}function f(){var e=a();t.getPlaceholder().trigger("plotselected",[e]),e.xaxis&&e.yaxis&&t.getPlaceholder().trigger("selected",[{x1:e.xaxis.from,y1:e.yaxis.from,x2:e.xaxis.to,y2:e.yaxis.to}])}function l(e,t,n){return tn?n:t}function c(e,r){var i=t.getOptions(),s=t.getPlaceholder().offset(),o=t.getPlotOffset();e.x=l(0,r.pageX-s.left-o.left,t.width()),e.y=l(0,r.pageY-s.top-o.top,t.height()),i.selection.mode=="y"&&(e.x=e==n.first?0:t.width()),i.selection.mode=="x"&&(e.y=e==n.first?0:t.height())}function h(e){if(e.pageX==null)return;c(n.second,e),m()?(n.show=!0,t.triggerRedrawOverlay()):p(!0)}function p(e){n.show&&(n.show=!1,t.triggerRedrawOverlay(),e||t.getPlaceholder().trigger("plotunselected",[]))}function d(e,n){var r,i,s,o,u=t.getAxes();for(var a in u){r=u[a];if(r.direction==n){o=n+r.n+"axis",!e[o]&&r.n==1&&(o=n+"axis");if(e[o]){i=e[o].from,s=e[o].to;break}}}e[o]||(r=n=="x"?t.getXAxes()[0]:t.getYAxes()[0],i=e[n+"1"],s=e[n+"2"]);if(i!=null&&s!=null&&i>s){var f=i;i=s,s=f}return{from:i,to:s,axis:r}}function v(e,r){var i,s,o=t.getOptions();o.selection.mode=="y"?(n.first.x=0,n.second.x=t.width()):(s=d(e,"x"),n.first.x=s.axis.p2c(s.from),n.second.x=s.axis.p2c(s.to)),o.selection.mode=="x"?(n.first.y=0,n.second.y=t.height()):(s=d(e,"y"),n.first.y=s.axis.p2c(s.from),n.second.y=s.axis.p2c(s.to)),n.show=!0,t.triggerRedrawOverlay(),!r&&m()&&f()}function m(){var e=t.getOptions().selection.minSize;return Math.abs(n.second.x-n.first.x)>=e&&Math.abs(n.second.y-n.first.y)>=e}var n={first:{x:-1,y:-1},second:{x:-1,y:-1},show:!1,active:!1},r={},i=null;t.clearSelection=p,t.setSelection=v,t.getSelection=a,t.hooks.bindEvents.push(function(e,t){var n=e.getOptions();n.selection.mode!=null&&(t.mousemove(s),t.mousedown(o))}),t.hooks.drawOverlay.push(function(t,r){if(n.show&&m()){var i=t.getPlotOffset(),s=t.getOptions();r.save(),r.translate(i.left,i.top);var o=e.color.parse(s.selection.color);r.strokeStyle=o.scale("a",.8).toString(),r.lineWidth=1,r.lineJoin=s.selection.shape,r.fillStyle=o.scale("a",.4).toString();var u=Math.min(n.first.x,n.second.x)+.5,a=Math.min(n.first.y,n.second.y)+.5,f=Math.abs(n.second.x-n.first.x)-1,l=Math.abs(n.second.y-n.first.y)-1;r.fillRect(u,a,f,l),r.strokeRect(u,a,f,l),r.restore()}}),t.hooks.shutdown.push(function(t,n){n.unbind("mousemove",s),n.unbind("mousedown",o),i&&e(document).unbind("mouseup",i)})}e.plot.plugins.push({init:t,options:{selection:{mode:null,color:"#e8cfac",shape:"round",minSize:5}},name:"selection",version:"1.1"})})(jQuery); \ No newline at end of file diff --git a/emoncms/Lib/flot/jquery.flot.stack.js b/emoncms/Lib/flot/jquery.flot.stack.js new file mode 100644 index 0000000..c01de67 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.stack.js @@ -0,0 +1,188 @@ +/* Flot plugin for stacking data sets rather than overlyaing them. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin assumes the data is sorted on x (or y if stacking horizontally). +For line charts, it is assumed that if a line has an undefined gap (from a +null point), then the line above it should have the same gap - insert zeros +instead of "null" if you want another behaviour. This also holds for the start +and end of the chart. Note that stacking a mix of positive and negative values +in most instances doesn't make sense (so it looks weird). + +Two or more series are stacked when their "stack" attribute is set to the same +key (which can be any number or string or just "true"). To specify the default +stack, you can set the stack option like this: + + series: { + stack: null/false, true, or a key (number/string) + } + +You can also specify it for a single series, like this: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + stack: true + }]) + +The stacking order is determined by the order of the data series in the array +(later series end up on top of the previous). + +Internally, the plugin modifies the datapoints in each series, adding an +offset to the y value. For line series, extra data points are inserted through +interpolation. If there's a second y value, it's also adjusted (e.g for bar +charts or filled areas). + +*/ + +(function ($) { + var options = { + series: { stack: null } // or number/string + }; + + function init(plot) { + function findMatchingSeries(s, allseries) { + var res = null; + for (var i = 0; i < allseries.length; ++i) { + if (s == allseries[i]) + break; + + if (allseries[i].stack == s.stack) + res = allseries[i]; + } + + return res; + } + + function stackData(plot, s, datapoints) { + if (s.stack == null || s.stack === false) + return; + + var other = findMatchingSeries(s, plot.getData()); + if (!other) + return; + + var ps = datapoints.pointsize, + points = datapoints.points, + otherps = other.datapoints.pointsize, + otherpoints = other.datapoints.points, + newpoints = [], + px, py, intery, qx, qy, bottom, + withlines = s.lines.show, + horizontal = s.bars.horizontal, + withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y), + withsteps = withlines && s.lines.steps, + fromgap = true, + keyOffset = horizontal ? 1 : 0, + accumulateOffset = horizontal ? 0 : 1, + i = 0, j = 0, l, m; + + while (true) { + if (i >= points.length) + break; + + l = newpoints.length; + + if (points[i] == null) { + // copy gaps + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + i += ps; + } + else if (j >= otherpoints.length) { + // for lines, we can't use the rest of the points + if (!withlines) { + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + } + i += ps; + } + else if (otherpoints[j] == null) { + // oops, got a gap + for (m = 0; m < ps; ++m) + newpoints.push(null); + fromgap = true; + j += otherps; + } + else { + // cases where we actually got two points + px = points[i + keyOffset]; + py = points[i + accumulateOffset]; + qx = otherpoints[j + keyOffset]; + qy = otherpoints[j + accumulateOffset]; + bottom = 0; + + if (px == qx) { + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + + newpoints[l + accumulateOffset] += qy; + bottom = qy; + + i += ps; + j += otherps; + } + else if (px > qx) { + // we got past point below, might need to + // insert interpolated extra point + if (withlines && i > 0 && points[i - ps] != null) { + intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px); + newpoints.push(qx); + newpoints.push(intery + qy); + for (m = 2; m < ps; ++m) + newpoints.push(points[i + m]); + bottom = qy; + } + + j += otherps; + } + else { // px < qx + if (fromgap && withlines) { + // if we come from a gap, we just skip this point + i += ps; + continue; + } + + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + + // we might be able to interpolate a point below, + // this can give us a better y + if (withlines && j > 0 && otherpoints[j - otherps] != null) + bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx); + + newpoints[l + accumulateOffset] += bottom; + + i += ps; + } + + fromgap = false; + + if (l != newpoints.length && withbottom) + newpoints[l + 2] += bottom; + } + + // maintain the line steps invariant + if (withsteps && l != newpoints.length && l > 0 + && newpoints[l] != null + && newpoints[l] != newpoints[l - ps] + && newpoints[l + 1] != newpoints[l - ps + 1]) { + for (m = 0; m < ps; ++m) + newpoints[l + ps + m] = newpoints[l + m]; + newpoints[l + 1] = newpoints[l - ps + 1]; + } + } + + datapoints.points = newpoints; + } + + plot.hooks.processDatapoints.push(stackData); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'stack', + version: '1.2' + }); +})(jQuery); diff --git a/emoncms/Lib/flot/jquery.flot.stack.min.js b/emoncms/Lib/flot/jquery.flot.stack.min.js new file mode 100644 index 0000000..14e9931 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.stack.min.js @@ -0,0 +1,36 @@ +/* Flot plugin for stacking data sets rather than overlyaing them. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin assumes the data is sorted on x (or y if stacking horizontally). +For line charts, it is assumed that if a line has an undefined gap (from a +null point), then the line above it should have the same gap - insert zeros +instead of "null" if you want another behaviour. This also holds for the start +and end of the chart. Note that stacking a mix of positive and negative values +in most instances doesn't make sense (so it looks weird). + +Two or more series are stacked when their "stack" attribute is set to the same +key (which can be any number or string or just "true"). To specify the default +stack, you can set the stack option like this: + + series: { + stack: null/false, true, or a key (number/string) + } + +You can also specify it for a single series, like this: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + stack: true + }]) + +The stacking order is determined by the order of the data series in the array +(later series end up on top of the previous). + +Internally, the plugin modifies the datapoints in each series, adding an +offset to the y value. For line series, extra data points are inserted through +interpolation. If there's a second y value, it's also adjusted (e.g for bar +charts or filled areas). + +*/(function(e){function n(e){function t(e,t){var n=null;for(var r=0;r2&&(g?r.format[2].x:r.format[2].y),b=m&&n.lines.steps,w=!0,E=g?1:0,S=g?0:1,x=0,T=0,N,C;for(;;){if(x>=o.length)break;N=f.length;if(o[x]==null){for(C=0;C=a.length){if(!m)for(C=0;Cp){if(m&&x>0&&o[x-s]!=null){h=c+(o[x-s+S]-c)*(p-l)/(o[x-s+E]-l),f.push(p),f.push(h+d);for(C=2;C0&&a[T-u]!=null&&(v=d+(a[T-u+S]-d)*(l-p)/(a[T-u+E]-p)),f[N+S]+=v,x+=s}w=!1,N!=f.length&&y&&(f[N+2]+=v)}if(b&&N!=f.length&&N>0&&f[N]!=null&&f[N]!=f[N-s]&&f[N+1]!=f[N-s+1]){for(C=0;C s = r * sqrt(pi)/2 + var size = radius * Math.sqrt(Math.PI) / 2; + ctx.rect(x - size, y - size, size + size, size + size); + }, + diamond: function (ctx, x, y, radius, shadow) { + // pi * r^2 = 2s^2 => s = r * sqrt(pi/2) + var size = radius * Math.sqrt(Math.PI / 2); + ctx.moveTo(x - size, y); + ctx.lineTo(x, y - size); + ctx.lineTo(x + size, y); + ctx.lineTo(x, y + size); + ctx.lineTo(x - size, y); + }, + triangle: function (ctx, x, y, radius, shadow) { + // pi * r^2 = 1/2 * s^2 * sin (pi / 3) => s = r * sqrt(2 * pi / sin(pi / 3)) + var size = radius * Math.sqrt(2 * Math.PI / Math.sin(Math.PI / 3)); + var height = size * Math.sin(Math.PI / 3); + ctx.moveTo(x - size/2, y + height/2); + ctx.lineTo(x + size/2, y + height/2); + if (!shadow) { + ctx.lineTo(x, y - height/2); + ctx.lineTo(x - size/2, y + height/2); + } + }, + cross: function (ctx, x, y, radius, shadow) { + // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2 + var size = radius * Math.sqrt(Math.PI) / 2; + ctx.moveTo(x - size, y - size); + ctx.lineTo(x + size, y + size); + ctx.moveTo(x - size, y + size); + ctx.lineTo(x + size, y - size); + } + }; + + var s = series.points.symbol; + if (handlers[s]) + series.points.symbol = handlers[s]; + } + + function init(plot) { + plot.hooks.processDatapoints.push(processRawData); + } + + $.plot.plugins.push({ + init: init, + name: 'symbols', + version: '1.0' + }); +})(jQuery); diff --git a/emoncms/Lib/flot/jquery.flot.symbol.min.js b/emoncms/Lib/flot/jquery.flot.symbol.min.js new file mode 100644 index 0000000..b78ea2e --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.symbol.min.js @@ -0,0 +1,14 @@ +/* Flot plugin that adds some extra symbols for plotting points. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The symbols are accessed as strings through the standard symbol options: + + series: { + points: { + symbol: "square" // or "diamond", "triangle", "cross" + } + } + +*/(function(e){function t(e,t,n){var r={square:function(e,t,n,r,i){var s=r*Math.sqrt(Math.PI)/2;e.rect(t-s,n-s,s+s,s+s)},diamond:function(e,t,n,r,i){var s=r*Math.sqrt(Math.PI/2);e.moveTo(t-s,n),e.lineTo(t,n-s),e.lineTo(t+s,n),e.lineTo(t,n+s),e.lineTo(t-s,n)},triangle:function(e,t,n,r,i){var s=r*Math.sqrt(2*Math.PI/Math.sin(Math.PI/3)),o=s*Math.sin(Math.PI/3);e.moveTo(t-s/2,n+o/2),e.lineTo(t+s/2,n+o/2),i||(e.lineTo(t,n-o/2),e.lineTo(t-s/2,n+o/2))},cross:function(e,t,n,r,i){var s=r*Math.sqrt(Math.PI)/2;e.moveTo(t-s,n-s),e.lineTo(t+s,n+s),e.moveTo(t-s,n+s),e.lineTo(t+s,n-s)}},i=t.points.symbol;r[i]&&(t.points.symbol=r[i])}function n(e){e.hooks.processDatapoints.push(t)}e.plot.plugins.push({init:n,name:"symbols",version:"1.0"})})(jQuery); \ No newline at end of file diff --git a/emoncms/Lib/flot/jquery.flot.threshold.js b/emoncms/Lib/flot/jquery.flot.threshold.js new file mode 100644 index 0000000..2f6e635 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.threshold.js @@ -0,0 +1,142 @@ +/* Flot plugin for thresholding data. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + + series: { + threshold: { + below: number + color: colorspec + } + } + +It can also be applied to a single series, like this: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + threshold: { ... } + }]) + +An array can be passed for multiple thresholding, like this: + + threshold: [{ + below: number1 + color: color1 + },{ + below: number2 + color: color2 + }] + +These multiple threshold objects can be passed in any order since they are +sorted by the processing function. + +The data points below "below" are drawn with the specified color. This makes +it easy to mark points below 0, e.g. for budget data. + +Internally, the plugin works by splitting the data into two series, above and +below the threshold. The extra series below the threshold will have its label +cleared and the special "originSeries" attribute set to the original series. +You may need to check for this in hover events. + +*/ + +(function ($) { + var options = { + series: { threshold: null } // or { below: number, color: color spec} + }; + + function init(plot) { + function thresholdData(plot, s, datapoints, below, color) { + var ps = datapoints.pointsize, i, x, y, p, prevp, + thresholded = $.extend({}, s); // note: shallow copy + + thresholded.datapoints = { points: [], pointsize: ps, format: datapoints.format }; + thresholded.label = null; + thresholded.color = color; + thresholded.threshold = null; + thresholded.originSeries = s; + thresholded.data = []; + + var origpoints = datapoints.points, + addCrossingPoints = s.lines.show; + + var threspoints = []; + var newpoints = []; + var m; + + for (i = 0; i < origpoints.length; i += ps) { + x = origpoints[i]; + y = origpoints[i + 1]; + + prevp = p; + if (y < below) + p = threspoints; + else + p = newpoints; + + if (addCrossingPoints && prevp != p && x != null + && i > 0 && origpoints[i - ps] != null) { + var interx = x + (below - y) * (x - origpoints[i - ps]) / (y - origpoints[i - ps + 1]); + prevp.push(interx); + prevp.push(below); + for (m = 2; m < ps; ++m) + prevp.push(origpoints[i + m]); + + p.push(null); // start new segment + p.push(null); + for (m = 2; m < ps; ++m) + p.push(origpoints[i + m]); + p.push(interx); + p.push(below); + for (m = 2; m < ps; ++m) + p.push(origpoints[i + m]); + } + + p.push(x); + p.push(y); + for (m = 2; m < ps; ++m) + p.push(origpoints[i + m]); + } + + datapoints.points = newpoints; + thresholded.datapoints.points = threspoints; + + if (thresholded.datapoints.points.length > 0) { + var origIndex = $.inArray(s, plot.getData()); + // Insert newly-generated series right after original one (to prevent it from becoming top-most) + plot.getData().splice(origIndex + 1, 0, thresholded); + } + + // FIXME: there are probably some edge cases left in bars + } + + function processThresholds(plot, s, datapoints) { + if (!s.threshold) + return; + + if (s.threshold instanceof Array) { + s.threshold.sort(function(a, b) { + return a.below - b.below; + }); + + $(s.threshold).each(function(i, th) { + thresholdData(plot, s, datapoints, th.below, th.color); + }); + } + else { + thresholdData(plot, s, datapoints, s.threshold.below, s.threshold.color); + } + } + + plot.hooks.processDatapoints.push(processThresholds); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'threshold', + version: '1.2' + }); +})(jQuery); diff --git a/emoncms/Lib/flot/jquery.flot.threshold.min.js b/emoncms/Lib/flot/jquery.flot.threshold.min.js new file mode 100644 index 0000000..1ca88a6 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.threshold.min.js @@ -0,0 +1,43 @@ +/* Flot plugin for thresholding data. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + + series: { + threshold: { + below: number + color: colorspec + } + } + +It can also be applied to a single series, like this: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + threshold: { ... } + }]) + +An array can be passed for multiple thresholding, like this: + + threshold: [{ + below: number1 + color: color1 + },{ + below: number2 + color: color2 + }] + +These multiple threshold objects can be passed in any order since they are +sorted by the processing function. + +The data points below "below" are drawn with the specified color. This makes +it easy to mark points below 0, e.g. for budget data. + +Internally, the plugin works by splitting the data into two series, above and +below the threshold. The extra series below the threshold will have its label +cleared and the special "originSeries" attribute set to the original series. +You may need to check for this in hover events. + +*/(function(e){function n(t){function n(t,n,r,i,s){var o=r.pointsize,u,a,f,l,c,h=e.extend({},n);h.datapoints={points:[],pointsize:o,format:r.format},h.label=null,h.color=s,h.threshold=null,h.originSeries=n,h.data=[];var p=r.points,d=n.lines.show,v=[],m=[],g;for(u=0;u0&&p[u-o]!=null){var y=a+(i-f)*(a-p[u-o])/(f-p[u-o+1]);c.push(y),c.push(i);for(g=2;g0){var b=e.inArray(n,t.getData());t.getData().splice(b+1,0,h)}}function r(t,r,i){if(!r.threshold)return;r.threshold instanceof Array?(r.threshold.sort(function(e,t){return e.below-t.below}),e(r.threshold).each(function(e,o){n(t,r,i,o.below,o.color)})):n(t,r,i,r.threshold.below,r.threshold.color)}t.hooks.processDatapoints.push(r)}var t={series:{threshold:null}};e.plot.plugins.push({init:n,options:t,name:"threshold",version:"1.2"})})(jQuery); \ No newline at end of file diff --git a/emoncms/Lib/flot/jquery.flot.time.js b/emoncms/Lib/flot/jquery.flot.time.js new file mode 100644 index 0000000..15f5281 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.time.js @@ -0,0 +1,431 @@ +/* Pretty handling of time axes. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +Set axis.mode to "time" to enable. See the section "Time series data" in +API.txt for details. + +*/ + +(function($) { + + var options = { + xaxis: { + timezone: null, // "browser" for local to the client or timezone for timezone-js + timeformat: null, // format string to use + twelveHourClock: false, // 12 or 24 time in time mode + monthNames: null // list of names of months + } + }; + + // round to nearby lower multiple of base + + function floorInBase(n, base) { + return base * Math.floor(n / base); + } + + // Returns a string with the date d formatted according to fmt. + // A subset of the Open Group's strftime format is supported. + + function formatDate(d, fmt, monthNames, dayNames) { + + if (typeof d.strftime == "function") { + return d.strftime(fmt); + } + + var leftPad = function(n, pad) { + n = "" + n; + pad = "" + (pad == null ? "0" : pad); + return n.length == 1 ? pad + n : n; + }; + + var r = []; + var escape = false; + var hours = d.getHours(); + var isAM = hours < 12; + + if (monthNames == null) { + monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + } + + if (dayNames == null) { + dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + } + + var hours12; + + if (hours > 12) { + hours12 = hours - 12; + } else if (hours == 0) { + hours12 = 12; + } else { + hours12 = hours; + } + + for (var i = 0; i < fmt.length; ++i) { + + var c = fmt.charAt(i); + + if (escape) { + switch (c) { + case 'a': c = "" + dayNames[d.getDay()]; break; + case 'b': c = "" + monthNames[d.getMonth()]; break; + case 'd': c = leftPad(d.getDate()); break; + case 'e': c = leftPad(d.getDate(), " "); break; + case 'h': // For back-compat with 0.7; remove in 1.0 + case 'H': c = leftPad(hours); break; + case 'I': c = leftPad(hours12); break; + case 'l': c = leftPad(hours12, " "); break; + case 'm': c = leftPad(d.getMonth() + 1); break; + case 'M': c = leftPad(d.getMinutes()); break; + // quarters not in Open Group's strftime specification + case 'q': + c = "" + (Math.floor(d.getMonth() / 3) + 1); break; + case 'S': c = leftPad(d.getSeconds()); break; + case 'y': c = leftPad(d.getFullYear() % 100); break; + case 'Y': c = "" + d.getFullYear(); break; + case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break; + case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break; + case 'w': c = "" + d.getDay(); break; + } + r.push(c); + escape = false; + } else { + if (c == "%") { + escape = true; + } else { + r.push(c); + } + } + } + + return r.join(""); + } + + // To have a consistent view of time-based data independent of which time + // zone the client happens to be in we need a date-like object independent + // of time zones. This is done through a wrapper that only calls the UTC + // versions of the accessor methods. + + function makeUtcWrapper(d) { + + function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) { + sourceObj[sourceMethod] = function() { + return targetObj[targetMethod].apply(targetObj, arguments); + }; + }; + + var utc = { + date: d + }; + + // support strftime, if found + + if (d.strftime != undefined) { + addProxyMethod(utc, "strftime", d, "strftime"); + } + + addProxyMethod(utc, "getTime", d, "getTime"); + addProxyMethod(utc, "setTime", d, "setTime"); + + var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"]; + + for (var p = 0; p < props.length; p++) { + addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]); + addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]); + } + + return utc; + }; + + // select time zone strategy. This returns a date-like object tied to the + // desired timezone + + function dateGenerator(ts, opts) { + if (opts.timezone == "browser") { + return new Date(ts); + } else if (!opts.timezone || opts.timezone == "utc") { + return makeUtcWrapper(new Date(ts)); + } else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") { + var d = new timezoneJS.Date(); + // timezone-js is fickle, so be sure to set the time zone before + // setting the time. + d.setTimezone(opts.timezone); + d.setTime(ts); + return d; + } else { + return makeUtcWrapper(new Date(ts)); + } + } + + // map of app. size of time units in milliseconds + + var timeUnitSize = { + "second": 1000, + "minute": 60 * 1000, + "hour": 60 * 60 * 1000, + "day": 24 * 60 * 60 * 1000, + "month": 30 * 24 * 60 * 60 * 1000, + "quarter": 3 * 30 * 24 * 60 * 60 * 1000, + "year": 365.2425 * 24 * 60 * 60 * 1000 + }; + + // the allowed tick sizes, after 1 year we use + // an integer algorithm + + var baseSpec = [ + [1, "second"], [2, "second"], [5, "second"], [10, "second"], + [30, "second"], + [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], + [30, "minute"], + [1, "hour"], [2, "hour"], [4, "hour"], + [8, "hour"], [12, "hour"], + [1, "day"], [2, "day"], [3, "day"], + [0.25, "month"], [0.5, "month"], [1, "month"], + [2, "month"] + ]; + + // we don't know which variant(s) we'll need yet, but generating both is + // cheap + + var specMonths = baseSpec.concat([[3, "month"], [6, "month"], + [1, "year"]]); + var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"], + [1, "year"]]); + + function init(plot) { + plot.hooks.processOptions.push(function (plot, options) { + $.each(plot.getAxes(), function(axisName, axis) { + + var opts = axis.options; + + if (opts.mode == "time") { + axis.tickGenerator = function(axis) { + + var ticks = []; + var d = dateGenerator(axis.min, opts); + var minSize = 0; + + // make quarter use a possibility if quarters are + // mentioned in either of these options + + var spec = (opts.tickSize && opts.tickSize[1] === + "quarter") || + (opts.minTickSize && opts.minTickSize[1] === + "quarter") ? specQuarters : specMonths; + + if (opts.minTickSize != null) { + if (typeof opts.tickSize == "number") { + minSize = opts.tickSize; + } else { + minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]]; + } + } + + for (var i = 0; i < spec.length - 1; ++i) { + if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]] + + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2 + && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) { + break; + } + } + + var size = spec[i][0]; + var unit = spec[i][1]; + + // special-case the possibility of several years + + if (unit == "year") { + + // if given a minTickSize in years, just use it, + // ensuring that it's an integer + + if (opts.minTickSize != null && opts.minTickSize[1] == "year") { + size = Math.floor(opts.minTickSize[0]); + } else { + + var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10)); + var norm = (axis.delta / timeUnitSize.year) / magn; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + } + + // minimum size for years is 1 + + if (size < 1) { + size = 1; + } + } + + axis.tickSize = opts.tickSize || [size, unit]; + var tickSize = axis.tickSize[0]; + unit = axis.tickSize[1]; + + var step = tickSize * timeUnitSize[unit]; + + if (unit == "second") { + d.setSeconds(floorInBase(d.getSeconds(), tickSize)); + } else if (unit == "minute") { + d.setMinutes(floorInBase(d.getMinutes(), tickSize)); + } else if (unit == "hour") { + d.setHours(floorInBase(d.getHours(), tickSize)); + } else if (unit == "month") { + d.setMonth(floorInBase(d.getMonth(), tickSize)); + } else if (unit == "quarter") { + d.setMonth(3 * floorInBase(d.getMonth() / 3, + tickSize)); + } else if (unit == "year") { + d.setFullYear(floorInBase(d.getFullYear(), tickSize)); + } + + // reset smaller components + + d.setMilliseconds(0); + + if (step >= timeUnitSize.minute) { + d.setSeconds(0); + } + if (step >= timeUnitSize.hour) { + d.setMinutes(0); + } + if (step >= timeUnitSize.day) { + d.setHours(0); + } + if (step >= timeUnitSize.day * 4) { + d.setDate(1); + } + if (step >= timeUnitSize.month * 2) { + d.setMonth(floorInBase(d.getMonth(), 3)); + } + if (step >= timeUnitSize.quarter * 2) { + d.setMonth(floorInBase(d.getMonth(), 6)); + } + if (step >= timeUnitSize.year) { + d.setMonth(0); + } + + var carry = 0; + var v = Number.NaN; + var prev; + + do { + + prev = v; + v = d.getTime(); + ticks.push(v); + + if (unit == "month" || unit == "quarter") { + if (tickSize < 1) { + + // a bit complicated - we'll divide the + // month/quarter up but we need to take + // care of fractions so we don't end up in + // the middle of a day + + d.setDate(1); + var start = d.getTime(); + d.setMonth(d.getMonth() + + (unit == "quarter" ? 3 : 1)); + var end = d.getTime(); + d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize); + carry = d.getHours(); + d.setHours(0); + } else { + d.setMonth(d.getMonth() + + tickSize * (unit == "quarter" ? 3 : 1)); + } + } else if (unit == "year") { + d.setFullYear(d.getFullYear() + tickSize); + } else { + d.setTime(v + step); + } + } while (v < axis.max && v != prev); + + return ticks; + }; + + axis.tickFormatter = function (v, axis) { + + var d = dateGenerator(v, axis.options); + + // first check global format + + if (opts.timeformat != null) { + return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames); + } + + // possibly use quarters if quarters are mentioned in + // any of these places + + var useQuarters = (axis.options.tickSize && + axis.options.tickSize[1] == "quarter") || + (axis.options.minTickSize && + axis.options.minTickSize[1] == "quarter"); + + var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]]; + var span = axis.max - axis.min; + var suffix = (opts.twelveHourClock) ? " %p" : ""; + var hourCode = (opts.twelveHourClock) ? "%I" : "%H"; + var fmt; + + if (t < timeUnitSize.minute) { + fmt = hourCode + ":%M:%S" + suffix; + } else if (t < timeUnitSize.day) { + if (span < 2 * timeUnitSize.day) { + fmt = hourCode + ":%M" + suffix; + } else { + fmt = "%b %d " + hourCode + ":%M" + suffix; + } + } else if (t < timeUnitSize.month) { + fmt = "%b %d"; + } else if ((useQuarters && t < timeUnitSize.quarter) || + (!useQuarters && t < timeUnitSize.year)) { + if (span < timeUnitSize.year) { + fmt = "%b"; + } else { + fmt = "%b %Y"; + } + } else if (useQuarters && t < timeUnitSize.year) { + if (span < timeUnitSize.year) { + fmt = "Q%q"; + } else { + fmt = "Q%q %Y"; + } + } else { + fmt = "%Y"; + } + + var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames); + + return rt; + }; + } + }); + }); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'time', + version: '1.0' + }); + + // Time-axis support used to be in Flot core, which exposed the + // formatDate function on the plot object. Various plugins depend + // on the function, so we need to re-expose it here. + + $.plot.formatDate = formatDate; + +})(jQuery); diff --git a/emoncms/Lib/flot/jquery.flot.time.min.js b/emoncms/Lib/flot/jquery.flot.time.min.js new file mode 100644 index 0000000..21d8477 --- /dev/null +++ b/emoncms/Lib/flot/jquery.flot.time.min.js @@ -0,0 +1,9 @@ +/* Pretty handling of time axes. + +Copyright (c) 2007-2013 IOLA and Ole Laursen. +Licensed under the MIT license. + +Set axis.mode to "time" to enable. See the section "Time series data" in +API.txt for details. + +*/(function(e){function n(e,t){return t*Math.floor(e/t)}function r(e,t,n,r){if(typeof e.strftime=="function")return e.strftime(t);var i=function(e,t){return e=""+e,t=""+(t==null?"0":t),e.length==1?t+e:e},s=[],o=!1,u=e.getHours(),a=u<12;n==null&&(n=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]),r==null&&(r=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]);var f;u>12?f=u-12:u==0?f=12:f=u;for(var l=0;l=u)break;var h=l[c][0],p=l[c][1];if(p=="year"){if(i.minTickSize!=null&&i.minTickSize[1]=="year")h=Math.floor(i.minTickSize[0]);else{var d=Math.pow(10,Math.floor(Math.log(e.delta/o.year)/Math.LN10)),v=e.delta/o.year/d;v<1.5?h=1:v<3?h=2:v<7.5?h=5:h=10,h*=d}h<1&&(h=1)}e.tickSize=i.tickSize||[h,p];var m=e.tickSize[0];p=e.tickSize[1];var g=m*o[p];p=="second"?r.setSeconds(n(r.getSeconds(),m)):p=="minute"?r.setMinutes(n(r.getMinutes(),m)):p=="hour"?r.setHours(n(r.getHours(),m)):p=="month"?r.setMonth(n(r.getMonth(),m)):p=="quarter"?r.setMonth(3*n(r.getMonth()/3,m)):p=="year"&&r.setFullYear(n(r.getFullYear(),m)),r.setMilliseconds(0),g>=o.minute&&r.setSeconds(0),g>=o.hour&&r.setMinutes(0),g>=o.day&&r.setHours(0),g>=o.day*4&&r.setDate(1),g>=o.month*2&&r.setMonth(n(r.getMonth(),3)),g>=o.quarter*2&&r.setMonth(n(r.getMonth(),6)),g>=o.year&&r.setMonth(0);var y=0,b=Number.NaN,w;do{w=b,b=r.getTime(),t.push(b);if(p=="month"||p=="quarter")if(m<1){r.setDate(1);var E=r.getTime();r.setMonth(r.getMonth()+(p=="quarter"?3:1));var S=r.getTime();r.setTime(b+y*o.hour+(S-E)*m),y=r.getHours(),r.setHours(0)}else r.setMonth(r.getMonth()+m*(p=="quarter"?3:1));else p=="year"?r.setFullYear(r.getFullYear()+m):r.setTime(b+g)}while(b to avoid XSS via location.hash (#9521) + rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // The ready event handler and self cleanup method + DOMContentLoaded = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + } else if ( document.readyState === "complete" ) { + // we're here because readyState === "complete" in oldIE + // which is good enough for us to call the dom ready! + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context && context.nodeType ? context.ownerDocument || context : document ); + + // scripts is true for back-compat + selector = jQuery.parseHTML( match[1], doc, true ); + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + this.attr.call( selector, context, true ); + } + + return jQuery.merge( this, selector ); + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.8.3", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ), + "slice", core_slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ core_toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // scripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, scripts ) { + var parsed; + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + scripts = context; + context = 0; + } + context = context || document; + + // Single tag + if ( (parsed = rsingleTag.exec( data )) ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); + return jQuery.merge( [], + (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); + }, + + parseJSON: function( data ) { + if ( !data || typeof data !== "string") { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && core_rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var name, + i = 0, + length = obj.length, + isObj = length === undefined || jQuery.isFunction( obj ); + + if ( args ) { + if ( isObj ) { + for ( name in obj ) { + if ( callback.apply( obj[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( obj[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in obj ) { + if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var type, + ret = results || []; + + if ( arr != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + type = jQuery.type( arr ); + + if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { + core_push.call( ret, arr ); + } else { + jQuery.merge( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, + ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready, 1 ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.split( core_rspace ), function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + return jQuery.inArray( fn, list ) > -1; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( list && ( !fired || stack ) ) { + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? + function() { + var returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + } : + newDefer[ action ] + ); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] = list.fire + deferred[ tuple[0] ] = list.fire; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + eventName, + i, + isSupported, + clickFn, + div = document.createElement("div"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
a"; + + // Support tests won't run in some limited or non-browser environments + all = div.getElementsByTagName("*"); + a = div.getElementsByTagName("a")[ 0 ]; + if ( !all || !a || !all.length ) { + return {}; + } + + // First batch of tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + a.style.cssText = "top:1px;float:left;opacity:.5"; + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.5/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form (#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode + boxModel: ( document.compatMode === "CSS1Compat" ), + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + boxSizingReliable: true, + pixelPosition: false + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", clickFn = function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent("onclick"); + div.detachEvent( "onclick", clickFn ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + input.setAttribute( "checked", "checked" ); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: true, + change: true, + focusin: true + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + // Run tests that need a body at doc ready + jQuery(function() { + var container, div, tds, marginDiv, + divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
t
"; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + support.boxSizing = ( div.offsetWidth === 4 ); + support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); + + // NOTE: To any future maintainer, we've window.getComputedStyle + // because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = document.createElement("div"); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
"; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + container.style.zoom = 1; + } + + // Null elements to avoid leaks in IE + body.removeChild( container ); + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + fragment.removeChild( div ); + all = a = select = opt = input = fragment = div = null; + + return support; +})(); +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + deletedIds: [], + + // Remove at next major release (1.9/2.0) + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( !name.indexOf( "data-" ) ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery.removeData( elem, type + "queue", true ); + jQuery.removeData( elem, key, true ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, fixSpecified, + rclass = /[\t\r\n]/g, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea|)$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( core_rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var removes, className, elem, c, cl, i, l; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + if ( (value && typeof value === "string") || value === undefined ) { + removes = ( value || "" ).split( core_rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + if ( elem.nodeType === 1 && elem.className ) { + + className = (" " + elem.className + " ").replace( rclass, " " ); + + // loop over each item in the removal list + for ( c = 0, cl = removes.length; c < cl; c++ ) { + // Remove until there is nothing to remove, + while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) { + className = className.replace( " " + removes[ c ] + " " , " " ); + } + } + elem.className = value ? jQuery.trim( className ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( core_rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val, + self = jQuery(this); + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // oldIE doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + // Don't return options that are disabled or in a disabled optgroup + ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && + ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 + attrFn: {}, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + + attrNames = value.split( core_rspace ); + + for ( ; i < attrNames.length; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? + ret.value : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.value = value + "" ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, + rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var t, tns, type, origType, namespaces, origCount, + j, events, special, eventType, handleObj, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, "events", true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, + type = event.type || event, + namespaces = []; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + for ( old = elem; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old === (elem.ownerDocument || document) ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related, + handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = core_slice.call( arguments ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = []; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.disabled !== true || event.type !== "click" ) { + selMatch = {}; + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) + event.metaKey = !!event.metaKey; + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === "undefined" ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "_submit_attached" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "_submit_attached", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "_change_attached", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://sizzlejs.com/ + */ +(function( window, undefined ) { + +var cachedruns, + assertGetIdNotName, + Expr, + getText, + isXML, + contains, + compile, + sortOrder, + hasDuplicate, + outermostContext, + + baseHasDuplicate = true, + strundefined = "undefined", + + expando = ( "sizcache" + Math.random() ).replace( ".", "" ), + + Token = String, + document = window.document, + docElem = document.documentElement, + dirruns = 0, + done = 0, + pop = [].pop, + push = [].push, + slice = [].slice, + // Use a stripped-down indexOf if a native one is unavailable + indexOf = [].indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + // Augment a function for special use by Sizzle + markFunction = function( fn, value ) { + fn[ expando ] = value == null || value; + return fn; + }, + + createCache = function() { + var cache = {}, + keys = []; + + return markFunction(function( key, value ) { + // Only keep the most recent entries + if ( keys.push( key ) > Expr.cacheLength ) { + delete cache[ keys.shift() ]; + } + + // Retrieve with (key + " ") to avoid collision with native Object.prototype properties (see Issue #157) + return (cache[ key + " " ] = value); + }, cache ); + }, + + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + + // Regex + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + operators = "([*^$|!~]?=)", + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments not in parens/brackets, + // then attribute selectors and non-pseudos (denoted by :), + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)", + + // For matchExpr.POS and matchExpr.needsContext + pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), + rpseudo = new RegExp( pseudos ), + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, + + rnot = /^:not/, + rsibling = /[\x20\t\r\n\f]*[+~]/, + rendsWithNot = /:not\($/, + + rheader = /h\d/i, + rinputs = /input|select|textarea|button/i, + + rbackslash = /\\(?!\\)/g, + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "POS": new RegExp( pos, "i" ), + "CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + // For use in libraries implementing .is() + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) + }, + + // Support + + // Used for testing something on an element + assert = function( fn ) { + var div = document.createElement("div"); + + try { + return fn( div ); + } catch (e) { + return false; + } finally { + // release memory in IE + div = null; + } + }, + + // Check if getElementsByTagName("*") returns only elements + assertTagNameNoComments = assert(function( div ) { + div.appendChild( document.createComment("") ); + return !div.getElementsByTagName("*").length; + }), + + // Check if getAttribute returns normalized href attributes + assertHrefNotNormalized = assert(function( div ) { + div.innerHTML = ""; + return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && + div.firstChild.getAttribute("href") === "#"; + }), + + // Check if attributes should be retrieved by attribute nodes + assertAttributes = assert(function( div ) { + div.innerHTML = ""; + var type = typeof div.lastChild.getAttribute("multiple"); + // IE8 returns a string for some attributes even when not present + return type !== "boolean" && type !== "string"; + }), + + // Check if getElementsByClassName can be trusted + assertUsableClassName = assert(function( div ) { + // Opera can't find a second classname (in 9.6) + div.innerHTML = ""; + if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { + return false; + } + + // Safari 3.2 caches class attributes and doesn't catch changes + div.lastChild.className = "e"; + return div.getElementsByClassName("e").length === 2; + }), + + // Check if getElementById returns elements by name + // Check if getElementsByName privileges form controls or returns elements by ID + assertUsableName = assert(function( div ) { + // Inject content + div.id = expando + 0; + div.innerHTML = "
"; + docElem.insertBefore( div, docElem.firstChild ); + + // Test + var pass = document.getElementsByName && + // buggy browsers will return fewer than the correct 2 + document.getElementsByName( expando ).length === 2 + + // buggy browsers will return more than the correct 0 + document.getElementsByName( expando + 0 ).length; + assertGetIdNotName = !document.getElementById( expando ); + + // Cleanup + docElem.removeChild( div ); + + return pass; + }); + +// If slice is not available, provide a backup +try { + slice.call( docElem.childNodes, 0 )[0].nodeType; +} catch ( e ) { + slice = function( i ) { + var elem, + results = []; + for ( ; (elem = this[i]); i++ ) { + results.push( elem ); + } + return results; + }; +} + +function Sizzle( selector, context, results, seed ) { + results = results || []; + context = context || document; + var match, elem, xml, m, + nodeType = context.nodeType; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( nodeType !== 1 && nodeType !== 9 ) { + return []; + } + + xml = isXML( context ); + + if ( !xml && !seed ) { + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { + push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); + return results; + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed, xml ); +} + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + return Sizzle( expr, null, null, [ elem ] ).length > 0; +}; + +// Returns a function to use in pseudos for input types +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +// Returns a function to use in pseudos for buttons +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +// Returns a function to use in pseudos for positionals +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + } else { + + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } + return ret; +}; + +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +// Element contains another +contains = Sizzle.contains = docElem.contains ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); + } : + docElem.compareDocumentPosition ? + function( a, b ) { + return b && !!( a.compareDocumentPosition( b ) & 16 ); + } : + function( a, b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + return false; + }; + +Sizzle.attr = function( elem, name ) { + var val, + xml = isXML( elem ); + + if ( !xml ) { + name = name.toLowerCase(); + } + if ( (val = Expr.attrHandle[ name ]) ) { + return val( elem ); + } + if ( xml || assertAttributes ) { + return elem.getAttribute( name ); + } + val = elem.getAttributeNode( name ); + return val ? + typeof elem[ name ] === "boolean" ? + elem[ name ] ? name : null : + val.specified ? val.value : null : + null; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + // IE6/7 return a modified href + attrHandle: assertHrefNotNormalized ? + {} : + { + "href": function( elem ) { + return elem.getAttribute( "href", 2 ); + }, + "type": function( elem ) { + return elem.getAttribute("type"); + } + }, + + find: { + "ID": assertGetIdNotName ? + function( id, context, xml ) { + if ( typeof context.getElementById !== strundefined && !xml ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + } : + function( id, context, xml ) { + if ( typeof context.getElementById !== strundefined && !xml ) { + var m = context.getElementById( id ); + + return m ? + m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? + [m] : + undefined : + []; + } + }, + + "TAG": assertTagNameNoComments ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + var elem, + tmp = [], + i = 0; + + for ( ; (elem = results[i]); i++ ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }, + + "NAME": assertUsableName && function( tag, context ) { + if ( typeof context.getElementsByName !== strundefined ) { + return context.getElementsByName( name ); + } + }, + + "CLASS": assertUsableClassName && function( className, context, xml ) { + if ( typeof context.getElementsByClassName !== strundefined && !xml ) { + return context.getElementsByClassName( className ); + } + } + }, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( rbackslash, "" ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 3 xn-component of xn+y argument ([+-]?\d*n|) + 4 sign of xn-component + 5 x of xn-component + 6 sign of y-component + 7 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1] === "nth" ) { + // nth-child requires argument + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); + match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); + + // other types prohibit arguments + } else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var unquoted, excess; + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + if ( match[3] ) { + match[2] = match[3]; + } else if ( (unquoted = match[4]) ) { + // Only check arguments that contain a pseudo + if ( rpseudo.test(unquoted) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + unquoted = unquoted.slice( 0, excess ); + match[0] = match[0].slice( 0, excess ); + } + match[2] = unquoted; + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + "ID": assertGetIdNotName ? + function( id ) { + id = id.replace( rbackslash, "" ); + return function( elem ) { + return elem.getAttribute("id") === id; + }; + } : + function( id ) { + id = id.replace( rbackslash, "" ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === id; + }; + }, + + "TAG": function( nodeName ) { + if ( nodeName === "*" ) { + return function() { return true; }; + } + nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); + + return function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ expando ][ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem, context ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.substr( result.length - check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, argument, first, last ) { + + if ( type === "nth" ) { + return function( elem ) { + var node, diff, + parent = elem.parentNode; + + if ( first === 1 && last === 0 ) { + return true; + } + + if ( parent ) { + diff = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + diff++; + if ( elem === node ) { + break; + } + } + } + } + + // Incorporate the offset (or cast to NaN), then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + }; + } + + return function( elem ) { + var node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + var nodeType; + elem = elem.firstChild; + while ( elem ) { + if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { + return false; + } + elem = elem.nextSibling; + } + return true; + }, + + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "text": function( elem ) { + var type, attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + (type = elem.type) === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); + }, + + // Input types + "radio": createInputPseudo("radio"), + "checkbox": createInputPseudo("checkbox"), + "file": createInputPseudo("file"), + "password": createInputPseudo("password"), + "image": createInputPseudo("image"), + + "submit": createButtonPseudo("submit"), + "reset": createButtonPseudo("reset"), + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "focus": function( elem ) { + var doc = elem.ownerDocument; + return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + "active": function( elem ) { + return elem === elem.ownerDocument.activeElement; + }, + + // Positional types + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + for ( var i = 0; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + for ( var i = 1; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +function siblingCheck( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; +} + +sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? + a.compareDocumentPosition : + a.compareDocumentPosition(b) & 4 + ) ? -1 : 1; + } : + function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + +// Always assume the presence of duplicates if sort doesn't +// pass them to our comparison function (as in Google Chrome). +[0, 0].sort( sortOrder ); +baseHasDuplicate = !hasDuplicate; + +// Document sorting and removing duplicates +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + i = 1, + j = 0; + + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( ; (elem = results[i]); i++ ) { + if ( elem === results[ i - 1 ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ expando ][ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + tokens.push( matched = new Token( match.shift() ) ); + soFar = soFar.slice( matched.length ); + + // Cast descendant combinators to space + matched.type = match[0].replace( rtrim, " " ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + + tokens.push( matched = new Token( match.shift() ) ); + soFar = soFar.slice( matched.length ); + matched.type = type; + matched.matches = match; + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && combinator.dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( !xml ) { + var cache, + dirkey = dirruns + " " + doneName + " ", + cachedkey = dirkey + cachedruns; + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + if ( (cache = elem[ expando ]) === cachedkey ) { + return elem.sizset; + } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { + if ( elem.sizset ) { + return elem; + } + } else { + elem[ expando ] = cachedkey; + if ( matcher( elem, context, xml ) ) { + elem.sizset = true; + return elem; + } + elem.sizset = false; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + if ( matcher( elem, context, xml ) ) { + return elem; + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && tokens.join("") + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Nested matchers should use non-integer dirruns + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = superMatcher.el; + } + + // Add elements passing elementMatchers directly to results + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + for ( j = 0; (matcher = elementMatchers[j]); j++ ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++superMatcher.el; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + for ( j = 0; (matcher = setMatchers[j]); j++ ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + superMatcher.el = 0; + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ expando ][ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed, xml ) { + var i, tokens, token, type, find, + match = tokenize( selector ), + j = match.length; + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && !xml && + Expr.relative[ tokens[1].type ] ) { + + context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0]; + if ( !context ) { + return results; + } + + selector = selector.slice( tokens.shift().length ); + } + + // Fetch a seed set for right-to-left matching + for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( rbackslash, "" ), + rsibling.test( tokens[0].type ) && context.parentNode || context, + xml + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && tokens.join(""); + if ( !selector ) { + push.apply( results, slice.call( seed, 0 ) ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + xml, + results, + rsibling.test( selector ) + ); + return results; +} + +if ( document.querySelectorAll ) { + (function() { + var disconnectedMatch, + oldSelect = select, + rescape = /'|\\/g, + rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, + + // qSa(:focus) reports false when true (Chrome 21), no need to also add to buggyMatches since matches checks buggyQSA + // A support test would require too much code (would include document ready) + rbuggyQSA = [ ":focus" ], + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + // A support test would require too much code (would include document ready) + // just skip matchesSelector for :active + rbuggyMatches = [ ":active" ], + matches = docElem.matchesSelector || + docElem.mozMatchesSelector || + docElem.webkitMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector; + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explictly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // IE8 - Some boolean attributes are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here (do not put tests after this one) + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Opera 10-12/IE9 - ^= $= *= and empty values + // Should not select anything + div.innerHTML = "

"; + if ( div.querySelectorAll("[test^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here (do not put tests after this one) + div.innerHTML = ""; + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push(":enabled", ":disabled"); + } + }); + + // rbuggyQSA always contains :focus, so no need for a length check + rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") ); + + select = function( selector, context, results, seed, xml ) { + // Only use querySelectorAll when not filtering, + // when this is not xml, + // and when no QSA bugs apply + if ( !seed && !xml && !rbuggyQSA.test( selector ) ) { + var groups, i, + old = true, + nid = expando, + newContext = context, + newSelector = context.nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + groups[i].join(""); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, slice.call( newContext.querySelectorAll( + newSelector + ), 0 ) ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + + return oldSelect( selector, context, results, seed, xml ); + }; + + if ( matches ) { + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + try { + matches.call( div, "[test!='']:sizzle" ); + rbuggyMatches.push( "!=", pseudos ); + } catch ( e ) {} + }); + + // rbuggyMatches always contains :active and :focus, so no need for a length check + rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); + + Sizzle.matchesSelector = function( elem, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + // rbuggyMatches always contains :active, so no need for an existence check + if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && !rbuggyQSA.test( expr ) ) { + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, null, null, [ elem ] ).length > 0; + }; + } + })(); +} + +// Deprecated +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Back-compat +function setFilters() {} +Expr.filters = setFilters.prototype = Expr.pseudos; +Expr.setFilters = new setFilters(); + +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + isSimple = /^.[^:#\[\.,]*$/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, l, length, n, r, ret, + self = this; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + ret = this.pushStack( "", "find", selector ); + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + rneedsContext.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + cur = this[i]; + + while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + } + cur = cur.parentNode; + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +jQuery.fn.andSelf = jQuery.fn.addBack; + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( this.length > 1 && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + rcheckableType = /^(?:checkbox|radio)$/, + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*\s*$/g, + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, +// unless wrapped in a div with non-breaking characters in front of it. +if ( !jQuery.support.htmlSerialize ) { + wrapMap._default = [ 1, "X
", "
" ]; +} + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + }, + + append: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 ) { + this.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 ) { + this.insertBefore( elem, this.firstChild ); + } + }); + }, + + before: function() { + if ( !isDisconnected( this[0] ) ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this ); + }); + } + + if ( arguments.length ) { + var set = jQuery.clean( arguments ); + return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); + } + }, + + after: function() { + if ( !isDisconnected( this[0] ) ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + } + + if ( arguments.length ) { + var set = jQuery.clean( arguments ); + return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); + } + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + jQuery.cleanData( [ elem ] ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName( "*" ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function( value ) { + if ( !isDisconnected( this[0] ) ) { + // Make sure that the elements are removed from the DOM before they are inserted + // this can help fix replacing a parent with child elements + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this), old = self.html(); + self.replaceWith( value.call( this, i, old ) ); + }); + } + + if ( typeof value !== "string" ) { + value = jQuery( value ).detach(); + } + + return this.each(function() { + var next = this.nextSibling, + parent = this.parentNode; + + jQuery( this ).remove(); + + if ( next ) { + jQuery(next).before( value ); + } else { + jQuery(parent).append( value ); + } + }); + } + + return this.length ? + this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : + this; + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, table, callback ) { + + // Flatten any nested arrays + args = [].concat.apply( [], args ); + + var results, first, fragment, iNoClone, + i = 0, + value = args[0], + scripts = [], + l = this.length; + + // We can't cloneNode fragments that contain checked, in WebKit + if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { + return this.each(function() { + jQuery(this).domManip( args, table, callback ); + }); + } + + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + args[0] = value.call( this, i, table ? self.html() : undefined ); + self.domManip( args, table, callback ); + }); + } + + if ( this[0] ) { + results = jQuery.buildFragment( args, this, scripts ); + fragment = results.fragment; + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + table = table && jQuery.nodeName( first, "tr" ); + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + // Fragments from the fragment cache must always be cloned and never used in place. + for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { + callback.call( + table && jQuery.nodeName( this[i], "table" ) ? + findOrAppend( this[i], "tbody" ) : + this[i], + i === iNoClone ? + fragment : + jQuery.clone( fragment, true, true ) + ); + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + + if ( scripts.length ) { + jQuery.each( scripts, function( i, elem ) { + if ( elem.src ) { + if ( jQuery.ajax ) { + jQuery.ajax({ + url: elem.src, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } else { + jQuery.error("no ajax"); + } + } else { + jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + }); + } + } + + return this; + } +}); + +function findOrAppend( elem, tag ) { + return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function cloneFixAttributes( src, dest ) { + var nodeName; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + // clearAttributes removes the attributes, which we don't want, + // but also removes the attachEvent events, which we *do* want + if ( dest.clearAttributes ) { + dest.clearAttributes(); + } + + // mergeAttributes, in contrast, only merges back on the + // original attributes, not the events + if ( dest.mergeAttributes ) { + dest.mergeAttributes( src ); + } + + nodeName = dest.nodeName.toLowerCase(); + + if ( nodeName === "object" ) { + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + + // IE blanks contents when cloning scripts + } else if ( nodeName === "script" && dest.text !== src.text ) { + dest.text = src.text; + } + + // Event data gets referenced instead of copied if the expando + // gets copied too + dest.removeAttribute( jQuery.expando ); +} + +jQuery.buildFragment = function( args, context, scripts ) { + var fragment, cacheable, cachehit, + first = args[ 0 ]; + + // Set context from what may come in as undefined or a jQuery collection or a node + // Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 & + // also doubles as fix for #8950 where plain objects caused createDocumentFragment exception + context = context || document; + context = !context.nodeType && context[0] || context; + context = context.ownerDocument || context; + + // Only cache "small" (1/2 KB) HTML strings that are associated with the main document + // Cloning options loses the selected state, so don't cache them + // IE 6 doesn't like it when you put or elements in a fragment + // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache + // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 + if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && + first.charAt(0) === "<" && !rnocache.test( first ) && + (jQuery.support.checkClone || !rchecked.test( first )) && + (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { + + // Mark cacheable and look for a hit + cacheable = true; + fragment = jQuery.fragments[ first ]; + cachehit = fragment !== undefined; + } + + if ( !fragment ) { + fragment = context.createDocumentFragment(); + jQuery.clean( args, context, fragment, scripts ); + + // Update the cache, but only store false + // unless this is a second parsing of the same content + if ( cacheable ) { + jQuery.fragments[ first ] = cachehit && fragment; + } + } + + return { fragment: fragment, cacheable: cacheable }; +}; + +jQuery.fragments = {}; + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + l = insert.length, + parent = this.length === 1 && this[0].parentNode; + + if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { + insert[ original ]( this[0] ); + return this; + } else { + for ( ; i < l; i++ ) { + elems = ( i > 0 ? this.clone(true) : this ).get(); + jQuery( insert[i] )[ original ]( elems ); + ret = ret.concat( elems ); + } + + return this.pushStack( ret, name, insert.selector ); + } + }; +}); + +function getAll( elem ) { + if ( typeof elem.getElementsByTagName !== "undefined" ) { + return elem.getElementsByTagName( "*" ); + + } else if ( typeof elem.querySelectorAll !== "undefined" ) { + return elem.querySelectorAll( "*" ); + + } else { + return []; + } +} + +// Used in clean, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var srcElements, + destElements, + i, + clone; + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + // IE copies events bound via attachEvent when using cloneNode. + // Calling detachEvent on the clone will also remove the events + // from the original. In order to get around this, we use some + // proprietary methods to clear the events. Thanks to MooTools + // guys for this hotness. + + cloneFixAttributes( elem, clone ); + + // Using Sizzle here is crazy slow, so we use getElementsByTagName instead + srcElements = getAll( elem ); + destElements = getAll( clone ); + + // Weird iteration because IE will replace the length property + // with an element if you are cloning the body and one of the + // elements on the page has a name or id of "length" + for ( i = 0; srcElements[i]; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + cloneFixAttributes( srcElements[i], destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + cloneCopyEvent( elem, clone ); + + if ( deepDataAndEvents ) { + srcElements = getAll( elem ); + destElements = getAll( clone ); + + for ( i = 0; srcElements[i]; ++i ) { + cloneCopyEvent( srcElements[i], destElements[i] ); + } + } + } + + srcElements = destElements = null; + + // Return the cloned set + return clone; + }, + + clean: function( elems, context, fragment, scripts ) { + var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, + safe = context === document && safeFragment, + ret = []; + + // Ensure that context is a document + if ( !context || typeof context.createDocumentFragment === "undefined" ) { + context = document; + } + + // Use the already-created safe fragment if context permits + for ( i = 0; (elem = elems[i]) != null; i++ ) { + if ( typeof elem === "number" ) { + elem += ""; + } + + if ( !elem ) { + continue; + } + + // Convert html string into DOM nodes + if ( typeof elem === "string" ) { + if ( !rhtml.test( elem ) ) { + elem = context.createTextNode( elem ); + } else { + // Ensure a safe container in which to render the html + safe = safe || createSafeFragment( context ); + div = context.createElement("div"); + safe.appendChild( div ); + + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(rxhtmlTag, "<$1>"); + + // Go to html and back, then peel off extra wrappers + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + depth = wrap[0]; + div.innerHTML = wrap[1] + elem + wrap[2]; + + // Move to the right depth + while ( depth-- ) { + div = div.lastChild; + } + + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { + + // String was a , *may* have spurious + hasBody = rtbody.test(elem); + tbody = tag === "table" && !hasBody ? + div.firstChild && div.firstChild.childNodes : + + // String was a bare or + wrap[1] === "
" && !hasBody ? + div.childNodes : + []; + + for ( j = tbody.length - 1; j >= 0 ; --j ) { + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { + tbody[ j ].parentNode.removeChild( tbody[ j ] ); + } + } + } + + // IE completely kills leading whitespace when innerHTML is used + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + } + + elem = div.childNodes; + + // Take out of fragment container (we need a fresh div each time) + div.parentNode.removeChild( div ); + } + } + + if ( elem.nodeType ) { + ret.push( elem ); + } else { + jQuery.merge( ret, elem ); + } + } + + // Fix #11356: Clear elements from safeFragment + if ( div ) { + elem = div = safe = null; + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + for ( i = 0; (elem = ret[i]) != null; i++ ) { + if ( jQuery.nodeName( elem, "input" ) ) { + fixDefaultChecked( elem ); + } else if ( typeof elem.getElementsByTagName !== "undefined" ) { + jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); + } + } + } + + // Append elements to a provided document fragment + if ( fragment ) { + // Special handling of each script element + handleScript = function( elem ) { + // Check if we consider it executable + if ( !elem.type || rscriptType.test( elem.type ) ) { + // Detach the script and store it in the scripts array (if provided) or the fragment + // Return truthy to indicate that it has been handled + return scripts ? + scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : + fragment.appendChild( elem ); + } + }; + + for ( i = 0; (elem = ret[i]) != null; i++ ) { + // Check if we're done after handling an executable script + if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { + // Append to fragment and handle embedded scripts + fragment.appendChild( elem ); + if ( typeof elem.getElementsByTagName !== "undefined" ) { + // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration + jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); + + // Splice the scripts into ret after their former ancestor and advance our index beyond them + ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); + i += jsTags.length; + } + } + } + } + + return ret; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var data, id, elem, type, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + jQuery.deletedIds.push( id ); + } + } + } + } + } +}); +// Limit scope pollution from any deprecated API +(function() { + +var matched, browser; + +// Use of jQuery.browser is frowned upon. +// More details: http://api.jquery.com/jQuery.browser +// jQuery.uaMatch maintained for back-compat +jQuery.uaMatch = function( ua ) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || + /(webkit)[ \/]([\w.]+)/.exec( ua ) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || + /(msie) ([\w.]+)/.exec( ua ) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; +}; + +matched = jQuery.uaMatch( navigator.userAgent ); +browser = {}; + +if ( matched.browser ) { + browser[ matched.browser ] = true; + browser.version = matched.version; +} + +// Chrome is Webkit, but Webkit is also Safari. +if ( browser.chrome ) { + browser.webkit = true; +} else if ( browser.webkit ) { + browser.safari = true; +} + +jQuery.browser = browser; + +jQuery.sub = function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; +}; + +})(); +var curCSS, iframe, iframeDoc, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity=([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), + elemdisplay = { BODY: "block" }, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], + + eventsToggle = jQuery.fn.toggle; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var elem, display, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + values[ index ] = jQuery._data( elem, "olddisplay" ); + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && elem.style.display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + display = curCSS( elem, "display" ); + + if ( !values[ index ] && display !== "none" ) { + jQuery._data( elem, "olddisplay", display ); + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state, fn2 ) { + var bool = typeof state === "boolean"; + + if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { + return eventsToggle.apply( this, arguments ); + } + + return this.each(function() { + if ( bool ? state : isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + + } + } + } + }, + + // Exclude the following css properties to add px + cssNumber: { + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, numeric, extra ) { + var val, num, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( numeric || extra !== undefined ) { + num = parseFloat( val ); + return numeric || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +// NOTE: To any future maintainer, we've window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + curCSS = function( elem, name ) { + var ret, width, minWidth, maxWidth, + computed = window.getComputedStyle( elem, null ), + style = elem.style; + + if ( computed ) { + + // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + curCSS = function( elem, name ) { + var left, rsLeft, + ret = elem.currentStyle && elem.currentStyle[ name ], + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + elem.runtimeStyle.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + elem.runtimeStyle.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + // we use jQuery.css instead of curCSS here + // because of the reliableMarginRight CSS hook! + val += jQuery.css( elem, extra + cssExpand[ i ], true ); + } + + // From this point on we use curCSS for maximum performance (relevant in animations) + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + } else { + // at this point, extra isn't content, so add padding + val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + valueIsBorderBox = true, + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox + ) + ) + "px"; +} + + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + if ( elemdisplay[ nodeName ] ) { + return elemdisplay[ nodeName ]; + } + + var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), + display = elem.css("display"); + elem.remove(); + + // If the simple way fails, + // get element's real default display by attaching it to a temp iframe + if ( display === "none" || display === "" ) { + // Use the already-created iframe if possible + iframe = document.body.appendChild( + iframe || jQuery.extend( document.createElement("iframe"), { + frameBorder: 0, + width: 0, + height: 0 + }) + ); + + // Create a cacheable copy of the iframe document on first call. + // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML + // document to it; WebKit & Firefox won't allow reusing the iframe document. + if ( !iframeDoc || !iframe.createElement ) { + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write(""); + iframeDoc.close(); + } + + elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); + + display = curCSS( elem, "display" ); + document.body.removeChild( iframe ); + } + + // Store the correct default display + elemdisplay[ nodeName ] = display; + + return display; +} + +jQuery.each([ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + // certain elements can have dimension info if we invisibly show them + // however, it must have a current display style that would benefit from this + if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) { + return jQuery.swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + }); + } else { + return getWidthOrHeight( elem, name, extra ); + } + } + }, + + set: function( elem, value, extra ) { + return setPositiveNumber( elem, value, extra ? + augmentWidthOrHeight( + elem, + name, + extra, + jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" + ) : 0 + ); + } + }; +}); + +if ( !jQuery.support.opacity ) { + jQuery.cssHooks.opacity = { + get: function( elem, computed ) { + // IE uses filters for opacity + return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? + ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : + computed ? "1" : ""; + }, + + set: function( elem, value ) { + var style = elem.style, + currentStyle = elem.currentStyle, + opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", + filter = currentStyle && currentStyle.filter || style.filter || ""; + + // IE has trouble with opacity if it does not have layout + // Force it by setting the zoom level + style.zoom = 1; + + // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 + if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && + style.removeAttribute ) { + + // Setting style.filter to null, "" & " " still leave "filter:" in the cssText + // if "filter:" is present at all, clearType is disabled, we want to avoid this + // style.removeAttribute is IE Only, but so apparently is this code path... + style.removeAttribute( "filter" ); + + // if there there is no filter style applied in a css rule, we are done + if ( currentStyle && !currentStyle.filter ) { + return; + } + } + + // otherwise, set new filter values + style.filter = ralpha.test( filter ) ? + filter.replace( ralpha, opacity ) : + filter + " " + opacity; + } + }; +} + +// These hooks cannot be added until DOM ready because the support test +// for it is not run until after DOM ready +jQuery(function() { + if ( !jQuery.support.reliableMarginRight ) { + jQuery.cssHooks.marginRight = { + get: function( elem, computed ) { + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + // Work around by temporarily setting element display to inline-block + return jQuery.swap( elem, { "display": "inline-block" }, function() { + if ( computed ) { + return curCSS( elem, "marginRight" ); + } + }); + } + }; + } + + // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 + // getComputedStyle returns percent when specified for top/left/bottom/right + // rather than make the css module depend on the offset module, we just check for it here + if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { + jQuery.each( [ "top", "left" ], function( i, prop ) { + jQuery.cssHooks[ prop ] = { + get: function( elem, computed ) { + if ( computed ) { + var ret = curCSS( elem, prop ); + // if curCSS returns percentage, fallback to offset + return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; + } + } + }; + }); + } + +}); + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.hidden = function( elem ) { + return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); + }; + + jQuery.expr.filters.visible = function( elem ) { + return !jQuery.expr.filters.hidden( elem ); + }; +} + +// These hooks are used by animate to expand properties +jQuery.each({ + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i, + + // assumes a single number if not a string + parts = typeof value === "string" ? value.split(" ") : [ value ], + expanded = {}; + + for ( i = 0; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +}); +var r20 = /%20/g, + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + rselectTextarea = /^(?:select|textarea)/i; + +jQuery.fn.extend({ + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map(function(){ + return this.elements ? jQuery.makeArray( this.elements ) : this; + }) + .filter(function(){ + return this.name && !this.disabled && + ( this.checked || rselectTextarea.test( this.nodeName ) || + rinput.test( this.type ) ); + }) + .map(function( i, elem ){ + var val = jQuery( this ).val(); + + return val == null ? + null : + jQuery.isArray( val ) ? + jQuery.map( val, function( val, i ){ + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }) : + { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }).get(); + } +}); + +//Serialize an array of form elements or a set of +//key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, value ) { + // If value is a function, invoke it and return its value + value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); + s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); + }; + + // Set traditional to true for jQuery <= 1.3.2 behavior. + if ( traditional === undefined ) { + traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + }); + + } else { + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ).replace( r20, "+" ); +}; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( jQuery.isArray( obj ) ) { + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + // If array item is non-scalar (array or object), encode its + // numeric index to resolve deserialization ambiguity issues. + // Note that rack (as of 1.0.0) can't currently deserialize + // nested arrays properly, and attempting to do so may cause + // a server error. Possible fixes are to modify rack's + // deserialization algorithm or to provide an option or flag + // to force array serialization to be shallow. + buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); + } + }); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + // Serialize scalar item. + add( prefix, obj ); + } +} +var + // Document location + ajaxLocParts, + ajaxLocation, + + rhash = /#.*$/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + rquery = /\?/, + rscript = /)<[^<]*)*<\/script>/gi, + rts = /([?&])_=[^&]*/, + rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, + + // Keep a copy of the old load method + _load = jQuery.fn.load, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = ["*/"] + ["*"]; + +// #8138, IE may throw an exception when accessing +// a field from window.location if document.domain has been set +try { + ajaxLocation = location.href; +} catch( e ) { + // Use the href attribute of an A element + // since IE will modify it given document.location + ajaxLocation = document.createElement( "a" ); + ajaxLocation.href = ""; + ajaxLocation = ajaxLocation.href; +} + +// Segment location into parts +ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, list, placeBefore, + dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), + i = 0, + length = dataTypes.length; + + if ( jQuery.isFunction( func ) ) { + // For each dataType in the dataTypeExpression + for ( ; i < length; i++ ) { + dataType = dataTypes[ i ]; + // We control if we're asked to add before + // any existing element + placeBefore = /^\+/.test( dataType ); + if ( placeBefore ) { + dataType = dataType.substr( 1 ) || "*"; + } + list = structure[ dataType ] = structure[ dataType ] || []; + // then we add to the structure accordingly + list[ placeBefore ? "unshift" : "push" ]( func ); + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, + dataType /* internal */, inspected /* internal */ ) { + + dataType = dataType || options.dataTypes[ 0 ]; + inspected = inspected || {}; + + inspected[ dataType ] = true; + + var selection, + list = structure[ dataType ], + i = 0, + length = list ? list.length : 0, + executeOnly = ( structure === prefilters ); + + for ( ; i < length && ( executeOnly || !selection ); i++ ) { + selection = list[ i ]( options, originalOptions, jqXHR ); + // If we got redirected to another dataType + // we try there if executing only and not done already + if ( typeof selection === "string" ) { + if ( !executeOnly || inspected[ selection ] ) { + selection = undefined; + } else { + options.dataTypes.unshift( selection ); + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, selection, inspected ); + } + } + } + // If we're only executing or nothing was selected + // we try the catchall dataType if not done already + if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, "*", inspected ); + } + // unnecessary when only executing (prefilters) + // but it'll be ignored by the caller in that case + return selection; +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } +} + +jQuery.fn.load = function( url, params, callback ) { + if ( typeof url !== "string" && _load ) { + return _load.apply( this, arguments ); + } + + // Don't do a request if no elements are being requested + if ( !this.length ) { + return this; + } + + var selector, type, response, + self = this, + off = url.indexOf(" "); + + if ( off >= 0 ) { + selector = url.slice( off, url.length ); + url = url.slice( 0, off ); + } + + // If it's a function + if ( jQuery.isFunction( params ) ) { + + // We assume that it's the callback + callback = params; + params = undefined; + + // Otherwise, build a param string + } else if ( params && typeof params === "object" ) { + type = "POST"; + } + + // Request the remote document + jQuery.ajax({ + url: url, + + // if "type" variable is undefined, then "GET" method will be used + type: type, + dataType: "html", + data: params, + complete: function( jqXHR, status ) { + if ( callback ) { + self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); + } + } + }).done(function( responseText ) { + + // Save response for use in complete callback + response = arguments; + + // See if a selector was specified + self.html( selector ? + + // Create a dummy div to hold the results + jQuery("
") + + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append( responseText.replace( rscript, "" ) ) + + // Locate the specified elements + .find( selector ) : + + // If not, just inject the full result + responseText ); + + }); + + return this; +}; + +// Attach a bunch of functions for handling common AJAX events +jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ + jQuery.fn[ o ] = function( f ){ + return this.on( o, f ); + }; +}); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + // shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + return jQuery.ajax({ + type: method, + url: url, + data: data, + success: callback, + dataType: type + }); + }; +}); + +jQuery.extend({ + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + if ( settings ) { + // Building a settings object + ajaxExtend( target, jQuery.ajaxSettings ); + } else { + // Extending ajaxSettings + settings = target; + target = jQuery.ajaxSettings; + } + ajaxExtend( target, settings ); + return target; + }, + + ajaxSettings: { + url: ajaxLocation, + isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), + global: true, + type: "GET", + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + processData: true, + async: true, + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + xml: "application/xml, text/xml", + html: "text/html", + text: "text/plain", + json: "application/json, text/javascript", + "*": allTypes + }, + + contents: { + xml: /xml/, + html: /html/, + json: /json/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText" + }, + + // List of data converters + // 1) key format is "source_type destination_type" (a single space in-between) + // 2) the catchall symbol "*" can be used for source_type + converters: { + + // Convert anything to text + "* text": window.String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": jQuery.parseJSON, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + context: true, + url: true + } + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var // ifModified key + ifModifiedKey, + // Response headers + responseHeadersString, + responseHeaders, + // transport + transport, + // timeout handle + timeoutTimer, + // Cross-domain detection vars + parts, + // To know if global events are to be dispatched + fireGlobals, + // Loop variable + i, + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + // Callbacks context + callbackContext = s.context || s, + // Context for global events + // It's the callbackContext if one was provided in the options + // and if it's a DOM node or a jQuery collection + globalEventContext = callbackContext !== s && + ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? + jQuery( callbackContext ) : jQuery.event, + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + // Status-dependent callbacks + statusCode = s.statusCode || {}, + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + // The jqXHR state + state = 0, + // Default abort message + strAbort = "canceled", + // Fake xhr + jqXHR = { + + readyState: 0, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( !state ) { + var lname = name.toLowerCase(); + name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Raw string + getAllResponseHeaders: function() { + return state === 2 ? responseHeadersString : null; + }, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( state === 2 ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match === undefined ? null : match; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( !state ) { + s.mimeType = type; + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + statusText = statusText || strAbort; + if ( transport ) { + transport.abort( statusText ); + } + done( 0, statusText ); + return this; + } + }; + + // Callback for when everything is done + // It is defined here because jslint complains if it is declared + // at the end of the function (which would be more logical and readable) + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Called once + if ( state === 2 ) { + return; + } + + // State is "done" now + state = 2; + + // Clear timeout if it exists + if ( timeoutTimer ) { + clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // If successful, handle type chaining + if ( status >= 200 && status < 300 || status === 304 ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + + modified = jqXHR.getResponseHeader("Last-Modified"); + if ( modified ) { + jQuery.lastModified[ ifModifiedKey ] = modified; + } + modified = jqXHR.getResponseHeader("Etag"); + if ( modified ) { + jQuery.etag[ ifModifiedKey ] = modified; + } + } + + // If not modified + if ( status === 304 ) { + + statusText = "notmodified"; + isSuccess = true; + + // If we have data + } else { + + isSuccess = ajaxConvert( s, response ); + statusText = isSuccess.state; + success = isSuccess.data; + error = isSuccess.error; + isSuccess = !error; + } + } else { + // We extract error from statusText + // then normalize statusText and status for non-aborts + error = statusText; + if ( !statusText || status ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + // Attach deferreds + deferred.promise( jqXHR ); + jqXHR.success = jqXHR.done; + jqXHR.error = jqXHR.fail; + jqXHR.complete = completeDeferred.add; + + // Status-dependent callbacks + jqXHR.statusCode = function( map ) { + if ( map ) { + var tmp; + if ( state < 2 ) { + for ( tmp in map ) { + statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; + } + } else { + tmp = map[ jqXHR.status ]; + jqXHR.always( tmp ); + } + } + return this; + }; + + // Remove hash character (#7531: and string promotion) + // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) + // We also use the url parameter if available + s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); + + // Extract dataTypes list + s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); + + // A cross-domain request is in order when we have a protocol:host:port mismatch + if ( s.crossDomain == null ) { + parts = rurl.exec( s.url.toLowerCase() ); + s.crossDomain = !!( parts && + ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] || + ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != + ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) + ); + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( state === 2 ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + fireGlobals = s.global; + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // If data is available, append data to url + if ( s.data ) { + s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Get ifModifiedKey before adding the anti-cache parameter + ifModifiedKey = s.url; + + // Add anti-cache in url if needed + if ( s.cache === false ) { + + var ts = jQuery.now(), + // try replacing _= if it is there + ret = s.url.replace( rts, "$1_=" + ts ); + + // if nothing was replaced, add timestamp to the end + s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + ifModifiedKey = ifModifiedKey || s.url; + if ( jQuery.lastModified[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); + } + if ( jQuery.etag[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); + } + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { + // Abort if not done already and return + return jqXHR.abort(); + + } + + // aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + for ( i in { success: 1, error: 1, complete: 1 } ) { + jqXHR[ i ]( s[ i ] ); + } + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = setTimeout( function(){ + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + state = 1; + transport.send( requestHeaders, done ); + } catch (e) { + // Propagate exception as error if not done + if ( state < 2 ) { + done( -1, e ); + // Simply rethrow otherwise + } else { + throw e; + } + } + } + + return jqXHR; + }, + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {} + +}); + +/* Handles responses to an ajax request: + * - sets all responseXXX fields accordingly + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes, + responseFields = s.responseFields; + + // Fill responseXXX fields + for ( type in responseFields ) { + if ( type in responses ) { + jqXHR[ responseFields[type] ] = responses[ type ]; + } + } + + // Remove auto dataType and get content-type in the process + while( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +// Chain conversions given the request and the original response +function ajaxConvert( s, response ) { + + var conv, conv2, current, tmp, + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(), + prev = dataTypes[ 0 ], + converters = {}, + i = 0; + + // Apply the dataFilter if provided + if ( s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + // Convert to each sequential dataType, tolerating list modification + for ( ; (current = dataTypes[++i]); ) { + + // There's only work to do if current dataType is non-auto + if ( current !== "*" ) { + + // Convert response if prev dataType is non-auto and differs from current + if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split(" "); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.splice( i--, 0, current ); + } + + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s["throws"] ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; + } + } + } + } + + // Update prev for next iteration + prev = current; + } + } + + return { state: "success", data: response }; +} +var oldCallbacks = [], + rquestion = /\?/, + rjsonp = /(=)\?(?=&|$)|\?\?/, + nonce = jQuery.now(); + +// Default jsonp settings +jQuery.ajaxSetup({ + jsonp: "callback", + jsonpCallback: function() { + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); + this[ callback ] = true; + return callback; + } +}); + +// Detect, normalize options and install callbacks for jsonp requests +jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { + + var callbackName, overwritten, responseContainer, + data = s.data, + url = s.url, + hasCallback = s.jsonp !== false, + replaceInUrl = hasCallback && rjsonp.test( url ), + replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && + !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && + rjsonp.test( data ); + + // Handle iff the expected data type is "jsonp" or we have a parameter to set + if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { + + // Get callback name, remembering preexisting value associated with it + callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? + s.jsonpCallback() : + s.jsonpCallback; + overwritten = window[ callbackName ]; + + // Insert callback into url or form data + if ( replaceInUrl ) { + s.url = url.replace( rjsonp, "$1" + callbackName ); + } else if ( replaceInData ) { + s.data = data.replace( rjsonp, "$1" + callbackName ); + } else if ( hasCallback ) { + s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; + } + + // Use data converter to retrieve json after script execution + s.converters["script json"] = function() { + if ( !responseContainer ) { + jQuery.error( callbackName + " was not called" ); + } + return responseContainer[ 0 ]; + }; + + // force json dataType + s.dataTypes[ 0 ] = "json"; + + // Install callback + window[ callbackName ] = function() { + responseContainer = arguments; + }; + + // Clean-up function (fires after converters) + jqXHR.always(function() { + // Restore preexisting value + window[ callbackName ] = overwritten; + + // Save back as free + if ( s[ callbackName ] ) { + // make sure that re-using the options doesn't screw things around + s.jsonpCallback = originalSettings.jsonpCallback; + + // save the callback name for future use + oldCallbacks.push( callbackName ); + } + + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( overwritten ) ) { + overwritten( responseContainer[ 0 ] ); + } + + responseContainer = overwritten = undefined; + }); + + // Delegate to script + return "script"; + } +}); +// Install script dataType +jQuery.ajaxSetup({ + accepts: { + script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /javascript|ecmascript/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +}); + +// Handle cache's special case and global +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + s.global = false; + } +}); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function(s) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + + var script, + head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; + + return { + + send: function( _, callback ) { + + script = document.createElement( "script" ); + + script.async = "async"; + + if ( s.scriptCharset ) { + script.charset = s.scriptCharset; + } + + script.src = s.url; + + // Attach handlers for all browsers + script.onload = script.onreadystatechange = function( _, isAbort ) { + + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { + + // Handle memory leak in IE + script.onload = script.onreadystatechange = null; + + // Remove the script + if ( head && script.parentNode ) { + head.removeChild( script ); + } + + // Dereference the script + script = undefined; + + // Callback if not abort + if ( !isAbort ) { + callback( 200, "success" ); + } + } + }; + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709 and #4378). + head.insertBefore( script, head.firstChild ); + }, + + abort: function() { + if ( script ) { + script.onload( 0, 1 ); + } + } + }; + } +}); +var xhrCallbacks, + // #5280: Internet Explorer will keep connections alive if we don't abort on unload + xhrOnUnloadAbort = window.ActiveXObject ? function() { + // Abort all pending requests + for ( var key in xhrCallbacks ) { + xhrCallbacks[ key ]( 0, 1 ); + } + } : false, + xhrId = 0; + +// Functions to create xhrs +function createStandardXHR() { + try { + return new window.XMLHttpRequest(); + } catch( e ) {} +} + +function createActiveXHR() { + try { + return new window.ActiveXObject( "Microsoft.XMLHTTP" ); + } catch( e ) {} +} + +// Create the request object +// (This is still attached to ajaxSettings for backward compatibility) +jQuery.ajaxSettings.xhr = window.ActiveXObject ? + /* Microsoft failed to properly + * implement the XMLHttpRequest in IE7 (can't request local files), + * so we use the ActiveXObject when it is available + * Additionally XMLHttpRequest can be disabled in IE7/IE8 so + * we need a fallback. + */ + function() { + return !this.isLocal && createStandardXHR() || createActiveXHR(); + } : + // For all other browsers, use the standard XMLHttpRequest object + createStandardXHR; + +// Determine support properties +(function( xhr ) { + jQuery.extend( jQuery.support, { + ajax: !!xhr, + cors: !!xhr && ( "withCredentials" in xhr ) + }); +})( jQuery.ajaxSettings.xhr() ); + +// Create transport if the browser can provide an xhr +if ( jQuery.support.ajax ) { + + jQuery.ajaxTransport(function( s ) { + // Cross domain only allowed if supported through XMLHttpRequest + if ( !s.crossDomain || jQuery.support.cors ) { + + var callback; + + return { + send: function( headers, complete ) { + + // Get a new xhr + var handle, i, + xhr = s.xhr(); + + // Open the socket + // Passing null username, generates a login popup on Opera (#2865) + if ( s.username ) { + xhr.open( s.type, s.url, s.async, s.username, s.password ); + } else { + xhr.open( s.type, s.url, s.async ); + } + + // Apply custom fields if provided + if ( s.xhrFields ) { + for ( i in s.xhrFields ) { + xhr[ i ] = s.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( s.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( s.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !s.crossDomain && !headers["X-Requested-With"] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Need an extra try/catch for cross domain requests in Firefox 3 + try { + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + } catch( _ ) {} + + // Do send the request + // This may raise an exception which is actually + // handled in jQuery.ajax (so no try/catch here) + xhr.send( ( s.hasContent && s.data ) || null ); + + // Listener + callback = function( _, isAbort ) { + + var status, + statusText, + responseHeaders, + responses, + xml; + + // Firefox throws exceptions when accessing properties + // of an xhr when a network error occurred + // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) + try { + + // Was never called and is aborted or complete + if ( callback && ( isAbort || xhr.readyState === 4 ) ) { + + // Only called once + callback = undefined; + + // Do not keep as active anymore + if ( handle ) { + xhr.onreadystatechange = jQuery.noop; + if ( xhrOnUnloadAbort ) { + delete xhrCallbacks[ handle ]; + } + } + + // If it's an abort + if ( isAbort ) { + // Abort it manually if needed + if ( xhr.readyState !== 4 ) { + xhr.abort(); + } + } else { + status = xhr.status; + responseHeaders = xhr.getAllResponseHeaders(); + responses = {}; + xml = xhr.responseXML; + + // Construct response list + if ( xml && xml.documentElement /* #4958 */ ) { + responses.xml = xml; + } + + // When requesting binary data, IE6-9 will throw an exception + // on any attempt to access responseText (#11426) + try { + responses.text = xhr.responseText; + } catch( e ) { + } + + // Firefox throws an exception when accessing + // statusText for faulty cross-domain requests + try { + statusText = xhr.statusText; + } catch( e ) { + // We normalize with Webkit giving an empty statusText + statusText = ""; + } + + // Filter status for non standard behaviors + + // If the request is local and we have data: assume a success + // (success with no data won't get notified, that's the best we + // can do given current implementations) + if ( !status && s.isLocal && !s.crossDomain ) { + status = responses.text ? 200 : 404; + // IE - #1450: sometimes returns 1223 when it should be 204 + } else if ( status === 1223 ) { + status = 204; + } + } + } + } catch( firefoxAccessException ) { + if ( !isAbort ) { + complete( -1, firefoxAccessException ); + } + } + + // Call complete if needed + if ( responses ) { + complete( status, statusText, responses, responseHeaders ); + } + }; + + if ( !s.async ) { + // if we're in sync mode we fire the callback + callback(); + } else if ( xhr.readyState === 4 ) { + // (IE6 & IE7) if it's in cache and has been + // retrieved directly we need to fire the callback + setTimeout( callback, 0 ); + } else { + handle = ++xhrId; + if ( xhrOnUnloadAbort ) { + // Create the active xhrs callbacks list if needed + // and attach the unload handler + if ( !xhrCallbacks ) { + xhrCallbacks = {}; + jQuery( window ).unload( xhrOnUnloadAbort ); + } + // Add to list of active xhrs callbacks + xhrCallbacks[ handle ] = callback; + } + xhr.onreadystatechange = callback; + } + }, + + abort: function() { + if ( callback ) { + callback(0,1); + } + } + }; + } + }); +} +var fxNow, timerId, + rfxtypes = /^(?:toggle|show|hide)$/, + rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), + rrun = /queueHooks$/, + animationPrefilters = [ defaultPrefilter ], + tweeners = { + "*": [function( prop, value ) { + var end, unit, + tween = this.createTween( prop, value ), + parts = rfxnum.exec( value ), + target = tween.cur(), + start = +target || 0, + scale = 1, + maxIterations = 20; + + if ( parts ) { + end = +parts[2]; + unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + + // We need to compute starting value + if ( unit !== "px" && start ) { + // Iteratively approximate from a nonzero starting point + // Prefer the current property, because this process will be trivial if it uses the same units + // Fallback to end or a simple constant + start = jQuery.css( tween.elem, prop, true ) || end || 1; + + do { + // If previous iteration zeroed out, double until we get *something* + // Use a string for doubling factor so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + start = start / scale; + jQuery.style( tween.elem, prop, start + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // And breaking the loop if scale is unchanged or perfect, or if we've just had enough + } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations ); + } + + tween.unit = unit; + tween.start = start; + // If a +=/-= token was provided, we're doing a relative animation + tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; + } + return tween; + }] + }; + +// Animations created synchronously will run synchronously +function createFxNow() { + setTimeout(function() { + fxNow = undefined; + }, 0 ); + return ( fxNow = jQuery.now() ); +} + +function createTweens( animation, props ) { + jQuery.each( props, function( prop, value ) { + var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( collection[ index ].call( animation, prop, value ) ) { + + // we're done with this property + return; + } + } + }); +} + +function Animation( elem, properties, options ) { + var result, + index = 0, + tweenerIndex = 0, + length = animationPrefilters.length, + deferred = jQuery.Deferred().always( function() { + // don't match elem in the :animated selector + delete tick.elem; + }), + tick = function() { + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length ; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ]); + + if ( percent < 1 && length ) { + return remaining; + } else { + deferred.resolveWith( elem, [ animation ] ); + return false; + } + }, + animation = deferred.promise({ + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { specialEasing: {} }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end, easing ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + // if we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + + for ( ; index < length ; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // resolve when we played the last frame + // otherwise, reject + if ( gotoEnd ) { + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + }), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length ; index++ ) { + result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + return result; + } + } + + createTweens( animation, props ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + jQuery.fx.timer( + jQuery.extend( tick, { + anim: animation, + queue: animation.opts.queue, + elem: elem + }) + ); + + // attach callbacks from options + return animation.progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( jQuery.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // not quite $.extend, this wont overwrite keys already present. + // also - reusing 'index' from above because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.split(" "); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length ; index++ ) { + prop = props[ index ]; + tweeners[ prop ] = tweeners[ prop ] || []; + tweeners[ prop ].unshift( callback ); + } + }, + + prefilter: function( callback, prepend ) { + if ( prepend ) { + animationPrefilters.unshift( callback ); + } else { + animationPrefilters.push( callback ); + } + } +}); + +function defaultPrefilter( elem, props, opts ) { + var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire, + anim = this, + style = elem.style, + orig = {}, + handled = [], + hidden = elem.nodeType && isHidden( elem ); + + // handle queue: false promises + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always(function() { + // doing this makes sure that the complete handler will be called + // before this completes + anim.always(function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + }); + }); + } + + // height/width overflow pass + if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { + // Make sure that nothing sneaks out + // Record all 3 overflow attributes because IE does not + // change the overflow attribute when overflowX and + // overflowY are set to the same value + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Set display property to inline-block for height/width + // animations on inline elements that are having width/height animated + if ( jQuery.css( elem, "display" ) === "inline" && + jQuery.css( elem, "float" ) === "none" ) { + + // inline-level elements accept inline-block; + // block-level elements need to be inline with layout + if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { + style.display = "inline-block"; + + } else { + style.zoom = 1; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + if ( !jQuery.support.shrinkWrapBlocks ) { + anim.done(function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + }); + } + } + + + // show/hide pass + for ( index in props ) { + value = props[ index ]; + if ( rfxtypes.exec( value ) ) { + delete props[ index ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + continue; + } + handled.push( index ); + } + } + + length = handled.length; + if ( length ) { + dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + + // store state if its toggle - enables .stop().toggle() to "reverse" + if ( toggle ) { + dataShow.hidden = !hidden; + } + if ( hidden ) { + jQuery( elem ).show(); + } else { + anim.done(function() { + jQuery( elem ).hide(); + }); + } + anim.done(function() { + var prop; + jQuery.removeData( elem, "fxshow", true ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + }); + for ( index = 0 ; index < length ; index++ ) { + prop = handled[ index ]; + tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); + orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); + + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = tween.start; + if ( hidden ) { + tween.end = tween.start; + tween.start = prop === "width" || prop === "height" ? 1 : 0; + } + } + } + } +} + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || "swing"; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + if ( tween.elem[ tween.prop ] != null && + (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { + return tween.elem[ tween.prop ]; + } + + // passing any value as a 4th parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails + // so, simple values such as "10px" are parsed to Float. + // complex values such as "rotate(1rad)" are returned as is. + result = jQuery.css( tween.elem, tween.prop, false, "" ); + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + // use step hook for back compat - use cssHook if its there - use .style if its + // available and use plain properties where available + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Remove in 2.0 - this supports IE8's panic based approach +// to setting things on disconnected nodes + +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" || + // special check for .toggle( handler, handler, ... ) + ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +}); + +jQuery.fn.extend({ + fadeTo: function( speed, to, easing, callback ) { + + // show any hidden elements after setting opacity to 0 + return this.filter( isHidden ).css( "opacity", 0 ).show() + + // animate to the value specified + .end().animate({ opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations resolve immediately + if ( empty ) { + anim.stop( true ); + } + }; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each(function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = jQuery._data( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // start the next in the queue if the last step wasn't forced + // timers currently will call their complete callbacks, which will dequeue + // but only if they were gotoEnd + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + }); + } +}); + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + attrs = { height: type }, + i = 0; + + // if we include width, step value is 1 to do all cssExpand values, + // if we don't include width, step value is 2 to skip over Left and Right + includeWidth = includeWidth? 1 : 0; + for( ; i < 4 ; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +// Generate shortcuts for custom animations +jQuery.each({ + slideDown: genFx("show"), + slideUp: genFx("hide"), + slideToggle: genFx("toggle"), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +}); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : + opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; + + // normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p*Math.PI ) / 2; + } +}; + +jQuery.timers = []; +jQuery.fx = Tween.prototype.init; +jQuery.fx.tick = function() { + var timer, + timers = jQuery.timers, + i = 0; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + // Checks the timer has not already been removed + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + if ( timer() && jQuery.timers.push( timer ) && !timerId ) { + timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); + } +}; + +jQuery.fx.interval = 13; + +jQuery.fx.stop = function() { + clearInterval( timerId ); + timerId = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + // Default speed + _default: 400 +}; + +// Back Compat <1.8 extension point +jQuery.fx.step = {}; + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.animated = function( elem ) { + return jQuery.grep(jQuery.timers, function( fn ) { + return elem === fn.elem; + }).length; + }; +} +var rroot = /^(?:body|html)$/i; + +jQuery.fn.offset = function( options ) { + if ( arguments.length ) { + return options === undefined ? + this : + this.each(function( i ) { + jQuery.offset.setOffset( this, options, i ); + }); + } + + var docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, + box = { top: 0, left: 0 }, + elem = this[ 0 ], + doc = elem && elem.ownerDocument; + + if ( !doc ) { + return; + } + + if ( (body = doc.body) === elem ) { + return jQuery.offset.bodyOffset( elem ); + } + + docElem = doc.documentElement; + + // Make sure it's not a disconnected DOM node + if ( !jQuery.contains( docElem, elem ) ) { + return box; + } + + // If we don't have gBCR, just use 0,0 rather than error + // BlackBerry 5, iOS 3 (original iPhone) + if ( typeof elem.getBoundingClientRect !== "undefined" ) { + box = elem.getBoundingClientRect(); + } + win = getWindow( doc ); + clientTop = docElem.clientTop || body.clientTop || 0; + clientLeft = docElem.clientLeft || body.clientLeft || 0; + scrollTop = win.pageYOffset || docElem.scrollTop; + scrollLeft = win.pageXOffset || docElem.scrollLeft; + return { + top: box.top + scrollTop - clientTop, + left: box.left + scrollLeft - clientLeft + }; +}; + +jQuery.offset = { + + bodyOffset: function( body ) { + var top = body.offsetTop, + left = body.offsetLeft; + + if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { + top += parseFloat( jQuery.css(body, "marginTop") ) || 0; + left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; + } + + return { top: top, left: left }; + }, + + setOffset: function( elem, options, i ) { + var position = jQuery.css( elem, "position" ); + + // set position first, in-case top/left are set even on static elem + if ( position === "static" ) { + elem.style.position = "relative"; + } + + var curElem = jQuery( elem ), + curOffset = curElem.offset(), + curCSSTop = jQuery.css( elem, "top" ), + curCSSLeft = jQuery.css( elem, "left" ), + calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, + props = {}, curPosition = {}, curTop, curLeft; + + // need to be able to calculate position if either top or left is auto and position is either absolute or fixed + if ( calculatePosition ) { + curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; + } + + if ( jQuery.isFunction( options ) ) { + options = options.call( elem, i, curOffset ); + } + + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; + } + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; + } + + if ( "using" in options ) { + options.using.call( elem, props ); + } else { + curElem.css( props ); + } + } +}; + + +jQuery.fn.extend({ + + position: function() { + if ( !this[0] ) { + return; + } + + var elem = this[0], + + // Get *real* offsetParent + offsetParent = this.offsetParent(), + + // Get correct offsets + offset = this.offset(), + parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; + offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; + + // Add offsetParent borders + parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; + parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + }; + }, + + offsetParent: function() { + return this.map(function() { + var offsetParent = this.offsetParent || document.body; + while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || document.body; + }); + } +}); + + +// Create scrollLeft and scrollTop methods +jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { + var top = /Y/.test( prop ); + + jQuery.fn[ method ] = function( val ) { + return jQuery.access( this, function( elem, method, val ) { + var win = getWindow( elem ); + + if ( val === undefined ) { + return win ? (prop in win) ? win[ prop ] : + win.document.documentElement[ method ] : + elem[ method ]; + } + + if ( win ) { + win.scrollTo( + !top ? val : jQuery( win ).scrollLeft(), + top ? val : jQuery( win ).scrollTop() + ); + + } else { + elem[ method ] = val; + } + }, method, val, arguments.length, null ); + }; +}); + +function getWindow( elem ) { + return jQuery.isWindow( elem ) ? + elem : + elem.nodeType === 9 ? + elem.defaultView || elem.parentWindow : + false; +} +// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods +jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { + jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { + // margin is only for outerHeight, outerWidth + jQuery.fn[ funcName ] = function( margin, value ) { + var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), + extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); + + return jQuery.access( this, function( elem, type, value ) { + var doc; + + if ( jQuery.isWindow( elem ) ) { + // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there + // isn't a whole lot we can do. See pull request at this URL for discussion: + // https://github.com/jquery/jquery/pull/764 + return elem.document.documentElement[ "client" + name ]; + } + + // Get document width or height + if ( elem.nodeType === 9 ) { + doc = elem.documentElement; + + // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest + // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. + return Math.max( + elem.body[ "scroll" + name ], doc[ "scroll" + name ], + elem.body[ "offset" + name ], doc[ "offset" + name ], + doc[ "client" + name ] + ); + } + + return value === undefined ? + // Get width or height on the element, requesting but not forcing parseFloat + jQuery.css( elem, type, value, extra ) : + + // Set width or height on the element + jQuery.style( elem, type, value, extra ); + }, type, chainable ? margin : undefined, chainable, null ); + }; + }); +}); +// Expose jQuery to the global object +window.jQuery = window.$ = jQuery; + +// Expose jQuery as an AMD module, but only for AMD loaders that +// understand the issues with loading multiple versions of jQuery +// in a page that all might call define(). The loader will indicate +// they have special allowances for multiple jQuery versions by +// specifying define.amd.jQuery = true. Register as a named module, +// since jQuery can be concatenated with other files that may use define, +// but not use a proper concatenation script that understands anonymous +// AMD modules. A named AMD is safest and most robust way to register. +// Lowercase jquery is used because AMD module names are derived from +// file names, and jQuery is normally delivered in a lowercase file name. +// Do this after creating the global so that if an AMD module wants to call +// noConflict to hide this version of jQuery, it will work. +if ( typeof define === "function" && define.amd && define.amd.jQuery ) { + define( "jquery", [], function () { return jQuery; } ); +} + +})( window ); diff --git a/emoncms/Lib/flot/jquery.min.js b/emoncms/Lib/flot/jquery.min.js new file mode 100644 index 0000000..83589da --- /dev/null +++ b/emoncms/Lib/flot/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/emoncms/Lib/jquery-1.9.0.min.js b/emoncms/Lib/jquery-1.9.0.min.js new file mode 100644 index 0000000..50d1b22 --- /dev/null +++ b/emoncms/Lib/jquery-1.9.0.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.9.0 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license */(function(e,t){"use strict";function n(e){var t=e.length,n=st.type(e);return st.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}function r(e){var t=Tt[e]={};return st.each(e.match(lt)||[],function(e,n){t[n]=!0}),t}function i(e,n,r,i){if(st.acceptData(e)){var o,a,s=st.expando,u="string"==typeof n,l=e.nodeType,c=l?st.cache:e,f=l?e[s]:e[s]&&s;if(f&&c[f]&&(i||c[f].data)||!u||r!==t)return f||(l?e[s]=f=K.pop()||st.guid++:f=s),c[f]||(c[f]={},l||(c[f].toJSON=st.noop)),("object"==typeof n||"function"==typeof n)&&(i?c[f]=st.extend(c[f],n):c[f].data=st.extend(c[f].data,n)),o=c[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[st.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[st.camelCase(n)])):a=o,a}}function o(e,t,n){if(st.acceptData(e)){var r,i,o,a=e.nodeType,u=a?st.cache:e,l=a?e[st.expando]:st.expando;if(u[l]){if(t&&(r=n?u[l]:u[l].data)){st.isArray(t)?t=t.concat(st.map(t,st.camelCase)):t in r?t=[t]:(t=st.camelCase(t),t=t in r?[t]:t.split(" "));for(i=0,o=t.length;o>i;i++)delete r[t[i]];if(!(n?s:st.isEmptyObject)(r))return}(n||(delete u[l].data,s(u[l])))&&(a?st.cleanData([e],!0):st.support.deleteExpando||u!=u.window?delete u[l]:u[l]=null)}}}function a(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(Nt,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:wt.test(r)?st.parseJSON(r):r}catch(o){}st.data(e,n,r)}else r=t}return r}function s(e){var t;for(t in e)if(("data"!==t||!st.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function u(){return!0}function l(){return!1}function c(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function f(e,t,n){if(t=t||0,st.isFunction(t))return st.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return st.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=st.grep(e,function(e){return 1===e.nodeType});if(Wt.test(t))return st.filter(t,r,!n);t=st.filter(t,r)}return st.grep(e,function(e){return st.inArray(e,t)>=0===n})}function p(e){var t=zt.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function d(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function h(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function g(e){var t=nn.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function m(e,t){for(var n,r=0;null!=(n=e[r]);r++)st._data(n,"globalEval",!t||st._data(t[r],"globalEval"))}function y(e,t){if(1===t.nodeType&&st.hasData(e)){var n,r,i,o=st._data(e),a=st._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)st.event.add(t,n,s[n][r])}a.data&&(a.data=st.extend({},a.data))}}function v(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!st.support.noCloneEvent&&t[st.expando]){r=st._data(t);for(i in r.events)st.removeEvent(t,i,r.handle);t.removeAttribute(st.expando)}"script"===n&&t.text!==e.text?(h(t).text=e.text,g(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),st.support.html5Clone&&e.innerHTML&&!st.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Zt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}function b(e,n){var r,i,o=0,a=e.getElementsByTagName!==t?e.getElementsByTagName(n||"*"):e.querySelectorAll!==t?e.querySelectorAll(n||"*"):t;if(!a)for(a=[],r=e.childNodes||e;null!=(i=r[o]);o++)!n||st.nodeName(i,n)?a.push(i):st.merge(a,b(i,n));return n===t||n&&st.nodeName(e,n)?st.merge([e],a):a}function x(e){Zt.test(e.type)&&(e.defaultChecked=e.checked)}function T(e,t){if(t in e)return t;for(var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Nn.length;i--;)if(t=Nn[i]+n,t in e)return t;return r}function w(e,t){return e=t||e,"none"===st.css(e,"display")||!st.contains(e.ownerDocument,e)}function N(e,t){for(var n,r=[],i=0,o=e.length;o>i;i++)n=e[i],n.style&&(r[i]=st._data(n,"olddisplay"),t?(r[i]||"none"!==n.style.display||(n.style.display=""),""===n.style.display&&w(n)&&(r[i]=st._data(n,"olddisplay",S(n.nodeName)))):r[i]||w(n)||st._data(n,"olddisplay",st.css(n,"display")));for(i=0;o>i;i++)n=e[i],n.style&&(t&&"none"!==n.style.display&&""!==n.style.display||(n.style.display=t?r[i]||"":"none"));return e}function C(e,t,n){var r=mn.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function k(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;4>o;o+=2)"margin"===n&&(a+=st.css(e,n+wn[o],!0,i)),r?("content"===n&&(a-=st.css(e,"padding"+wn[o],!0,i)),"margin"!==n&&(a-=st.css(e,"border"+wn[o]+"Width",!0,i))):(a+=st.css(e,"padding"+wn[o],!0,i),"padding"!==n&&(a+=st.css(e,"border"+wn[o]+"Width",!0,i)));return a}function E(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=ln(e),a=st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=un(e,t,o),(0>i||null==i)&&(i=e.style[t]),yn.test(i))return i;r=a&&(st.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+k(e,t,n||(a?"border":"content"),r,o)+"px"}function S(e){var t=V,n=bn[e];return n||(n=A(e,t),"none"!==n&&n||(cn=(cn||st("'); + + if (publicfeed == 1) $("#embedcode").val(''); else $("#embedcode").val('\n\n\n\n'); + + }); + + $("#fullscreen").click(function(){ + var visurl = ""; + var vistype = $("#visselect").val(); + + // Added in custom action for multigraph + // if the vis type is multigraph then we construct + // the visurl with multigraph?id=1 + if (vistype=="multigraph") + { + visurl = "multigraph?mid="+multigraph_id; + } + else + { + visurl += path+"vis/"+vistype; + var options = []; + $(".options").each(function() { + if ($(this).val()) + { + options.push($(this).attr("id")+"="+$(this).val()); + } + }); + } + if (options) visurl += "?"+options.join("&"); + $(window.location).attr('href',visurl); + }); + + function draw_options(box_options) + { + // Build options table html + var options_html = "
"; + for (z in box_options) + { + options_html += ""; + + var type = box_options[z][1]; + + if (type == 0 || type == 1 || type == 2 || type == 3) + { + options_html += ""; + } + else + { + options_html += ""; + } + options_html += ""; + } + options_html += "
"+box_options[z][0]+":"+select_feed(box_options[z][0], feedlist, type)+"
"; + $("#box-options").html(options_html); + } + + // Create a drop down select box with a list of feeds. + function select_feed(id, feedlist, type) + { + var out = ""; + return out; + } + + vis_resize(); + $(window).resize(function(){vis_resize();}); + + function vis_resize() + { + var viswidth = $("#vispage").width() - 340; + var visheight = viswidth * (3/4); + + $("#vis_bound").width(viswidth); + $("#vis_bound").height(visheight); + $("#visiframe").width(viswidth); + $("#visiframe").height(visheight); + } + + diff --git a/emoncms/Modules/vis/vis_menu.php b/emoncms/Modules/vis/vis_menu.php new file mode 100644 index 0000000..cbe16b8 --- /dev/null +++ b/emoncms/Modules/vis/vis_menu.php @@ -0,0 +1,7 @@ + dgettext($domain, "Vis"), 'path'=>"vis/list" , 'session'=>"write", 'order' => 3 ); \ No newline at end of file diff --git a/emoncms/Modules/vis/vis_object.php b/emoncms/Modules/vis/vis_object.php new file mode 100644 index 0000000..94403bf --- /dev/null +++ b/emoncms/Modules/vis/vis_object.php @@ -0,0 +1,45 @@ + array('options'=>array( + array('feedid',1)) + ), + + // Hex colour EDC240 is the default color for flot. since we want existing setups to not change, we set the default value to it manually now, + 'rawdata'=> array('options'=>array( + array('feedid',1), + array('fill',7,0), + array('colour',5,'EDC240'), + array('units',5,'W'), + array('dp',7,'1'), + array('scale',6,'1')) + ), + + 'bargraph'=> array('options'=>array( + array('feedid',0), + array('colour',5,'EDC240'), + array('interval',7,'86400'), + array('units',5,''), + array('dp',7,'1'), + array('scale',6,'1'), + array('delta',7,'0')) + ), + + 'multigraph' => array ('action'=>'multigraph', 'options'=>array(array('mid',7)) ), + + 'graph'=> array('options'=>array( + array('feedid',1) + )) + ); diff --git a/emoncms/Modules/vis/vis_schema.php b/emoncms/Modules/vis/vis_schema.php new file mode 100644 index 0000000..dce6eb5 --- /dev/null +++ b/emoncms/Modules/vis/vis_schema.php @@ -0,0 +1,8 @@ + array('type' => 'int(11)', 'Null'=>'NO', 'Key'=>'PRI', 'Extra'=>'auto_increment'), + 'name' => array('type' => 'text'), + 'userid' => array('type' => 'int(11)'), + 'feedlist' => array('type' => 'text') +); \ No newline at end of file diff --git a/emoncms/Modules/vis/visualisations/bargraph.php b/emoncms/Modules/vis/visualisations/bargraph.php new file mode 100644 index 0000000..a5d567f --- /dev/null +++ b/emoncms/Modules/vis/visualisations/bargraph.php @@ -0,0 +1,374 @@ + + + + + + + + + + +
+ +
+
+
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + +
+ +
+ +

+
+ + + diff --git a/emoncms/Modules/vis/visualisations/graph.js b/emoncms/Modules/vis/visualisations/graph.js new file mode 100644 index 0000000..4dc618e --- /dev/null +++ b/emoncms/Modules/vis/visualisations/graph.js @@ -0,0 +1,282 @@ +var app_graph = { + + feedname: 0, + + start:0, + end:0, + interval:0, + npoints:600, + skipmissing:1, + limitinterval:1, + showcsv:0, + data:[], + + mean: 0, + stdev: 0, + minval: 0, + maxval: 0, + + // Include required javascript libraries + include: [ + "static/flot/jquery.flot.min.js", + "static/flot/jquery.flot.time.min.js", + "static/flot/jquery.flot.selection.min.js", + "static/vis.helper.js", + "static/flot/date.format.js" + ], + + init: function() + { + var timeWindow = (3600000*24.0*7); + var now = Math.round(+new Date * 0.001)*1000; + app_graph.start = now - timeWindow; + app_graph.end = now; + app_graph.calc_interval(); + + $("#graph_zoomout").click(function () {app_graph.zoomout(); app_graph.draw();}); + $("#graph_zoomin").click(function () {app_graph.zoomin(); app_graph.draw();}); + $('#graph_right').click(function () {app_graph.panright(); app_graph.draw();}); + $('#graph_left').click(function () {app_graph.panleft(); app_graph.draw();}); + $('.graph_time').click(function () { + app_graph.timewindow($(this).attr("time")); app_graph.draw(); + }); + + $('#placeholder').bind("plotselected", function (event, ranges) + { + app_graph.start = ranges.xaxis.from; + app_graph.end = ranges.xaxis.to; + app_graph.calc_interval(); + + app_graph.draw(); + }); + + $("#resend").click(function(){ + app_graph.start = $("#request-start").val()*1000; + app_graph.end = $("#request-end").val()*1000; + app_graph.interval = $("#request-interval").val(); + app_graph.skipmissing = $("#request-skipmissing")[0].checked*1; + app_graph.limitinterval = $("#request-limitinterval")[0].checked*1; + + app_graph.draw(); + }); + + $("#showcsv").click(function(){ + if ($("#showcsv").html()=="Show CSV Output") { + app_graph.printcsv() + $("#csv").show(); + app_graph.showcsv = 1; + $("#showcsv").html("Hide CSV Output"); + } else { + app_graph.showcsv = 0; + $("#csv").hide(); + $("#showcsv").html("Show CSV Output"); + } + }); + }, + + show: function() + { + var top_offset = 0; + var placeholder_bound = $('#placeholder_bound'); + var placeholder = $('#placeholder'); + + var width = placeholder_bound.width(); + var height = width * 0.5; + + placeholder.width(width); + placeholder_bound.height(height); + placeholder.height(height-top_offset); + + app_graph.draw(); + + $("#info").show(); + }, + + hide: function() + { + + }, + + draw: function() + { + + var request = path+"feed/data.json?id="+app_graph.feedname+"&start="+app_graph.start+"&end="+app_graph.end+"&interval="+app_graph.interval+"&skipmissing="+app_graph.skipmissing+"&limitinterval="+app_graph.limitinterval; + + $("#request-start").val(app_graph.start/1000); + $("#request-end").val(app_graph.end/1000); + $("#request-interval").val(app_graph.interval); + $("#request-skipmissing").attr("checked",app_graph.skipmissing); + $("#request-limitinterval").attr("checked",app_graph.limitinterval); + $("#request-url").html(request); + $("#request-url").attr("href",request); + + $.ajax({ + url: request, + async: false, + dataType: "text", + success: function(data_in) { + + // 1) Check validity of json data, or show error + var valid = true; + try { + app_graph.data = JSON.parse(data_in); + if (app_graph.data.success!=undefined) valid = false; + + $("#error").hide(); + } catch (e) { + valid = false; + } + + // 2) If valid + if (!valid) + { + $("#error").html("
Request error "+data_in+"
").show(); + } + else + { + var options = { + lines: { fill: true }, + xaxis: { + mode: "time", timezone: "browser", + min: app_graph.start, max: app_graph.end + }, + grid: {hoverable: true, clickable: true}, + selection: { mode: "x" } + } + + $.plot($('#placeholder'), [{data:app_graph.data}], options); + + if (app_graph.showcsv) app_graph.printcsv(); + + app_graph.stats(); + dp = 1; + units = ""; + $("#stats-mean").html(app_graph.mean.toFixed(dp)+units); + $("#stats-max").html(app_graph.maxval.toFixed(dp)+units); + $("#stats-min").html(app_graph.minval.toFixed(dp)+units); + $("#stats-stdev").html(app_graph.stdev.toFixed(dp)+units); + $("#stats-npoints").html(app_graph.data.length); + } + } + }); + }, + + printcsv: function() + { + var csvout = ""; + var start_time = app_graph.data[0][0]; + for (z in app_graph.data) { + csvout += Math.round((app_graph.data[z][0]-start_time)/1000)+", "+app_graph.data[z][1]+"\n"; + } + $("#csv").val(csvout); + }, + + // View functions + + 'zoomout':function () + { + var time_window = app_graph.end - app_graph.start; + var middle = app_graph.start + time_window / 2; + time_window = time_window * 2; + app_graph.start = middle - (time_window/2); + app_graph.end = middle + (time_window/2); + app_graph.calc_interval(); + }, + + 'zoomin':function () + { + var time_window = app_graph.end - app_graph.start; + var middle = app_graph.start + time_window / 2; + time_window = time_window * 0.5; + app_graph.start = middle - (time_window/2); + app_graph.end = middle + (time_window/2); + app_graph.calc_interval(); + }, + + 'panright':function () + { + var time_window = app_graph.end - app_graph.start; + var shiftsize = time_window * 0.2; + app_graph.start += shiftsize; + app_graph.end += shiftsize; + app_graph.calc_interval(); + }, + + 'panleft':function () + { + var time_window = app_graph.end - app_graph.start; + var shiftsize = time_window * 0.2; + app_graph.start -= shiftsize; + app_graph.end -= shiftsize; + app_graph.calc_interval(); + }, + + 'timewindow':function(time) + { + app_graph.start = ((new Date()).getTime())-(3600000*24*time); //Get start time + app_graph.end = (new Date()).getTime(); //Get end time + app_graph.calc_interval(); + }, + + 'calc_interval':function() + { + var interval = Math.round(((app_graph.end - app_graph.start)/app_graph.npoints)/1000); + + var outinterval = 5; + if (interval>10) outinterval = 10; + if (interval>15) outinterval = 15; + if (interval>20) outinterval = 20; + if (interval>30) outinterval = 30; + if (interval>60) outinterval = 60; + if (interval>120) outinterval = 120; + if (interval>180) outinterval = 180; + if (interval>300) outinterval = 300; + if (interval>600) outinterval = 600; + if (interval>900) outinterval = 900; + if (interval>1200) outinterval = 1200; + if (interval>1800) outinterval = 1800; + if (interval>3600*1) outinterval = 3600*1; + if (interval>3600*2) outinterval = 3600*2; + if (interval>3600*3) outinterval = 3600*3; + if (interval>3600*4) outinterval = 3600*4; + if (interval>3600*5) outinterval = 3600*5; + if (interval>3600*6) outinterval = 3600*6; + if (interval>3600*12) outinterval = 3600*12; + if (interval>3600*24) outinterval = 3600*24; + + app_graph.interval = outinterval; + + app_graph.start = Math.floor((app_graph.start/1000) / outinterval) * outinterval * 1000; + app_graph.end = Math.ceil((app_graph.end/1000) / outinterval) * outinterval * 1000; + }, + + 'stats':function() + { + var sum = 0, i=0; + app_graph.minval = 0; + app_graph.maxval = 0; + for (z in app_graph.data) + { + var val = app_graph.data[z][1]; + if (val!=null) + { + if (i==0) { + app_graph.maxval = val; + app_graph.minval = val; + } + if (val>app_graph.maxval) app_graph.maxval = val; + if (val + + + + + + + + + + +

Data viewer

+ + + +
+ + + + + + + + +
+ +
+
+
+ + + + diff --git a/emoncms/Modules/vis/visualisations/multigraph.js b/emoncms/Modules/vis/visualisations/multigraph.js new file mode 100644 index 0000000..8b3e46f --- /dev/null +++ b/emoncms/Modules/vis/visualisations/multigraph.js @@ -0,0 +1,211 @@ + var plotdata = []; + var timeWindowChanged = 0; + var multigraph_editmode = false; + + function convert_to_plotlist(multigraph_feedlist) + { + var plotlist = []; + for (z in multigraph_feedlist) + { + plotlist[z] = { + id: multigraph_feedlist[z]['id'], + selected: 1, + plot: + { + data: null, + label: multigraph_feedlist[z]['name'], + lines: + { + show: true, + fill: multigraph_feedlist[z]['fill'] + } + } + }; + + if (multigraph_feedlist[z]['left']==true) + { + plotlist[z].plot.yaxis = 1; + } + else if (multigraph_feedlist[z]['right']==true) + { + plotlist[z].plot.yaxis = 2; + } + else + { + console.log("ERROR: Unknown plot alignment! Alignment setting: ", multigraph_feedlist[z]['right']); + } + + // Only set the plotcolour variable if we have a value to set it with + if (multigraph_feedlist[z]["lineColour"]) + { + // Some browsers really want the leading "#". It works without in chrome, not in IE and opera. + // What the hell, people? + if (multigraph_feedlist[z]["lineColour"].indexOf("#") == -1) + { + plotlist[z].plot.color = "#" + multigraph_feedlist[z]["lineColour"]; + } + else + { + plotlist[z].plot.color = multigraph_feedlist[z]["lineColour"]; + } + } + + + if (multigraph_feedlist[z]['left']==false && multigraph_feedlist[z]['right']==false) + { + plotlist[z].selected = 0; + } + + } + return plotlist; + } + + /* + + Handle_feeds + + For all feeds in the plotlist: + - remove all plot data if the time window has changed + - if the feed is selected load new data + - add the feed to the multigraph plot + - plot the multigraph + + */ + function vis_feed_data() + { + var plotlist = convert_to_plotlist(multigraph_feedlist); + console.log(plotlist); + plotdata = []; + for(var i in plotlist) { + if (timeWindowChanged) + { + plotlist[i].plot.data = null; + } + if (plotlist[i].selected) { + if (!plotlist[i].plot.data) + { + + var npoints = 800; + interval = Math.round(((view.end - view.start)/npoints)/1000); + + $.ajax({ + url: path+'feed/data.json', + data: "id="+plotlist[i].id+"&start="+view.start+"&end="+view.end+"&interval="+interval, + dataType: 'json', + async: false, + success: function(data_in) { plotlist[i].plot.data = data_in; } + }); + } + + if ( plotlist[i].plot.data) + { + plotdata.push(plotlist[i].plot); + } + } + } + + plot(); + + timeWindowChanged=0; + + if (multigraph_editmode==true) + { + //update_multigraph_feedlist(); + } + } + + function plot() + { + $.plot($("#graph"), plotdata, { + grid: { show: true, hoverable: true, clickable: true }, + xaxis: { mode: "time", timezone: "browser", min: view.start, max: view.end }, + selection: { mode: "x" }, + legend: { position: "nw"} + }); + } + +function multigraph_init(element) +{ + // Get start and end time of multigraph view + // end time and timewindow is stored in the first multigraph_feedlist item. + // start time is calculated from end - timewindow + + var timeWindow = (3600000*24.0*7); + view.start = +new Date - timeWindow; + view.end = +new Date; + + if (multigraph_feedlist[0]!=undefined) + { + view.end = multigraph_feedlist[0].end; + if (view.end==0) view.end = (new Date()).getTime(); + if (multigraph_feedlist[0].timeWindow) { + view.start = view.end - multigraph_feedlist[0].timeWindow; + } + } + + var out = + "
"+ + "
"+ + ""+ + "
" + ; + $(element).html(out); + + $('#graph').width($('#graph_bound').width()); + $('#graph').height($('#graph_bound').height()); + if (embed) $('#graph').height($(window).height()); + + $(window).resize(function(){ + $('#graph').width($('#graph_bound').width()); + if (embed) $('#graph').height($(window).height()); + plot(); + }); + + + // Fade in/out the control buttons on mouse-over the plot container + $("#graph_bound").mouseenter(function(){ + $("#graph_buttons").stop().fadeIn(); + }).mouseleave(function(){ + $("#graph_buttons").stop().fadeOut(); + }); + + //-------------------------------------------------------------------------------------- + // Graph zooming + //-------------------------------------------------------------------------------------- + $("#graph").bind("plotselected", function (event, ranges) + { + view.start = ranges.xaxis.from; + view.end = ranges.xaxis.to; + timeWindowChanged = 1; vis_feed_data(); + }); + + //---------------------------------------------------------------------------------------------- + // Operate buttons + //---------------------------------------------------------------------------------------------- + $("#zoomout").click(function () {view.zoomout(); vis_feed_data();}); + $("#zoomin").click(function () {view.zoomin(); vis_feed_data();}); + $('#right').click(function () {view.panright(); vis_feed_data();}); + $('#left').click(function () {view.panleft(); vis_feed_data();}); + $('.time').click(function () {view.timewindow($(this).attr("time")); vis_feed_data();}); + //----------------------------------------------------------------------------------------------- +} diff --git a/emoncms/Modules/vis/visualisations/multigraph.php b/emoncms/Modules/vis/visualisations/multigraph.php new file mode 100644 index 0000000..f7b3c6c --- /dev/null +++ b/emoncms/Modules/vis/visualisations/multigraph.php @@ -0,0 +1,108 @@ + + + + + + + + + + + + +

+ + + +
+ + + diff --git a/emoncms/Modules/vis/visualisations/rawdata.php b/emoncms/Modules/vis/visualisations/rawdata.php new file mode 100644 index 0000000..c36aa7e --- /dev/null +++ b/emoncms/Modules/vis/visualisations/rawdata.php @@ -0,0 +1,230 @@ + + + + + + + + + + +
+ +
+
+
+ +
+ + + + +
+ +
+ + + + +
+ +
+ +

+
+ + + + + diff --git a/emoncms/Modules/vis/visualisations/realtime.php b/emoncms/Modules/vis/visualisations/realtime.php new file mode 100644 index 0000000..c108f8f --- /dev/null +++ b/emoncms/Modules/vis/visualisations/realtime.php @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + +

+ + +
+
+
+ + + + + +
+
+ + + + + diff --git a/emoncms/Modules/vis/visualisations/vis.helper.js b/emoncms/Modules/vis/visualisations/vis.helper.js new file mode 100644 index 0000000..63d1a08 --- /dev/null +++ b/emoncms/Modules/vis/visualisations/vis.helper.js @@ -0,0 +1,120 @@ +var view = +{ + 'start':0, + 'end':0, + + 'zoomout':function () + { + var time_window = this.end - this.start; + var middle = this.start + time_window / 2; + time_window = time_window * 2; + this.start = middle - (time_window/2); + this.end = middle + (time_window/2); + }, + + 'zoomin':function () + { + var time_window = this.end - this.start; + var middle = this.start + time_window / 2; + time_window = time_window * 0.5; + this.start = middle - (time_window/2); + this.end = middle + (time_window/2); + }, + + 'panright':function () + { + var time_window = this.end - this.start; + var shiftsize = time_window * 0.2; + this.start += shiftsize; + this.end += shiftsize; + }, + + 'panleft':function () + { + var time_window = this.end - this.start; + var shiftsize = time_window * 0.2; + this.start -= shiftsize; + this.end -= shiftsize; + }, + + 'timewindow':function(time) + { + this.start = ((new Date()).getTime())-(3600000*24*time); //Get start time + this.end = (new Date()).getTime(); //Get end time + } +} + +var stats = { + + 'min': 0, + 'max': 0, + 'mean': 0, + 'stdev': 0, + + 'calc':function(data) + { + var sum = 0, i=0; + stats.min = 0; + stats.max = 0; + for (z in data) + { + if (i==0) { + stats.max = data[z][1]; + stats.min = data[z][1]; + } + + if (data[z][1]>stats.max) stats.max = data[z][1]; + if (data[z][1]' + contents + '').css({ + position: 'absolute', + display: 'none', + 'font-weight':'bold', + border: '1px solid rgb(255, 221, 221)', + padding: '2px', + 'background-color': bgColour, + opacity: '0.8' + }).appendTo("body").fadeIn(200); + //x = x - elem.width(); + //x = x - elem.width(); + elem.css({ + top: y - elem.height() - offset, + left: x - elem.width() - offset, + }); +}; diff --git a/emoncms/Theme/embed.php b/emoncms/Theme/embed.php new file mode 100644 index 0000000..7aafd04 --- /dev/null +++ b/emoncms/Theme/embed.php @@ -0,0 +1,30 @@ + + + + + + + + + Emoncms embed + + + + + +
+ +
+ + \ No newline at end of file diff --git a/emoncms/Theme/emon.css b/emoncms/Theme/emon.css new file mode 100644 index 0000000..4b24552 --- /dev/null +++ b/emoncms/Theme/emon.css @@ -0,0 +1,90 @@ +/* +All Emoncms code is released under the GNU Affero General Public License. +See COPYRIGHT.txt and LICENSE.txt. + +--------------------------------------------------------------------- +Emoncms - open source energy visualisation +Part of the OpenEnergyMonitor project: +http://openenergymonitor.org + +*/ + html, body { + height: 100%; +} +#wrap { + min-height: 100%; + height: auto !important; + height: 100%; + /* Negative indent footer by it's height */ + margin: 0 auto -40px; +} + +#login-form input[type="text"], #login-form input[type="password"] { + width: 94%; +} + +#push, #footer { + height: 30px; +} +#footer { + background-color: #f5f5f5; + text-align: center; + font-size: 13px; + font-weight: bold; + padding-top:10px; +} +#footer a { + color: #77b4d9; + text-decoration: none; +} +#footer span { + color:#999; +} +#submenu { + width:100%; + background-color:#ddd; + height:27px; +} +#topspacer { + padding-top: 42px; +} + +div#account { + width:230px; +} + +.account-item { + margin-bottom:10px; +} + +input[type=text][class=variable-name-edit] { + margin-bottom:0px; +} +body .modal { + /* new custom width */ + width: 1080px; + /* must be half of the width, minus scrollbar on the left (30px) */ + margin-left: -540px; +} +.modal-body { + max-height: 800px; +} +@media (min-width: 768px) and (max-width: 979px) { + #topspacer { + margin-top:-20px; + padding-top: 0px; + } +} +/* Lastly, apply responsive CSS fixes as necessary */ + @media (max-width: 767px) { + #submenu, #footer { + margin-left: -20px; + margin-right: -20px; + padding-left: 20px; + padding-right: 20px; + } + #topspacer { + margin-top:-20px; + padding-top: 0px; + } +} diff --git a/emoncms/Theme/emoncms logo off.png b/emoncms/Theme/emoncms logo off.png new file mode 100644 index 0000000..ce6354f Binary files /dev/null and b/emoncms/Theme/emoncms logo off.png differ diff --git a/emoncms/Theme/emoncms-logo.png b/emoncms/Theme/emoncms-logo.png new file mode 100644 index 0000000..8cde787 Binary files /dev/null and b/emoncms/Theme/emoncms-logo.png differ diff --git a/emoncms/Theme/emoncms_logo.png b/emoncms/Theme/emoncms_logo.png new file mode 100644 index 0000000..89e1454 Binary files /dev/null and b/emoncms/Theme/emoncms_logo.png differ diff --git a/emoncms/Theme/favicon-low-write.png b/emoncms/Theme/favicon-low-write.png new file mode 100644 index 0000000..9b6cb67 Binary files /dev/null and b/emoncms/Theme/favicon-low-write.png differ diff --git a/emoncms/Theme/favicon.png b/emoncms/Theme/favicon.png new file mode 100644 index 0000000..9b6cb67 Binary files /dev/null and b/emoncms/Theme/favicon.png differ diff --git a/emoncms/Theme/ios_load.png b/emoncms/Theme/ios_load.png new file mode 100644 index 0000000..d451cf9 Binary files /dev/null and b/emoncms/Theme/ios_load.png differ diff --git a/emoncms/Theme/logo_normal.png b/emoncms/Theme/logo_normal.png new file mode 100644 index 0000000..839830d Binary files /dev/null and b/emoncms/Theme/logo_normal.png differ diff --git a/emoncms/Theme/menu_view.php b/emoncms/Theme/menu_view.php new file mode 100644 index 0000000..4f9b9d3 --- /dev/null +++ b/emoncms/Theme/menu_view.php @@ -0,0 +1,89 @@ +"Log In", 'path'=>"user/login", 'order' => -1 ); +?> + + + + + diff --git a/emoncms/Theme/theme.php b/emoncms/Theme/theme.php new file mode 100644 index 0000000..258db3a --- /dev/null +++ b/emoncms/Theme/theme.php @@ -0,0 +1,89 @@ + + + + + + + + SC Nordic WifiAgent + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + +
+ +
+ + + + + + +
+
+ + + + + + + + diff --git a/emoncms/core.php b/emoncms/core.php new file mode 100644 index 0000000..0b9fbcb --- /dev/null +++ b/emoncms/core.php @@ -0,0 +1,159 @@ +query("SELECT count(table_schema) from information_schema.tables WHERE table_schema = '$database'"); + $row = $result->fetch_array(); + if ($row['0']>0) return true; else return false; +} + +function controller($controller_name) +{ + $output = array('content'=>''); + + if ($controller_name) + { + $controller = $controller_name."_controller"; + $controllerScript = "Modules/".$controller_name."/".$controller.".php"; + if (is_file($controllerScript)) + { + // Load language files for module + $domain = "messages"; + bindtextdomain($domain, "Modules/".$controller_name."/locale"); + bind_textdomain_codeset($domain, 'UTF-8'); + + + textdomain($domain); + + require $controllerScript; + $output = $controller(); + } + } + return $output; +} + +function view($filepath, array $args) +{ + extract($args); + ob_start(); + include "$filepath"; + $content = ob_get_clean(); + return $content; +} + +function get($index) +{ + $val = null; + if (isset($_GET[$index])) $val = $_GET[$index]; + + if (get_magic_quotes_gpc()) $val = stripslashes($val); + return $val; +} + +function post($index) +{ + $val = null; + if (isset($_POST[$index])) $val = $_POST[$index]; + + if (get_magic_quotes_gpc()) $val = stripslashes($val); + return $val; +} + +function prop($index) +{ + $val = null; + if (isset($_GET[$index])) $val = $_GET[$index]; + if (isset($_POST[$index])) $val = $_POST[$index]; + + if (get_magic_quotes_gpc()) $val = stripslashes($val); + return $val; +} + + +function server($index) +{ + $val = null; + if (isset($_SERVER[$index])) $val = $_SERVER[$index]; + return $val; +} + +function load_db_schema() +{ + $schema = array(); + $dir = scandir("Modules"); + for ($i=2; $i$menu_left, 'right'=>$menu_right, 'dropdown'=>$menu_dropdown); +} + +// Menu sort by order +function menu_sort($a,$b) { + return $a['order']>$b['order']; +} diff --git a/emoncms/default.emonpi.settings.php b/emoncms/default.emonpi.settings.php new file mode 100644 index 0000000..833713f --- /dev/null +++ b/emoncms/default.emonpi.settings.php @@ -0,0 +1,88 @@ +800, + + 'phpfina'=>array( + 'datadir'=>'/home/pi/data/phpfina/' + ), + + 'phptimeseries'=>array( + 'datadir'=>'/home/pi/data/phptimeseries/' + ) + ); + + // (OPTIONAL) Used by password reset feature + $smtp_email_settings = array( + 'host'=>"_SMTP_HOST_", + 'username'=>"_SMTP_USER_", + 'password'=>"_SMTP_PASSWORD_", + 'from'=>array('_SMTP_EMAIL_ADDR_' => '_SMTP_EMAIL_NAME_') + ); + + $enable_password_reset = false; + + // Checks for limiting garbage data? + $max_node_id_limit = 32; + + /* + + Default router settings - in absence of stated path + + */ + + // Default controller and action if none are specified and user is anonymous + $default_controller = "user"; + $default_action = "login"; + + // Default controller and action if none are specified and user is logged in + $default_controller_auth = "user"; + $default_action_auth = "view"; + + // Public profile functionality + $public_profile_enabled = TRUE; + $public_profile_controller = "dashboard"; + $public_profile_action = "view"; + + /* + + Other + + */ + + // Theme location + $theme = "basic"; + + // Error processing + $display_errors = TRUE; + + // Enable multi user emoncms. + // If set to false, emoncms will automatically remove the register form and + // ability to create further users after the first user has been created + $enable_multi_user = false; + + // Enable remember me feature - needs more testing + $enable_rememberme = TRUE; + + // Skip database setup test - set to false once database has been setup. + $dbtest = TRUE; + + // Log4PHP configuration + $log4php_configPath = 'logconfig.xml'; diff --git a/emoncms/default.settings.php b/emoncms/default.settings.php new file mode 100644 index 0000000..833713f --- /dev/null +++ b/emoncms/default.settings.php @@ -0,0 +1,88 @@ +800, + + 'phpfina'=>array( + 'datadir'=>'/home/pi/data/phpfina/' + ), + + 'phptimeseries'=>array( + 'datadir'=>'/home/pi/data/phptimeseries/' + ) + ); + + // (OPTIONAL) Used by password reset feature + $smtp_email_settings = array( + 'host'=>"_SMTP_HOST_", + 'username'=>"_SMTP_USER_", + 'password'=>"_SMTP_PASSWORD_", + 'from'=>array('_SMTP_EMAIL_ADDR_' => '_SMTP_EMAIL_NAME_') + ); + + $enable_password_reset = false; + + // Checks for limiting garbage data? + $max_node_id_limit = 32; + + /* + + Default router settings - in absence of stated path + + */ + + // Default controller and action if none are specified and user is anonymous + $default_controller = "user"; + $default_action = "login"; + + // Default controller and action if none are specified and user is logged in + $default_controller_auth = "user"; + $default_action_auth = "view"; + + // Public profile functionality + $public_profile_enabled = TRUE; + $public_profile_controller = "dashboard"; + $public_profile_action = "view"; + + /* + + Other + + */ + + // Theme location + $theme = "basic"; + + // Error processing + $display_errors = TRUE; + + // Enable multi user emoncms. + // If set to false, emoncms will automatically remove the register form and + // ability to create further users after the first user has been created + $enable_multi_user = false; + + // Enable remember me feature - needs more testing + $enable_rememberme = TRUE; + + // Skip database setup test - set to false once database has been setup. + $dbtest = TRUE; + + // Log4PHP configuration + $log4php_configPath = 'logconfig.xml'; diff --git a/emoncms/docs/emonhubmod.md b/emoncms/docs/emonhubmod.md new file mode 100644 index 0000000..703502e --- /dev/null +++ b/emoncms/docs/emonhubmod.md @@ -0,0 +1,94 @@ +## Optional Emonhub modifications + +1. Modifying emonhub to post to emoncms node module for remote node decoding +2. Modifying emonhub to work with the emoncms packetgen module for sending out control packets over the rfm12/69 network. + +### Using Emonhub with the optional emoncms node module + +Emonhub has a powerfull node decoder built into it that allows for the decoding of node data with non-default packet structures. This decoder can be configured from emonhub.conf. There are ideas for how it could be possible to set the node decoders in the emonhub remotely but this is still a feature in early development. See emonhub issue 64: + +[https://github.com/emonhub/emonhub/issues/64](https://github.com/emonhub/emonhub/issues/64) + +In the meantime if you wish to carry out the node decoding within a remote emoncms installation rather than use the standard local emonhub based node decoding a couple of small modifications to emonhub can be made to achieve this: + +In emonhub.conf under interfacers -> runtimesettings add the line + + datacode = b + +In src/emonhub_reporter.py change [line 275](https://github.com/emonhub/emonhub/blob/development/src/emonhub_reporter.py#L275) + + post_url = self._settings['url']+'/input/bulk'+'.json?apikey=' + +to + + post_url = self._settings['url']+'/node/multiple'+'.json?apikey=' + +and change [line 289](https://github.com/emonhub/emonhub/blob/development/src/emonhub_reporter.py#L289) + + if reply == 'ok': + +to + + if reply == 'true': + +Restart emonhub to finish: + + sudo service emonhub restart + +Check that there are no errors in the log: + + tail -f /var/log/emonhub/emonhub.log + +If the emoncms node module is not present in your emoncms installation (if your using the bufferedwrite branch) then the node module can be installed from git by running in your emoncms/Modules folder: + + git clone https://github.com/emoncms/node.git + +Complete the node module installation by running db update from within the admin panel of your emoncms account. + +### Using Emonhub with the emoncms PacketGen module + +The emoncms packetgen module can be used to construct control packets to be send out over the rfm12/69 network. The control packet is a register of properties that any node can pick and choose from. These properties could be room set point temperatures for radiator control nodes to make use of or lighting on/off etc. + +Development of control functionality within emoncms is at an early stage and we are currently discussing the best way to interface emonhub with emoncms for control, see: [https://github.com/emonhub/emonhub/issues/64](https://github.com/emonhub/emonhub/issues/64). The following is a quick modification that can be done to emonhub to get control working using packetgen until a more permanent solution is reached: + +Start by installing packetgen by running the following in your emoncms/Modules folder: + + git clone https://github.com/emoncms/packetgen.git + +Complete the packetgen module installation by running db update from within the admin panel of your emoncms account + +We can modify emonhub to poll the packetgen module periodically and send the packetgen packet state over serial to the rfm12/69. + + cd /home/pi/emonhub/src + + nano emonhub_interfacer.py + +Add just below import select [~line 16](https://github.com/emonhub/emonhub/blob/development/src/emonhub_interfacer.py#L16) the line: + + import urllib2 + +Add just below self._interval_timestamp = 0 [~line 50](https://github.com/emonhub/emonhub/blob/development/src/emonhub_interfacer.py#L50) the line: + + self._control_timestamp = time.time() + 30 + +In class EmonHubJeeInterfacer, method run, add just below: now = time.time() [~line 483](https://github.com/emonhub/emonhub/blob/development/src/emonhub_interfacer.py#L483) +Take care to make sure the code is correctly indented as shown below, this is needed for python + + if now - self._control_timestamp > 5: + self._control_timestamp = now + packet = urllib2.urlopen("http://localhost/emoncms/packetgen/rfpacket.json?apikey=APIKEY").read() + packet = packet[1:-1] + self._log.debug(self.name + " broadcasting control packet " + packet + "s") + self._ser.write(packet+"s") + +Set your emoncms location (it can be localhost or a remote server) and apikey in the URL string. + +Save and exit [Ctrl + X] then [Enter] + +Restart emonhub to finish: + + sudo service emonhub restart + +Check that there are no errors in the log: + + tail -f /var/log/emonhub/emonhub.log diff --git a/emoncms/docs/files/emoncms_graphic.png b/emoncms/docs/files/emoncms_graphic.png new file mode 100644 index 0000000..f732e74 Binary files /dev/null and b/emoncms/docs/files/emoncms_graphic.png differ diff --git a/emoncms/docs/files/emonpi_sys_diag.png b/emoncms/docs/files/emonpi_sys_diag.png new file mode 100644 index 0000000..f4626c9 Binary files /dev/null and b/emoncms/docs/files/emonpi_sys_diag.png differ diff --git a/emoncms/docs/hddsetup.md b/emoncms/docs/hddsetup.md new file mode 100644 index 0000000..e140660 --- /dev/null +++ b/emoncms/docs/hddsetup.md @@ -0,0 +1,50 @@ +## HDD Setup + +The emonSD-21-7-14.img.zip image can be used with a harddrive or an SD Card. Start by writing the emonSD-21-7-14.img on to both your harddrive and an SD Card. The SD card is needed for initial boot up, after it boots it will use the harddrive. + +### Change /boot/cmdline.txt on the boot partition of the SD card + +Paul ([pb66](http://openenergymonitor.org/emon/user/4440)) from the OpenEnergyMonitor forums has written an alternative guide for setting up the Pi with file system on a hard drive which should be easier for those running Windows, see forum post: [http://openenergymonitor.org/emon/node/5092] (http://openenergymonitor.org/emon/node/5092) + +Mount the SD Card on your computer and open the boot) partition. Open to edit the file: + + /boot/cmdline.txt + +Over write with: + + dwc_otg.lpm_enable=0 console=tty1 root=/dev/sda2 rootfstype=ext4 elevator=deadline rootwait + +This both tells the PI that the root filesystem is on /dev/sda2 and to not use the serial port for raspberrypi debug purposes as we need it for emoncms. + +### Edit /etc/fstab on the HDD + +Mount the Harddrive on your computer and open the main partition. Open to edit the file /etc/fstab: + + tmpfs /tmp tmpfs nodev,nosuid,size=30M,mode=1777 0 0 + tmpfs /var/log tmpfs nodev,nosuid,size=30M,mode=1777 0 0 + proc /proc proc defaults 0 0 + /dev/mmcblk0p1 /boot vfat defaults 0 2 + /dev/mmcblk0p2 / ext4 defaults,ro,noatime,errors=remount-ro 0 1 + /dev/mmcblk0p3 /home/pi/data ext2 defaults,rw,noatime 0 2 + +Change the root device "/" from: /dev/mmcblk0p2 to be /dev/sda2 +Change the "/home/pi/data" device from: /dev/mmcblk0p3 to be /dev/sda3 + + tmpfs /tmp tmpfs nodev,nosuid,size=30M,mode=1777 0 0 + tmpfs /var/log tmpfs nodev,nosuid,size=30M,mode=1777 0 0 + proc /proc proc defaults 0 0 + /dev/mmcblk0p1 /boot vfat defaults 0 2 + /dev/sda2 / ext4 defaults,ro,noatime,errors=remount-ro 0 1 + /dev/sda3 /home/pi/data ext2 defaults,rw,noatime 0 2 + +**Note:** To make the OS partition load in write mode change: + + /dev/sda2 / ext4 defaults,ro,noatime,errors=remount-ro 0 1 + +to: + + /dev/sda2 / ext4 defaults,rw,noatime,errors=remount-ro 0 1 + +That's all that is needed to get the data partition of the raspberrypi running of a harddrive rather than the SD card. You can now insert the SD card in the raspberrypi and connect up the harddrive, power up and use the raspberrypi in the same way as you would use the pi if it was running off an SD card. + +The data partition on the harddrive will still be around 900Mb, you may wish to extend the partition, there are plenty of good guides available on the internet for this search for extending an ext2 filesystem. diff --git a/emoncms/docs/install.md b/emoncms/docs/install.md new file mode 100644 index 0000000..1e4b0ea --- /dev/null +++ b/emoncms/docs/install.md @@ -0,0 +1,470 @@ +## How to setup a raspberrypi running emonhub + the low write branch of emoncms + +This guide details how to setup a raspberry pi basestation that can be used to either forward data to a remote server or record data locally or both. + +It uses the low write branch of emoncms which is part of the investigation and development work into a version of emoncms that has a reduced disk write load with the view of enabling the use of SD cards for long term logging. Its early days yet to know whether this approach will succeed, however monitoring of disk activity shows that the write load on a busy system can be several hundred times less with this modified version of emoncms. + +[Full investigation into improving write performance with write buffering](https://github.com/openenergymonitor/documentation/blob/master/BuildingBlocks/TimeSeries/writeloadinvestigation.md) + +The build uses the latest version of [EmonHub](https://github.com/emonhub/) to provide a flexible input stage and ability to forward data to other remote servers. EmonHub is also used to decode the byte data recieved from the rfm12pi adapter board. The result of which is passed to the input interface in emoncms. + +![System diagram](files/emonpi_sys_diag.png) + +The writer process writes the feed data to disk step periodically. The writing step involves first reading all the items out of the redis queue placing the individual feed datapoints into individual buffers which are again in memory. Then at the end of this process each block of data accumulated for each feed is written to the disk in a single write operation (per feed) + +### Raspbian + +Download the official raspberrpi raspbian image and write to the SD card. + +[http://www.raspberrypi.org/downloads](http://www.raspberrypi.org/downloads) + +To upload the image using dd on linux + +Check the mount location of the SD card using: + + df -h + +Unmount any mounted SD card partitions + + umount /dev/sdb1 + umount /dev/sdb2 + +Write the raspbian image to the SD card (Make sure of=/dev/sdb is the correct location) + + sudo dd bs=4M if=2014-06-20-wheezy-raspbian.img of=/dev/sdb + +Insert the SD card into the raspberrypi and power the pi up. + +Find the IP address of your raspberrypi on your network then connect and login to your pi with SSH, for windows users there's a nice tool called [putty](http://www.putty.org/) which you can use to do this. To connect via ssh on linux, type the following in terminal: + + ssh pi@YOUR_PI_IP_ADDRESS + +It will then prompt you for a username and password which are: **username:**pi, **password:**raspberry. + +### Setup Data partition + +Steps for creating 3rd partition for data using fdisk and mkfs: + + sudo fdisk -l + Note end of last partition (5785599 on standard sd card) + sudo fdisk /dev/mmcblk0 + enter: n->p->3 + enter: 5785600 + enter: default or 7626751 + enter: w (write partition to disk) + fails with error, will write at reboot + sudo reboot + + On reboot, login and run: + sudo mkfs.ext2 -b 1024 /dev/mmcblk0p3 + +**Note:** *We create here an ext2 filesystem with a blocksize of 1024 bytes instead of the default 4096 bytes. A lower block size results in significant write load reduction when using an application like emoncms that only makes small but frequent and across many files updates to disk. Ext2 is choosen because it supports multiple linux user ownership options which are needed for the mysql data folder. Ext2 is non-journaling which reduces the write load a little although it may make data recovery harder vs Ext4, The data disk size is small however and the downtime from running fsck is perhaps less critical.* + +Now that your loged in to your pi, the first step is to edit the _inittab_ and _boot cmdline config_ file to allow the python gateway which we will install next to use the serial port, type: + + sudo nano /etc/inittab + +At the bottom of the file comment out the line, by adding a ‘#’ at beginning: + + # T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100 + +[Ctrl+X] then [y] then [Enter] to save and exit + +Edit boot cmdline.txt + + sudo nano /boot/cmdline.txt + +replace the line: + + dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 + root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait + +with: + + dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait + +Create a directory that will be a mount point for the rw data partition + + mkdir /home/pi/data + +### Read only mode + +Configure Raspbian to run in read-only mode for increased stability (optional but recommended) + +The following is copied from: +http://emonhub.org/documentation/install/raspberrypi/sd-card/ + +Then run these commands to make changes to filesystem + + sudo cp /etc/default/rcS /etc/default/rcS.orig + sudo sh -c "echo 'RAMTMP=yes' >> /etc/default/rcS" + sudo mv /etc/fstab /etc/fstab.orig + sudo sh -c "echo 'tmpfs /tmp tmpfs nodev,nosuid,size=30M,mode=1777 0 0' >> /etc/fstab" + sudo sh -c "echo 'tmpfs /var/log tmpfs nodev,nosuid,size=30M,mode=1777 0 0' >> /etc/fstab" + sudo sh -c "echo 'proc /proc proc defaults 0 0' >> /etc/fstab" + sudo sh -c "echo '/dev/mmcblk0p1 /boot vfat defaults 0 2' >> /etc/fstab" + sudo sh -c "echo '/dev/mmcblk0p2 / ext4 defaults,ro,noatime,errors=remount-ro 0 1' >> /etc/fstab" + sudo sh -c "echo '/dev/mmcblk0p3 /home/pi/data ext2 defaults,rw,noatime 0 2' >> /etc/fstab" + sudo sh -c "echo ' ' >> /etc/fstab" + sudo mv /etc/mtab /etc/mtab.orig + sudo ln -s /proc/self/mounts /etc/mtab + +The Pi will now run in Read-Only mode from the next restart. + +Before restarting create two shortcut commands to switch between read-only and write access modes. + +Firstly “ rpi-rw “ will be the command to unlock the filesystem for editing, run + + sudo nano /usr/bin/rpi-rw + +and add the following to the blank file that opens + + #!/bin/sh + sudo mount -o remount,rw /dev/mmcblk0p2 / + echo "Filesystem is unlocked - Write access" + echo "type ' rpi-ro ' to lock" + +save and exit using ctrl-x -> y -> enter and then to make this executable run + + sudo chmod +x /usr/bin/rpi-rw + +Next “ rpi-ro “ will be the command to lock the filesytem down again, run + + sudo nano /usr/bin/rpi-ro + +and add the following to the blank file that opens + + #!/bin/sh + sudo mount -o remount,ro /dev/mmcblk0p2 / + echo "Filesystem is locked - Read Only access" + echo "type ' rpi-rw ' to unlock" + +save and exit using ctrl-x -> y -> enter and then to make this executable run + + sudo chmod +x /usr/bin/rpi-ro + +Lastly reboot for changes to take effect + + sudo shutdown -r now + +Login again, change data partition permissions: + + sudo chmod -R a+w data + sudo chown -R pi data + sudo chgrp -R pi data + +### Install dependencies + +Update the rasbian repositories with: + + rpi-rw + + sudo apt-get update + +Install all dependencies: +There are a few extra things in here such as mosquitto (MQTT) which is not currently used but may be soon. + + sudo apt-get install apache2 mysql-server mysql-client php5 libapache2-mod-php5 php5-mysql php5-curl php-pear php5-dev php5-mcrypt git-core redis-server build-essential ufw ntp python-serial python-configobj mosquitto mosquitto-clients python-pip python-dev screen sysstat minicom + +Install pecl dependencies (redis and swift mailer) + + sudo pecl install redis + + sudo pear channel-discover pear.apache.org/log4php + sudo pear install log4php/Apache_log4php + +Add pecl modules to php5 config + + sudo sh -c 'echo "extension=redis.so" > /etc/php5/apache2/conf.d/20-redis.ini' + sudo sh -c 'echo "extension=redis.so" > /etc/php5/cli/conf.d/20-redis.ini' + +### Configure dependencies + +**Redis** + +Configure redis to run without logging or data persistance. + + sudo nano /etc/redis/redis.conf + +comment out redis log file + + # logfile /var/log/redis/redis-server.log + +comment out all redis saving + + # save 900 1 + # save 300 10 + # save 60 10000 + + sudo /etc/init.d/redis-server start + +**Apache2** + +Emoncms uses a front controller to route requests, modrewrite needs to be configured: + + $ sudo a2enmod rewrite + $ sudo nano /etc/apache2/sites-enabled/000-default + +Change (line 7 and line 11), "AllowOverride None" to "AllowOverride All". + + Comment out line # CustomLog ${APACHE_LOG_DIR}/access.log combined + +That is the sections and . +[Ctrl + X ] then [Y] then [Enter] to Save and exit. + +Change apache2 log directory: + + sudo nano /etc/apache2/envvars + export APACHE_LOG_DIR=/var/log$SUFFIX (remove the apache2 bit) + +Comment the access log to other-vhosts (add #) + + sudo nano /etc/apache2/conf.d/other-vhosts-access-log + +**Mysql** + + mkdir /home/pi/data/mysql + sudo cp -rp /var/lib/mysql/. /home/pi/data/mysql + + sudo nano /etc/mysql/my.cnf + change line datadir to /home/pi/data/mysql + +**PHP5 Sessions** + + sudo nano /etc/php5/apache2/php.ini + +Find line: + + ; session.save_path = "/var/lib/php5" + +change to: + + session.save_path = "/tmp" + + +### Security + +[http://blog.al4.co.nz/2011/05/setting-up-a-secure-ubuntu-lamp-server/](http://blog.al4.co.nz/2011/05/setting-up-a-secure-ubuntu-lamp-server/) + +**Install ufw** + +ufw: uncomplicated firewall, is a great little firewall program that you can use to control your server access rules. The default set below are fairly standard for a web server but are quite permissive. You may want to only allow connection on a certain ip if you will always be accessing your pi from a fixed ip. + +UFW Documentation +[https://help.ubuntu.com/community/UFW](https://help.ubuntu.com/community/UFW) + + sudo ufw allow 80/tcp + sudo ufw allow 443/tcp + sudo ufw allow 22/tcp + sudo ufw enable + +**Change root password** + +Set root password + + sudo passwd root + +The default root password used in the ready to go image is **raspberry**. +Change this to a hard to guess password to make your root account secure. + +**Secure MySQL** + +Run mysql_secure_installation see [mysql docs](http://dev.mysql.com/doc/refman/5.0/en/mysql-secure-installation.html) + + mysql_secure_installation + +**Secure SSH** + +Disable root login: + + sudo nano /etc/ssh/sshd_config + +Set **PermitRootLogin** to **no** + + +### Reboot the pi + + sudo reboot + +### Install the emoncms application via git + +Git is a source code management and revision control system but at this stage we use it to just download and update the emoncms application. + +First cd into the var directory: + + $ cd /var/ + +Set the permissions of the www directory to be owned by your username: + + $ sudo chown pi www + +Cd into www directory + + $ cd www + +Download emoncms using git: + + $ git clone -b low-write https://github.com/emoncms/emoncms.git + +Once installed you can pull in updates with: + + git pull + +### Create a MYSQL database + + $ mysql -u root -p + +Enter the mysql password that you set above. +Then enter the sql to create a database: + + mysql> CREATE DATABASE emoncms; + +Exit mysql by: + + mysql> exit + +### Create data repositories for emoncms feed engine's + + sudo mkdir /home/pi/data/phpfina + sudo mkdir /home/pi/data/phptimeseries + + sudo chown www-data:root /home/pi/data/phpfina + sudo chown www-data:root /home/pi/data/phptimeseries + +### Set emoncms database settings. + +cd into the emoncms directory where the settings file is located + + $ cd /var/www/emoncms/ + +Make a copy of default.settings.php and call it settings.php + + $ cp default.settings.php settings.php + +Open settings.php in an editor: + + $ nano settings.php + +Enter in your database settings. + + $username = "USERNAME"; + $password = "PASSWORD"; + $server = "localhost"; + $database = "emoncms"; + +Save (Ctrl-X), type Y and exit + +Move the writer script to home folder and service script to /etc/init.d/ + + sudo cp /var/www/emoncms/run/feedwriter /etc/init.d/ + sudo chmod 755 /etc/init.d/feedwriter + sudo update-rc.d feedwriter defaults + +### Disable Serial console + +The RFM12Pi/RFM69Pi communicates with Raspberry Pi via /dev/ttyAMA0. The Raspberry Pi's serial console must be disabled to enable the RFM69Pi serial communication: + + $ sudo wget https://raw.github.com/lurch/rpi-serial-console/master/rpi-serial-console -O /usr/bin/rpi-serial-console && sudo chmod +x /usr/bin/rpi-serial-console + $ sudo rpi-serial-console disable + $ sudo reboot + $ rpi-serial-console status + + +### Install Emonhub + +Copied from: [https://github.com/emonhub/dev-emonhub](https://github.com/emonhub/dev-emonhub) + +Use this commandline to install a "development" version of emonHub + + git clone https://github.com/emonhub/dev-emonhub.git ~/dev-emonhub && ~/dev-emonhub/install + +This script is not intended to fully install emonHub, It clones into "emonhub" folder in home directory and symlinks the files to where they are supposed to be. + +Edit configurations + + sudo nano /etc/emonhub/emonhub.conf + +Place OS Parition of SD card back in read only mode: + + rpi-ro + +Manually restart emonhub: + + sudo service emonhub restart + +Manually start feedwriter (add 'log' to end to enable logging) + + sudo service feedwriter start log + +### Add index.php redirect in web root + +echo "" > /var/www/index.php + +### Create scripts to disable and enable local emoncms + +#### Disable local emoncms + + sudo nano /usr/bin/localemoncms-disable + +Copy and paste: + + #!/bin/sh + sudo update-rc.d apache2 remove + sudo update-rc.d mysql remove + sudo update-rc.d feedwriter remove + sudo update-rc.d redis-server remove + + sudo service feedwriter stop + sudo service apache2 stop + sudo service mysql stop + sudo service redis-server stop + +Make excutable: + + sudo chmod +x /usr/bin/localemoncms-disable + +#### Enable local emoncms + + sudo nano /usr/bin/localemoncms-enable + +Copy and paste: + + #!/bin/sh + + sudo update-rc.d apache2 defaults + sudo update-rc.d mysql defaults + sudo update-rc.d redis-server defaults + sudo update-rc.d feedwriter defaults + + sudo service apache2 start + sudo service mysql start + sudo service redis-server start + sudo service feedwriter start + +Make excutable: + + sudo chmod +x /usr/bin/localemoncms-enable + +### SD Card defaults + +Create an emoncms user called raspberry and password raspberry. + +Set emoncms settings.php $dbtest to false and $allowusersregister to false. + +Default is local emoncms disabled + +---------------------------------------------- + +### Debugging and monitoring + +To view logfile entries: + + tail -f /var/log/emonhub/emonhub.log + tail -f /var/log/feedwriter.log + tail -f /var/log/emoncms.log + +Monitor disk load with sysstat: + + sudo iostat 60 (will give you 1 minuite disk load average, note kb_wrtn/s value) + +kb_wrtn/s should be around 0.5-1.5 kb_wrtn/s diff --git a/emoncms/docs/setup.md b/emoncms/docs/setup.md new file mode 100644 index 0000000..65955b9 --- /dev/null +++ b/emoncms/docs/setup.md @@ -0,0 +1,69 @@ +# Using the SD card + +## 1) Download the ready-to-go SD card image: + +**Latest - emonSD-17-06-15.img.zip ** + +[Download UK Mirror](http://openenergymonitor.org/files/emonSD-17Jun2015.img.zip) + +[Download USA Mirror](http://oem.aluminumalloyboats.com/oem/emonSD-17Jun2015.img.zip) + + +[See image User Guide Here](http://openenergymonitor.org/emon/modules/emonpi) + + +*Please get in contact if you can help with hosting bandwidth or seeding a torrent for these image downloads. Any help is much appreciated.* + +### 1a) Alternatively build it yourself: + +[https://github.com/emoncms/emoncms/blob/bufferedwrite/docs/install.md](https://github.com/emoncms/emoncms/blob/bufferedwrite/docs/install.md) + +## 2) Write the image to an SD card + +### Linux + +Start by inserting your SD card, your distribution should mount it automatically so the first step is to unmount the SD card and make a note of the SD card device name, to view mounted disks and partitions run: + + $ df -h + +You should see something like this: + + Filesystem Size Used Avail Use% Mounted on + /dev/sda6 120G 90G 24G 79% / + none 490M 700K 490M 1% /dev + none 497M 1.7M 495M 1% /dev/shm + none 497M 260K 497M 1% /var/run + none 497M 0 497M 0% /var/lock + /dev/sdb1 3.7G 4.0K 3.7G 1% /media/sandisk + +Unmount the SD card, change sdb to match your SD card drive: + + $ umount /dev/sdb1 + +If the card has more than one partition unmount that also: + + $ umount /dev/sdb2 + +Locate the directory of your downloaded emoncms image in terminal and write it to an SD card using linux tool *dd*: + +**Warning: take care with running the following command that your pointing at the right drive! If you point at your computer drive you could lose your data!** + + $ sudo dd bs=4M if=emonSD-17-06-15.img of=/dev/sdb + +### Windows + +The main raspberry pi sd card setup guide recommends Win32DiskImager, see steps for windows here: +[http://elinux.org/RPi_Easy_SD_Card_Setup](http://elinux.org/RPi_Easy_SD_Card_Setup) +Select the image as downloaded above. + +### Mac OSX + +See steps for Mac OSX as documented on the main raspberry pi sd card setup guide: +[http://elinux.org/RPi_Easy_SD_Card_Setup](http://elinux.org/RPi_Easy_SD_Card_Setup) +Select the image as downloaded above. +

+ +## 3.) Getting Started User Guide: + +[See emonHub / emonPi user guide here](http://openenergymonitor.org/emon/modules/emonpi) + diff --git a/emoncms/docs/switchtofull.md b/emoncms/docs/switchtofull.md new file mode 100644 index 0000000..e184e56 --- /dev/null +++ b/emoncms/docs/switchtofull.md @@ -0,0 +1,61 @@ +## Switching to full emoncms (master branch) + +To switch from the low write load branch of emoncms to the full master branch of emoncms which does not have the low write load optimisations but does have the PHPFiwa and Histogram feed engines. + +You may wish to do this if your running of a harddrive instead of an SD card. + +Place the RaspberryPI in write mode: + + rpi-rw + +Navigate to the emoncms directory + + cd /var/www/emoncms + +Switch to the master branch: + + git checkout master + +**You may want to install one of the other branches of emoncms here, perhaps to try out a new feature set not yet available in the master branch. See the branch list and descriptions on the [start page](https://github.com/emoncms/emoncms)** + +It should give the following confirmation: + + Branch master set up to track remote branch master from origin. + Switched to a new branch 'master' + +Create the phpfiwa data directory: + + sudo mkdir /home/pi/data/phpfiwa + sudo chown www-data:root /home/pi/data/phpfiwa + +Reapply www-data ownership: + + sudo chown -R www-data:root /home/pi/data/phpfina + sudo chown -R www-data:root /home/pi/data/phptimeseries + sudo chown -R www-data:root /home/pi/data/phpfiwa + +Repeat the same for phptimestore or timestore if you wish to use these engines. + +Add a settings.php entry for phpfiwa, in feed_settings add: + + 'phpfiwa'=>array( + 'datadir'=>'/home/trystan/Data/19July/phpfiwa/' + ) + +Disable feedwriter.php at startup: + + sudo update-rc.d feedwriter remove + +Stop feedwriter.php + + sudo service feedwriter stop + +Put the system back into read-only mode: + + rpi-ro + + + + + + diff --git a/emoncms/index.php b/emoncms/index.php new file mode 100644 index 0000000..5ec57e6 --- /dev/null +++ b/emoncms/index.php @@ -0,0 +1,161 @@ +connect("127.0.0.1"); + if (!$connected) { + echo "Can't connect to redis database, it may be that redis-server is not installed or started see readme for redis installation"; die; + } + + // 1) Load settings and core scripts + require "process_settings.php"; + require "core.php"; + require "route.php"; + require "locale.php"; + + $path = get_application_path(); + + require "Modules/log/EmonLogger.php"; + + // 2) Database + $mysqli = @new mysqli($server,$username,$password,$database); + + + $mqtt = false; + + if ( $mysqli->connect_error ) { + echo "Can't connect to database, please verify credentials/configuration in settings.php
"; + if ( $display_errors ) { + echo "Error message: " . $mysqli->connect_error . ""; + } + die(); + } + + if (!$mysqli->connect_error && $dbtest==true) { + require "Lib/dbschemasetup.php"; + if (!db_check($mysqli,$database)) db_schema_setup($mysqli,load_db_schema(),true); + } + + // 3) User sessions + require "Modules/user/rememberme_model.php"; + $rememberme = new Rememberme($mysqli); + require("Modules/user/user_model.php"); + $user = new User($mysqli,$redis,$rememberme); + + if (isset($_GET['apikey'])) + { + $session = $user->apikey_session($_GET['apikey']); + } + elseif (isset($_POST['apikey'])) + { + $session = $user->apikey_session($_POST['apikey']); + + } + else + { + $session = $user->emon_session_start(); + } + + // 4) Language + if (!isset($session['lang'])) $session['lang']=''; + set_emoncms_lang($session['lang']); + + // 5) Get route and load controller + $route = new Route(get('q')); + + if (get('embed')==1) $embed = 1; else $embed = 0; + + // If no route specified use defaults + if (!$route->controller && !$route->action) + { + // Non authenticated defaults + if (!$session['read']) + { + $route->controller = $default_controller; + $route->action = $default_action; + } + else // Authenticated defaults + { + $route->controller = $default_controller_auth; + $route->action = $default_action_auth; + } + } + + if ($route->controller == 'api') $route->controller = 'input'; + if ($route->controller == 'input' && $route->action == 'post') $route->format = 'json'; + if ($route->controller == 'input' && $route->action == 'bulk') $route->format = 'json'; + + // 6) Load the main page controller + $output = controller($route->controller); + + // If no controller of this name - then try username + // need to actually test if there isnt a controller rather than if no content + // is returned from the controller. + if (!$output['content'] && $public_profile_enabled && $route->controller!='admin') + { + $userid = $user->get_id($route->controller); + if ($userid) { + $route->subaction = $route->action; + $session['userid'] = $userid; + $session['username'] = $route->controller; + $session['read'] = 1; + $session['profile'] = 1; + $route->action = $public_profile_action; + $output = controller($public_profile_controller); + } + } + + // $mysqli->close(); + + // 7) Output + if ($route->format == 'json') + { + header('Content-Type: application/json'); + if ($route->controller=='time') { + print $output['content']; + } elseif ($route->controller=='input' && $route->action=='post') { + print $output['content']; + } elseif ($route->controller=='input' && $route->action=='bulk') { + print $output['content']; + } else { + print json_encode($output['content']); + } + } + + if ($route->format == 'text') + { + header('Content-Type: text'); + print $output['content']; + } + + if ($route->format == 'html') + { + $menu = load_menu(); + $output['mainmenu'] = view("Theme/menu_view.php", array()); + if ($embed == 0) print view("Theme/theme.php", $output); + if ($embed == 1) print view("Theme/embed.php", $output); + } + + $ltime = microtime(true) - $ltime; + + // if ($session['userid']>0) { + // $redis->incr("user:postcount:".$session['userid']); + // $redis->incrbyfloat("user:reqtime:".$session['userid'],$ltime); + // } diff --git a/emoncms/locale.php b/emoncms/locale.php new file mode 100644 index 0000000..1dce0b5 --- /dev/null +++ b/emoncms/locale.php @@ -0,0 +1,98 @@ + $object){ + $entry = str_replace($dir, '', $entry); + if (basename(dirname($entry))=='locale' && basename($entry)!='.' && basename($entry)!='..') $dlist[] = basename($entry); + } + + return array_unique($dlist); + } +} + +function get_available_languages() +{ + return directoryLocaleScan(dirname(__FILE__)); +} + + +function lang_http_accept() +{ + $langs = array(); + + foreach (explode(',', server('HTTP_ACCEPT_LANGUAGE')) as $lang) + { + $pattern = '/^(?P[a-zA-Z]{2,8})'. + '(?:-(?P[a-zA-Z]{2,8}))?(?:(?:;q=)'. + '(?P\d\.\d))?$/'; + + $splits = array(); + + if (preg_match($pattern, $lang, $splits)) { + $a = $splits["primarytag"]; + if (isset($splits["subtag"]) && $splits["subtag"]<> "") $a = $a."_".$splits["subtag"]; + $langs[]=$a; + } else { + // No match + } + } + return $langs; +} + +function set_lang($language) +{ + // set the first browser selected language + // TODO: iterate to find a suitable available language + + // Chrome returns different HTTP_ACCEPT_LANGUAGE code than firefox!!! + // Firefox Chrome + // ------------------- + // en_EN en + // es_ES es + // ... so translation system does not work in Chrome!!! + // lets try to fix quickly + + if (isset($language[0])) + { + if ($language[0] == 'es') $language[0]='es_ES'; + elseif ($language[0] == 'fr') $language[0]='fr_FR'; + + set_lang_by_user($language[0]); + } +} + +function set_lang_by_user($lang) +{ + putenv("LC_ALL=$lang"); + setlocale(LC_ALL,$lang); +} + +function set_emoncms_lang($lang) +{ + // If no language defined use the language browser + if ($lang == '') + set_lang(lang_http_accept()); + else + set_lang_by_user($lang); +} + diff --git a/emoncms/logconfig.xml b/emoncms/logconfig.xml new file mode 100644 index 0000000..8c6bb3e --- /dev/null +++ b/emoncms/logconfig.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/emoncms/old.settings.php b/emoncms/old.settings.php new file mode 100644 index 0000000..833713f --- /dev/null +++ b/emoncms/old.settings.php @@ -0,0 +1,88 @@ +800, + + 'phpfina'=>array( + 'datadir'=>'/home/pi/data/phpfina/' + ), + + 'phptimeseries'=>array( + 'datadir'=>'/home/pi/data/phptimeseries/' + ) + ); + + // (OPTIONAL) Used by password reset feature + $smtp_email_settings = array( + 'host'=>"_SMTP_HOST_", + 'username'=>"_SMTP_USER_", + 'password'=>"_SMTP_PASSWORD_", + 'from'=>array('_SMTP_EMAIL_ADDR_' => '_SMTP_EMAIL_NAME_') + ); + + $enable_password_reset = false; + + // Checks for limiting garbage data? + $max_node_id_limit = 32; + + /* + + Default router settings - in absence of stated path + + */ + + // Default controller and action if none are specified and user is anonymous + $default_controller = "user"; + $default_action = "login"; + + // Default controller and action if none are specified and user is logged in + $default_controller_auth = "user"; + $default_action_auth = "view"; + + // Public profile functionality + $public_profile_enabled = TRUE; + $public_profile_controller = "dashboard"; + $public_profile_action = "view"; + + /* + + Other + + */ + + // Theme location + $theme = "basic"; + + // Error processing + $display_errors = TRUE; + + // Enable multi user emoncms. + // If set to false, emoncms will automatically remove the register form and + // ability to create further users after the first user has been created + $enable_multi_user = false; + + // Enable remember me feature - needs more testing + $enable_rememberme = TRUE; + + // Skip database setup test - set to false once database has been setup. + $dbtest = TRUE; + + // Log4PHP configuration + $log4php_configPath = 'logconfig.xml'; diff --git a/emoncms/process_settings.php b/emoncms/process_settings.php new file mode 100644 index 0000000..f1f8ced --- /dev/null +++ b/emoncms/process_settings.php @@ -0,0 +1,59 @@ +missing setting: $username

'; + if (!isset($password)) $error_out .= '

missing setting: $password

'; + if (!isset($server) || $server=="") $error_out .= '

missing setting: $server

'; + if (!isset($database) || $database=="") $error_out .= '

missing setting: $database

'; + if ($enable_password_reset && !isset($smtp_email_settings)) $error_out .= '

missing setting: $smtp_email_settings

'; + + if (!isset($feed_settings)) $error_out .= "

missing setting: feed_settings

"; + + if (!isset($redis_enabled)) $redis_enabled = true; + + if ($error_out!="") { + echo "
"; + echo "

settings.php file error

"; + echo $error_out; + echo "

To fix check that the settings are set in settings.php or try re-creating your settings.php file from default.settings.php template

"; + echo "
"; + die; + } + + + // Set display errors + if (isset($display_errors) && ($display_errors)) { + error_reporting(E_ALL); + ini_set('display_errors', 'on'); + } +} +else +{ + echo "
"; + echo "

settings.php file error

"; + echo 'Copy and modify default.settings.php to settings.php
'; + echo 'For more information about configure settings.php file go to http://emoncms.org'; + echo "
"; + die; +} diff --git a/emoncms/readme.md b/emoncms/readme.md new file mode 100644 index 0000000..9aa7914 --- /dev/null +++ b/emoncms/readme.md @@ -0,0 +1,28 @@ +### How to setup a raspberrypi running emonhub + emoncms (low write version) + +This guide details how to setup a Raspberry Pi emonBase base-station that can be used to forward data to a remote server, record data locally or both. + +- [Download & Setup-up the ready-to-go SD card image](docs/setup.md) + +--------------------------------------------------------------------------------- + + +- [Full Image build guide](docs/install.md) + +- [Optional: modifications to emonhub for connection to emoncms node module and emoncms packetgen module](docs/emonhubmod.md)] + +- [Optional: Using a harddrive instead of an SD Card](docs/hddsetup.md) + +- [Optional: Switch to full emoncms (master branch)](docs/switchtofull.md) + +### Technical detail + +The low write branch of emoncms is the result of development work into a version of emoncms that has a reduced disk write load with the view of enabling the use of SD cards for long term logging. Its early days yet to know whether this approach will succeed, however monitoring of disk activity shows that the write load on a busy system can be 30 to a several 100 times less with this modified version of emoncms. + +[Full investigation into improving write performance with write buffering](https://github.com/openenergymonitor/documentation/blob/master/BuildingBlocks/TimeSeries/writeloadinvestigation.md) + +The build uses the latest version of [EmonHub](https://github.com/emonhub/) to provide a flexible input stage and ability to forward data to other remote servers. EmonHub is also used to decode the byte data recieved from the rfm12pi adapter board. The result of which is passed to the input interface in emoncms. + +![System diagram](docs/files/emonpi_sys_diag.png) + +The writer process writes the feed data to disk step periodically. The writing step involves first reading all the items out of the redis queue placing the individual feed datapoints into individual buffers which are again in memory. Then at the end of this process each block of data accumulated for each feed is written to the disk in a single write operation (per feed) diff --git a/emoncms/route.php b/emoncms/route.php new file mode 100644 index 0000000..0d8c6fa --- /dev/null +++ b/emoncms/route.php @@ -0,0 +1,80 @@ +decode($q); + } + + public function decode($q) + { + // filter out the applications relative root + + // If we're running in a subdirectory "emoncms", $q would look like '/emoncms/user/view' instead or just 'user/view' + // for the example of viewing a users profile. We need to remove the first directory to get the "clean" routing path + // within the application no matter at which path it's hosted. + + // First get the absolute physical path + // Example running at root: '/var/www' or subdirectory: '/var/www/emoncms' + $absolutePath = realpath(dirname(__FILE__)); + + // Next up, we need to find the relative path to the www root and remove everything except the part we will use to route + // for example this will perform the following: + // Running at root: str_replace('/var/www', '', '/var/www') => '' + // Running at subdirectory: str_replace('/var/www', '', '/var/www/emoncms') => '/emoncms' + $relativeApplicationPath = str_replace($_SERVER['DOCUMENT_ROOT'], '', $absolutePath); + + // Next up we will need to remove the '/emoncms' from the route path '/emoncms/user/view' + // str_replace('/emoncms', '', '/emoncms/user/view') => '/user/view' + // running at root path it will just perform nothing: str_replace('', '', '/emoncms/user/view') so it can be skipped + if ( !empty($relativeApplicationPath) ) { + $q = str_replace($relativeApplicationPath, '', $q); + } + + // trim slashes: '/user/view' => 'user/view' + $q = trim($q, '/'); + + // filter out all except a-z and / . + $q = preg_replace('/[^.\/A-Za-z0-9-]/', '', $q); + + // Split by / + $args = preg_split('/[\/]/', $q); + + // get format (part of last argument after . i.e view.json) + $lastarg = sizeof($args) - 1; + $lastarg_split = preg_split('/[.]/', $args[$lastarg]); + if (count($lastarg_split) > 1) { $this->format = $lastarg_split[1]; } + $args[$lastarg] = $lastarg_split[0]; + + if (count($args) > 0) { $this->controller = $args[0]; } + if (count($args) > 1) { $this->action = $args[1]; } + if (count($args) > 2) { $this->subaction = $args[2]; } + + + $this->method = "GET"; + if ($_SERVER["REQUEST_METHOD"]=="POST") $this->method = "POST"; + if ($_SERVER["REQUEST_METHOD"]=="DELETE") $this->method = "DELETE"; + if ($_SERVER["REQUEST_METHOD"]=="PUT") $this->method = "PUT"; + } +} diff --git a/emoncms/run/feedwriter b/emoncms/run/feedwriter new file mode 100755 index 0000000..e5e87f7 --- /dev/null +++ b/emoncms/run/feedwriter @@ -0,0 +1,166 @@ +#!/bin/bash + +### +# +# All Emoncms code is released under the GNU Affero General Public License. +# See COPYRIGHT.txt and LICENSE.txt. +# +# --------------------------------------------------------------------- +# Emoncms - open source energy visualisation +# Part of the OpenEnergyMonitor project: +# http://openenergymonitor.org +# +# Script below thanks to https://github.com/myheathub/mhh +# +### + +### BEGIN INIT INFO +# Provides: feedwriter +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: feedwriter script daemon +# Description: feedwriter persists emoncms data to disk from a redis queue +### END INIT INFO + +# RPI sync control +########### SETTINGS ########## + +## the user that must be used to run the bot +USER=root + +## where rpi is located +RPI_BIN="/var/www/emoncms/run/feedwriter.php" +RPI_SCRIPT="feedwriter.php" + +## where the binary is located +RPI_EXEC=/usr/bin/php + +if [ "$2" = "log" ]; then + echo "Log is turned on" + LOG=1 +else + echo "Log is turned off" + LOG=0 +fi + +########### SETTINGS END ############ + + + + +set -e +DEBUG=off +RPI_PID_FILE="/run/feedwriter.pid" + +if [ ! -f "$RPI_BIN" ]; then + echo "ERROR: file not found : '$RPI_BIN'" + exit 1 +fi +if [ ! -f "$RPI_EXEC" ]; then + echo "ERROR: file not found : '$RPI_EXEC'" + exit 1 +fi +if [ ! -x "$RPI_EXEC" ]; then + echo "ERROR: cannot execute '$RPI_EXEC'" + exit 1 +fi + +if [ "$(whoami)" != "$USER" ]; then + echo "ERROR: you have to run that script as $USER" + exit 1 +fi + +function debug() { + if [ "$DEBUG" = "on" ]; then + echo DEBUG: $@ + fi +} + +function do_start { + cd $(dirname $RPI_BIN) + sleep 7 + + if [ "$LOG" = 1 ]; then + $RPI_EXEC -f $RPI_BIN >> /var/log/feedwriter.log & + echo $! > $RPI_PID_FILE + else + $RPI_EXEC -f $RPI_BIN > /dev/null 2>&1 & + echo $! > $RPI_PID_FILE + fi +} + +function do_stop { + NB_PROCESS=`ps ax | grep $RPI_SCRIPT | grep -v grep | wc -l` + if [ $NB_PROCESS -gt 1 ]; then + echo "ERROR: multiple $RPI_SCRIPT processes found, you'd better kill those processes by hand." + elif [ $NB_PROCESS -eq 1 ]; then + if [ -f $RPI_PID_FILE ]; then + PID=$(cat $RPI_PID_FILE) + NB_PROCESS=`ps hax $PID | grep $RPI_SCRIPT | grep -v grep | wc -l` + if [ $NB_PROCESS -eq 1 ]; then + kill -15 $PID + else + echo "ERROR: process $PID does not seem to be $RPI_SCRIPT" + echo "kill $RPI_SCRIPT by hand" + fi + fi + else + echo " ($RPI_SCRIPT was not running...)" + fi +} + +kill_script() { + PID=`ps hax | grep "$RPI_SCRIPT" | grep -v grep | cut -d' ' -f1 | head -n1` + echo "killing process [$PID]" + kill -9 $PID +} + +case "$1" in + start) + echo "Starting RPI" + NB_PROCESS=`ps ax | grep $RPI_SCRIPT | grep -v grep | wc -l` + if [ $NB_PROCESS -eq 0 ]; then + do_start + else + echo "ERROR: feedwriter is already running" + fi + ;; + stop) + echo -n "Stopping feedwriter: " + do_stop + echo "stopped" + ;; + + restart) + echo -n "Restarting feedwriter" + do_stop + sleep 1 + do_start + ;; + + status) + debug "status:" + NB_PROCESS=`ps ax | grep $RPI_SCRIPT | grep -v grep | wc -l` + debug "NB_PROCESS: $NB_PROCESS" + if [ $NB_PROCESS -gt 1 ]; then + echo "WARNING: multiple $RPI_SCRIPT processes found !" + elif [ $NB_PROCESS -eq 1 ]; then + echo "running" + else + echo "stopped" + fi + ;; + + kill) + kill_script + ;; + *) + PROG_NAME=`basename $0` + echo "Usage: $PROG_NAME {start|stop|restart|status|kill}" + exit 1 +esac + +exit 0 + diff --git a/emoncms/run/feedwriter.php b/emoncms/run/feedwriter.php new file mode 100644 index 0000000..39e9cdf --- /dev/null +++ b/emoncms/run/feedwriter.php @@ -0,0 +1,57 @@ +set_logfile("/var/log/emoncms.log"); + $log->set_topic("FEEDWRITER"); + $log->info("Starting feedwriter process"); + + // Connect to redis + $redis = new Redis(); + while (!$redis->connect("127.0.0.1")) { + sleep(1); + $log->warn("Could not connect to redis, retrying"); + } + + require "Modules/feed/engine/PHPTimeSeries.php"; + require "Modules/feed/engine/PHPFina.php"; + + $engine = array(); + $engine[Engine::PHPTIMESERIES] = new PHPTimeSeries($feed_settings['phptimeseries']); + $engine[Engine::PHPFINA] = new PHPFina($feed_settings['phpfina']); + + while(true) + { + $len = $redis->llen("feedbuffer"); + for ($i=0; $i<$len; $i++) + { + $f = explode(",",$redis->lpop("feedbuffer")); + + $feedid = $f[0]; + $timestamp = $f[1]; + $value = $f[2]; + $padding_mode = (int) $f[3]; + + $e = $redis->hget("feed:$feedid",'engine'); + + if ($padding_mode==1) $engine[Engine::PHPFINA]->padding_mode = 'join'; + $engine[$e]->prepare($feedid,$timestamp,$value); + $engine[Engine::PHPFINA]->padding_mode = 'nan'; + } + + $log->info("PHPTimeSeries bytes written: ".$engine[Engine::PHPTIMESERIES]->save()); + $log->info("PHPFina bytes written: ".$engine[Engine::PHPFINA]->save()); + sleep(60); + } diff --git a/emoncms/scripts/examples/mqtt_feed_subscriber.php b/emoncms/scripts/examples/mqtt_feed_subscriber.php new file mode 100644 index 0000000..6c8306a --- /dev/null +++ b/emoncms/scripts/examples/mqtt_feed_subscriber.php @@ -0,0 +1,21 @@ +connect()){ + exit(1); + } + + $topics["emoncms/#"] = array("qos"=>0, "function"=>"procmsg"); + $mqtt->subscribe($topics,0); + while($mqtt->proc()){ } + $mqtt->close(); + + function procmsg($topic,$value) + { + $time = time(); + print $topic." ".$value."\n"; + } diff --git a/emoncms/scripts/examples/mqtt_input_publisher.php b/emoncms/scripts/examples/mqtt_input_publisher.php new file mode 100644 index 0000000..b1e665f --- /dev/null +++ b/emoncms/scripts/examples/mqtt_input_publisher.php @@ -0,0 +1,35 @@ +connect()) { + + $mqtt->publish("emoncms/input/5","100,200,300",0); + sleep(1); + + $mqtt->publish("emoncms/input/10/power",350.3,0); + sleep(1); + + $mqtt->publish("emoncms/input/house/power",2500,0); + sleep(1); + + $mqtt->publish("emoncms/input/house/temperature",18.2,0); + sleep(1); + + $m = array( + 'apikey'=>"d8e9fa2ccc5c2a9c24bc75cd8596404e", + 'time'=>time(), + 'node'=>1, + 'csv'=>array(200,300,400) + ); + + $mqtt->publish("emoncms/input",json_encode($m),0); + sleep(1); + + + $mqtt->close(); + } + diff --git a/emoncms/scripts/multiuser.md b/emoncms/scripts/multiuser.md new file mode 100644 index 0000000..b0ed2b2 --- /dev/null +++ b/emoncms/scripts/multiuser.md @@ -0,0 +1,24 @@ +MQTT notes: + +add below line 107: + + else + { + // emoncms/input + $m = json_decode($value); + $time = $m->time; + $nodeid = $m->node; + $data = $m->csv; + + $session = $user->apikey_session($m->apikey); + if ($session['write']) + { + $userid = $session['userid']; + $dbinputs = $input->get_inputs($userid); + + $name = 0; + foreach ($data as $value) { + $inputs[] = array("userid"=>$userid, "time"=>$time, "nodeid"=>$nodeid, "name"=>$name++, "value"=>$value); + } + } + } diff --git a/emoncms/scripts/phpmqtt_input.php b/emoncms/scripts/phpmqtt_input.php new file mode 100644 index 0000000..9d41fb7 --- /dev/null +++ b/emoncms/scripts/phpmqtt_input.php @@ -0,0 +1,133 @@ + 1, + 'basetopic' => "rx" + ); + + /* + + MQTT input interface script, subscribes to topic emoncms/input + + Topics: + + emoncms/input/10 100,200,300 + emoncms/input/10/1 100 + emoncms/input/10/power 250 + emoncms/input/house/power 2500 + + * userid has to be set in script, no method of setting timestamp + + Emoncms then processes these inputs in the same way as they would be + if sent to the HTTP Api. + + */ + + // This code is released under the GNU Affero General Public License. + // OpenEnergyMonitor project: + // http://openenergymonitor.org + + define('EMONCMS_EXEC', 1); + + $fp = fopen("runlock", "w"); + if (! flock($fp, LOCK_EX | LOCK_NB)) { echo "Already running\n"; die; } + + chdir("/var/www/emoncms"); + + require "Modules/log/EmonLogger.php"; + + require "process_settings.php"; + $mysqli = @new mysqli($server,$username,$password,$database); + $redis = new Redis(); + $redis->connect("127.0.0.1"); + + require("Lib/phpMQTT.php"); + $mqtt = new phpMQTT("127.0.0.1", 1883, "Emoncms input subscriber"); + + require("Modules/user/user_model.php"); + $user = new User($mysqli,$redis,null); + + include "Modules/feed/feed_model.php"; + $feed = new Feed($mysqli,$redis,$feed_settings); + + require "Modules/input/input_model.php"; // 295 + $input = new Input($mysqli,$redis, $feed); + + require "Modules/input/process_model.php"; // 886 + $process = new Process($mysqli,$input,$feed); + + if(!$mqtt->connect()){ + exit(1); + } + + $topic = $mqttsettings['basetopic']."/#"; + print "Subscribing to: ".$topic."\n"; + + $topics[$topic] = array("qos"=>0, "function"=>"procmsg"); + $mqtt->subscribe($topics,0); + while($mqtt->proc()){ } + $mqtt->close(); + + function procmsg($topic,$value) + { + $time = time(); + print $topic." ".$value."\n"; + + global $mqttsettings, $user, $input, $process, $feed; + + $userid = $mqttsettings['userid']; + + $inputs = array(); + + $route = explode("/",$topic); + + if ($route[0]==$mqttsettings['basetopic']) + { + // nodeid defined in topic: emoncms/input/10 + if (isset($route[1])) + { + $nodeid = $route[1]; + $dbinputs = $input->get_inputs($userid); + + // input id defined in topic: emoncms/input/10/1 + if (isset($route[2])) + { + $inputs[] = array("userid"=>$userid, "time"=>$time, "nodeid"=>$nodeid, "name"=>$route[2], "value"=>$value); + } + else + { + $values = explode(",",$value); + $name = 0; + foreach ($values as $value) { + $inputs[] = array("userid"=>$userid, "time"=>$time, "nodeid"=>$nodeid, "name"=>$name++, "value"=>$value); + } + } + } + } + + $tmp = array(); + foreach ($inputs as $i) + { + $userid = $i['userid']; + $time = $i['time']; + $nodeid = $i['nodeid']; + $name = $i['name']; + $value = $i['value']; + + if (!isset($dbinputs[$nodeid][$name])) { + $inputid = $input->create_input($userid, $nodeid, $name); + $dbinputs[$nodeid][$name] = true; + $dbinputs[$nodeid][$name] = array('id'=>$inputid); + $input->set_timevalue($dbinputs[$nodeid][$name]['id'],$time,$value); + print "set_timevalue\n"; + } else { + $inputid = $dbinputs[$nodeid][$name]['id']; + $input->set_timevalue($dbinputs[$nodeid][$name]['id'],$time,$value); + + if ($dbinputs[$nodeid][$name]['processList']) $tmp[] = array('value'=>$value,'processList'=>$dbinputs[$nodeid][$name]['processList']); + } + } + + foreach ($tmp as $i) $process->input($time,$i['value'],$i['processList']); + + } diff --git a/emoncms/scripts/phpmqtt_input_subtopic.php b/emoncms/scripts/phpmqtt_input_subtopic.php new file mode 100644 index 0000000..bd77e92 --- /dev/null +++ b/emoncms/scripts/phpmqtt_input_subtopic.php @@ -0,0 +1,133 @@ + 14, + 'basetopic' => "rx" + ); + + /* + + MQTT input interface script, subscribes to topic emoncms/input + + Topics: + + emoncms/input/10 100,200,300 + emoncms/input/10/1 100 + emoncms/input/10/power 250 + emoncms/input/house/power 2500 + + * userid has to be set in script, no method of setting timestamp + + Emoncms then processes these inputs in the same way as they would be + if sent to the HTTP Api. + + */ + + // This code is released under the GNU Affero General Public License. + // OpenEnergyMonitor project: + // http://openenergymonitor.org + + define('EMONCMS_EXEC', 1); + + $fp = fopen("runlock", "w"); + if (! flock($fp, LOCK_EX | LOCK_NB)) { echo "Already running\n"; die; } + + chdir("/var/www/emoncms"); + + require "Modules/log/EmonLogger.php"; + + require "process_settings.php"; + $mysqli = @new mysqli($server,$username,$password,$database); + $redis = new Redis(); + $redis->connect("127.0.0.1"); + + require("Lib/phpMQTT.php"); + $mqtt = new phpMQTT("127.0.0.1", 1883, "Emoncms input subscriber"); + + require("Modules/user/user_model.php"); + $user = new User($mysqli,$redis,null); + + include "Modules/feed/feed_model.php"; + $feed = new Feed($mysqli,$redis,$feed_settings); + + require "Modules/input/input_model.php"; // 295 + $input = new Input($mysqli,$redis, $feed); + + require "Modules/input/process_model.php"; // 886 + $process = new Process($mysqli,$input,$feed); + + if(!$mqtt->connect()){ + exit(1); + } + + $topic = $mqttsettings['basetopic']."/#"; + print "Subscribing to: ".$topic."\n"; + + $topics[$topic] = array("qos"=>0, "function"=>"procmsg"); + $mqtt->subscribe($topics,0); + while($mqtt->proc()){ } + $mqtt->close(); + + function procmsg($topic,$value) + { + $time = time(); + print $topic." ".$value."\n"; + + global $mqttsettings, $user, $input, $process, $feed; + + $userid = $mqttsettings['userid']; + + $inputs = array(); + + $route = explode("/",$topic); + + if ($route[0]==$mqttsettings['basetopic']) + { + // nodeid defined in topic: emoncms/input/10 + if (isset($route[1])) + { + $nodeid = $route[1]; + $dbinputs = $input->get_inputs($userid); + + // input id defined in topic: emoncms/input/10/1 + if (isset($route[2])) + { + $inputs[] = array("userid"=>$userid, "time"=>$time, "nodeid"=>$nodeid, "name"=>$route[2], "value"=>$value); + } + else + { + $values = explode(",",$value); + $name = 0; + foreach ($values as $value) { + $inputs[] = array("userid"=>$userid, "time"=>$time, "nodeid"=>$nodeid, "name"=>$name++, "value"=>$value); + } + } + } + } + + $tmp = array(); + foreach ($inputs as $i) + { + $userid = $i['userid']; + $time = $i['time']; + $nodeid = $i['nodeid']; + $name = $i['name']; + $value = $i['value']; + + if (!isset($dbinputs[$nodeid][$name])) { + $inputid = $input->create_input($userid, $nodeid, $name); + $dbinputs[$nodeid][$name] = true; + $dbinputs[$nodeid][$name] = array('id'=>$inputid); + $input->set_timevalue($dbinputs[$nodeid][$name]['id'],$time,$value); + print "set_timevalue\n"; + } else { + $inputid = $dbinputs[$nodeid][$name]['id']; + $input->set_timevalue($dbinputs[$nodeid][$name]['id'],$time,$value); + + if ($dbinputs[$nodeid][$name]['processList']) $tmp[] = array('value'=>$value,'processList'=>$dbinputs[$nodeid][$name]['processList']); + } + } + + foreach ($tmp as $i) $process->input($time,$i['value'],$i['processList']); + + } diff --git a/emonhub/.gitattributes b/emonhub/.gitattributes new file mode 100755 index 0000000..b0ff811 --- /dev/null +++ b/emonhub/.gitattributes @@ -0,0 +1 @@ +README.md merge=ours diff --git a/emonhub/.gitignore b/emonhub/.gitignore new file mode 100755 index 0000000..3bc0777 --- /dev/null +++ b/emonhub/.gitignore @@ -0,0 +1,4 @@ +README.md +*.pyc +*.swp +*.idea diff --git a/emonhub/conf/VEDirect.readme.md b/emonhub/conf/VEDirect.readme.md new file mode 100755 index 0000000..5ba63e2 --- /dev/null +++ b/emonhub/conf/VEDirect.readme.md @@ -0,0 +1,55 @@ +#VE Direct interface Victron products# + +The VE Direct protocol is as binary/ASCII [protocol](https://www.victronenergy.com/upload/documents/VE.Direct-Protocol.pdf) used by [Victron Energy] to communicate between it's products. For those who don't know, Victron is the leading producer of solar inverters and charge controllers designed for the off grid market. + + With this interfacer now it's possible to interface data from any VE Direct compatible Victron product with Emon. In this example we use the [BMV 700](https://www.google.rw/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwi14t-MkqfLAhVBExoKHRGeCioQFggbMAA&url=https%3A%2F%2Fwww.victronenergy.com%2Fbattery-monitors%2Fbmv-700&usg=AFQjCNGENUubkSY_HkWGN61NdkP8onXHag&sig2=XjH6HIbtSzwY_kDDKOfsJw), which is a battery monitor. For emon users that have a battery bank, this will allow them to get stats on their batteries very easily. + +##Usage and configuration## +There is a sample vedirect.emonhub.conf file located in this directory. +This is already preconfigured to talk to a BMV700 that is connect to the emonpi via isolated [USB cable](https://www.victronenergy.com/accessories/ve-direct-to-usb-interface) + +Each VE Direct product has it's own source of variables that it delivers. The full list of variables can be found on Victron's github page as [datalist.py](https://github.com/victronenergy/velib_python/blob/master/dbusmonitor.py). + +This file isn't necessary, but it's just useful as a reference to see which data codes correspond to which values. + + + +###Sample interfacer config within emonhub.conf ### + # Sample configuration for Victron Product with VEDirect connection over USB + # Configuration is for BMV 700 + [[VEDirect]] + Type = EmonHubVEDirectInterfacer + [[[init_settings]]] + com_port = /dev/ttyUSB0 # Where to find our device + com_baud = 19200 # Baud rate needed to decode + toextract = SOC,CE,TTG,V,I,Relay,Alarm # These are the fields we wish to extract, explanation can be seen in datalist.py + poll_interval = 10 # How often to get data in seconds + [[[runtimesettings]]] + nodeoffset = 9 #make sure this matches with nodename below + pubchannels = ToEmonCMS, + subchannels = ToBMV, + basetopic = emonhub/ + + +### Followed by a corresponding Node declaration in emonhub.conf### +In this example our battery monitor will be designated node id 9 + + [[9]] + nodename = emonDC + firmware =V1_6_emonTxV3_4_DiscreteSampling #not used + hardware = emonTx_(NodeID_DIP_Switch1:ON) #not used + [[[rx]]] + names = SOC,CE,TTG,V,I,Relay,Alarm # Make sure this matches 'toextract' in interfacer + datacode = 0 #no need to decode values + scales = 0.1,1,1,0.001,1,1,1 # Some scaling necassary + units =%,Ah,s,V,A,S,S + + +With this config in place now you simply need to restart emonhub on our emonpi by ssh'ing into it and typing + + $>sudo service emonhub restart + +If there are any problems you can debug by looking inside /var/emonhub/emonhub.log + +Hope that helps + diff --git a/emonhub/conf/default/emonhub b/emonhub/conf/default/emonhub new file mode 100755 index 0000000..c6ea86b --- /dev/null +++ b/emonhub/conf/default/emonhub @@ -0,0 +1,17 @@ +## emonHub settings + +# Edit this to configure the parameters used in +# the /etc/init.d/emonhub script. + +# This file should be deployed to /etc/default/emonhub +# unless you have edited the init.d file to give an +# alternate SYSCONF_PATH + +# Specify the directory in which emonhub.py is found: +EMONHUB_PATH=/usr/share/emonhub/ + +# Specify the full config file path: +EMONHUB_CONFIG=/home/pi/data/emonhub.conf + +# Specify the full log file path: +EMONHUB_LOG=/var/log/emonhub/emonhub.log diff --git a/emonhub/conf/emonhub.conf b/emonhub/conf/emonhub.conf new file mode 100755 index 0000000..68a019f --- /dev/null +++ b/emonhub/conf/emonhub.conf @@ -0,0 +1,139 @@ +######################################################### +####################### emonhub.conf ######################### +####################################################################### +### +### SPECIMEN emonHub configuration file +### Note that when installed from apt, a new config file is written +### by the debian/postinst script, so changing this file will do +### nothing in and of itself. +### +### Each Interfacer and each Reporter has +### - a [[name]]: a unique string +### - a type: the name of the class it instantiates +### - a set of init_settings (depends on the type) +### - a set of runtimesettings (depends on the type) +### Both init_settings and runtimesettings sections must be defined, +### even if empty. Init settings are used at initialization, +### and runtime settings are refreshed on a regular basis. +### Many settings below are "commented out" as they are not mandatory and +### have been included as a template or to provide alternative options +### removing the leading # will enable the setting and override the default +### Default settings are shown as comments on the same line as the setting +### eg #(default:xyz) "xyz" is set if the setting is "commented out". +### +### All lines beginning with '###' are comments and can be safely removed. +### +####################################################################### +####################### emonHub settings ####################### +####################################################################### + +[hub] + +### loglevel must be one of DEBUG, INFO, WARNING, ERROR, and CRITICAL +### see here : http://docs.python.org/2/library/logging.html +loglevel = DEBUG #(default:WARNING) + +####################################################################### +####################### Interfacers ####################### +####################################################################### + +[interfacers] + +### This interfacer manages the RFM2Pi module +#[[TESTER_INTERFACE]] +# Type = EmonHubTesterInterfacer +# [[[init_settings]]] +# [[[runtimesettings]]] +# pubchannels = ToCloud, +# subchannels = ToRFM12, + + # datacode = B #(default:h) + # scale = 100 #(default:1) + #group = 210 #(default:210) + #frequency = 433 #(default:433) + #baseid = 5 #(emonPi default:5) + #quiet = false #(default:true) + #calibration = 230V #(UK/EU: 230V, US: 110V) + # interval = 300 #(default:0) + # nodeoffset = 32 #(default:0) + +[[SMILICS_INTERFACE]] + Type = EmonHubSmilicsInterfacer + [[[init_settings]]] + port = 8080 + [[[runtimesettings]]] + pubchannels = ToCloud, + subchannels = ToNothing, + + # datacode = B #(default:h) + # scale = 100 #(default:1) + #group = 210 #(default:210) + #frequency = 433 #(default:433) + #baseid = 5 #(emonPi default:5) + #quiet = false #(default:true) + #calibration = 230V #(UK/EU: 230V, US: 110V) + # interval = 300 #(default:0) + # nodeoffset = 32 #(default:0) + +### This interfacer manages the RFM2Pi module +#[[MQTT]] + + #Type = EmonHubMqttInterfacer + #[[[init_settings]]] + # mqtt_host = 127.0.0.1 + # mqtt_port = 1883 + # mqtt_user = emonpi + # mqtt_passwd = emonpimqtt2016 + + #[[[runtimesettings]]] + # pubchannels = ToRFM12, + # subchannels = ToCloud, + # basetopic = emonhub/ + + +[[scnordic]] + Type = EmonHubSCNordicHTTPInterfacer + [[[init_settings]]] + [[[runtimesettings]]] + pubchannels = ToRFM12, + subchannels = ToCloud, + url = http://scnordic.dev:8000/api/v3 + apikey = 980a907d09dd32232309128ec506176f1a317cde4f0751dd6466ff522f10f0333a2911f0744ebc13473ee89e10b388200f1edd60 + #apikey = fd9b1def9a1cb1f5e387ab153de0332bfb0f3b48d8359ca5384b07c7c8a763eee9d9de33fde04291b8bceac354d8273ab67c3e5a + prev_values_path = /tmp/prev_values.conf + +####################################################################### +####################### Nodes ####################### +####################################################################### + +[nodes] +[[5]] + nodename = emonpi + [[[rx]]] + names = power1,power2,power1pluspower2,vrms,t1,t2,t3,t4,t5,t6,pulsecount + datacodes = h, h, h, h, h, h, h, h, h, h, L + scales = 1,1,1,0.01,0.1,0.1,0.1,0.1,0.1,0.1,1 + units = W,W,W,V,C,C,C,C,C,C,p + senddata = 0,0,0,0,0,0,0,0,0,0,0 + +[[10]] + nodename = EMONTX10 + firmware =V120 + hardware = SC-EmonTx + [[[rx]]] + names = power1, power2, power3, power4, Vrms, pulse, Wh1, Wh2, Wh3, Wh4, RunHours1, RunHours2, RunHours3, RunHours4 + datacodes = h, h, h, h, h, L, l, l, l, l, L, L, L, L + scales = 1, 1, 1, 1, 0.01, 1, 1, 1, 1, 1, 1, 1, 1, 1 + units = W, W, W, W, V, p, Wh, Wh, Wh, Wh, sec, sec, sec, sec + senddata = 0,0,0,0,0,0,1,0,0,0,0,1,0,0,0 + +[[001ec0133c1f]] + nodename = SMILICS01 + firmware =V120 + hardware = Smilics Wibeee + [[[rx]]] + names = power1, power2, power3, power_total, wh1, wh2, wh3, wh_total + datacodes = h, h, h, h, h, h, h, h + scales = 1, 1, 1, 1, 1, 1, 1, 1 + units = W, W, W, W, Wh, Wh, Wh, Wh + senddata = 0,0,0,0,0,0,0,1 \ No newline at end of file diff --git a/emonhub/conf/emonpi.default.emonhub.conf b/emonhub/conf/emonpi.default.emonhub.conf new file mode 100755 index 0000000..be0fc53 --- /dev/null +++ b/emonhub/conf/emonpi.default.emonhub.conf @@ -0,0 +1,188 @@ +####################################################################### +####################### emonhub.conf ######################### +####################################################################### +### emonHub configuration file, for info see documentation: +### http://github.com/openenergymonitor/emonhub/blob/emon-pi/configuration.md +####################################################################### +####################### emonHub settings ####################### +####################################################################### + +[hub] +### loglevel must be one of DEBUG, INFO, WARNING, ERROR, and CRITICAL +loglevel = DEBUG + +####################################################################### +####################### Interfacers ####################### +####################################################################### + +[interfacers] +### This interfacer manages the RFM12Pi/RFM69Pi/emonPi module +[[RFM2Pi]] + Type = EmonHubJeeInterfacer + [[[init_settings]]] + com_port = /dev/ttyAMA0 + com_baud = 38400 # 9600 for old RFM12Pi + [[[runtimesettings]]] + pubchannels = ToEmonCMS, + subchannels = ToRFM12, + + group = 210 + frequency = 433 + baseid = 5 # emonPi / emonBase nodeID + quiet = true # Report incomplete RF packets (no implemented on emonPi) + calibration = 230V # (UK/EU: 230V, US: 110V) + # interval = 0 # Interval to transmit time to emonGLCD (seconds) + +[[MQTT]] + + Type = EmonHubMqttInterfacer + [[[init_settings]]] + mqtt_host = 127.0.0.1 + mqtt_port = 1883 + mqtt_user = emonpi + mqtt_passwd = emonpimqtt2016 + + [[[runtimesettings]]] + pubchannels = ToRFM12, + subchannels = ToEmonCMS, + + # emonhub/rx/10/values format + # Use with emoncms Nodes module + node_format_enable = 1 + node_format_basetopic = emonhub/ + + # emon/emontx/power1 format - use with Emoncms MQTT input + # http://github.com/emoncms/emoncms/blob/master/docs/RaspberryPi/MQTT.md + nodevar_format_enable = 1 + nodevar_format_basetopic = emon/ + +[[emoncmsorg]] + Type = EmonHubEmoncmsHTTPInterfacer + [[[init_settings]]] + [[[runtimesettings]]] + pubchannels = ToRFM12, + subchannels = ToEmonCMS, + url = https://emoncms.org + apikey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + senddata = 1 # Enable sending data to Emoncms.org + sendstatus = 1 # Enable sending WAN IP to Emoncms.org MyIP > https://emoncms.org/myip/list + sendinterval= 30 # Bulk send interval to Emocnms.org in seconds + +####################################################################### +####################### Nodes ####################### +####################################################################### + +[nodes] + +## See config user guide: http://github.com/openenergymonitor/emonhub/blob/master/configuration.md + +[[5]] + nodename = emonpi + [[[rx]]] + names = power1,power2,power1pluspower2,vrms,t1,t2,t3,t4,t5,t6,pulsecount + datacodes = h, h, h, h, h, h, h, h, h, h, L + scales = 1,1,1,0.01,0.1,0.1,0.1,0.1,0.1,0.1,1 + units = W,W,W,V,C,C,C,C,C,C,p + +[[6]] + nodename = emontxshield + [[[rx]]] + names = power1, power2, power3, power4, vrms + datacode = h + scales = 1,1,1,1,0.01 + units =W,W,W,W,V + +[[7]] + nodename = emontx4 + [[[rx]]] + names = power1, power2, power3, power4, vrms, temp1, temp2, temp3, temp4, temp5, temp6, pulse + datacodes = h,h,h,h,h,h,h,h,h,h,h,L + scales = 1,1,1,1,0.01,0.1,0.1, 0.1,0.1,0.1,0.1,1 + units =W,W,W,W,V,C,C,C,C,C,C,p + +[[8]] + nodename = emontx3 + [[[rx]]] + names = power1, power2, power3, power4, vrms, temp1, temp2, temp3, temp4, temp5, temp6, pulse + datacodes = h,h,h,h,h,h,h,h,h,h,h,L + scales = 1,1,1,1,0.01,0.1,0.1, 0.1,0.1,0.1,0.1,1 + units =W,W,W,W,V,C,C,C,C,C,C,p + +[[9]] + nodename = emontx2 + [[[rx]]] + names = power1, power2, power3, power4, vrms, temp1, temp2, temp3, temp4, temp5, temp6, pulse + datacode = h + scales = 1,1,1,1,0.01,0.1,0.1, 0.1,0.1,0.1,0.1,1 + units =W,W,W,W,V,C,C,C,C,C,C,p + +[[10]] + nodename = emontx1 + [[[rx]]] + names = power1, power2, power3, power4, vrms, temp1, temp2, temp3, temp4, temp5, temp6, pulse + datacode = h + scales = 1,1,1,1,0.01,0.1,0.1, 0.1,0.1,0.1,0.1,1 + units =W,W,W,W,V,C,C,C,C,C,C,p + +[[19]] + nodename = emonth1 + [[[rx]]] + names = temperature, external temperature, humidity, battery + datacode = h + scales = 0.1,0.1,0.1,0.1 + units = C,C,%,V + +[[20]] + nodename = emonth2 + [[[rx]]] + names = temperature, external temperature, humidity, battery + datacode = h + scales = 0.1,0.1,0.1,0.1 + units = C,C,%,V + +[[21]] + nodename = emonth3 + [[[rx]]] + names = temperature, external temperature, humidity, battery + datacode = h + scales = 0.1,0.1,0.1,0.1 + units = C,C,%,V + +[[22]] + nodename = emonth4 + [[[rx]]] + names = temperature, external temperature, humidity, battery + datacode = h + scales = 0.1,0.1,0.1,0.1 + units = C,C,%,V +[[23]] + nodename = emonth5 + [[[rx]]] + names = temperature, external temperature, humidity, battery, pulsecount + datacodes = h,h,h,h,L + scales = 0.1,0.1,0.1,0.1,1 + units = C,C,%,V,p + +[[24]] + nodename = emonth6 + [[[rx]]] + names = temperature, external temperature, humidity, battery, pulsecount + datacodes = h,h,h,h,L + scales = 0.1,0.1,0.1,0.1,1 + units = C,C,%,V,p + +[[25]] + nodename = emonth7 + [[[rx]]] + names = temperature, external temperature, humidity, battery, pulsecount + datacodes = h,h,h,h,L + scales = 0.1,0.1,0.1,0.1,1 + units = C,C,%,V,p + +[[26]] + nodename = emonth8 + [[[rx]]] + names = temperature, external temperature, humidity, battery, pulsecount + datacodes = h,h,h,h,L + scales = 0.1,0.1,0.1,0.1,1 + units = C,C,%,V,p diff --git a/emonhub/conf/nodes/10 b/emonhub/conf/nodes/10 new file mode 100755 index 0000000..7c62615 --- /dev/null +++ b/emonhub/conf/nodes/10 @@ -0,0 +1,12 @@ +[[10]] + nodename = emonTx_1 + firmware =V1_6_emonTxV3_4_DiscreteSampling + hardware = emonTx_(NodeID_DIP_Switch1:OFF) + [[[rx]]] + names = power1, power2, power3, power4, Vrms, temp1, temp2, temp3, temp4, temp5, temp6, pulse #Firmware V1.6 + #names = power1, power2, power3, power4, Vrms, temp #Firmware => $emonhub_location + echo "">>$emonhub_location + echo "Added node $var to emonhub.conf" + fi + else + echo "Node $var already present" + fi +done diff --git a/emonhub/conf/old.default.emonhub.conf b/emonhub/conf/old.default.emonhub.conf new file mode 100755 index 0000000..a08a1dc --- /dev/null +++ b/emonhub/conf/old.default.emonhub.conf @@ -0,0 +1,194 @@ +####################################################################### +####################### emonhub.conf ######################### +####################################################################### + +## **LEGACY CONFIG: For use with 17thJune2015 emonPi/emonBase image and older ** +## (check image version by looking for file in /boot) +## Uses old CSV MQTT topic structure compatible with Emoncms Nodes +## Does not use MQTT server authentication + +### emonHub configuration file, for info see documentation: +### http://github.com/openenergymonitor/emonhub/blob/master/configuration.md +####################################################################### +####################### emonHub settings ####################### +####################################################################### + +[hub] +### loglevel must be one of DEBUG, INFO, WARNING, ERROR, and CRITICAL +loglevel = DEBUG #(default:WARNING) + +####################################################################### +####################### Interfacers ####################### +####################################################################### + +[interfacers] +### This interfacer manages the RFM12Pi/RFM69Pi/emonPi module +[[RFM2Pi]] + Type = EmonHubJeeInterfacer + [[[init_settings]]] + com_port = /dev/ttyAMA0 + com_baud = 38400 # 9600 for old RFM12Pi modules + [[[runtimesettings]]] + pubchannels = ToEmonCMS, + subchannels = ToRFM12, + + group = 210 + frequency = 433 + baseid = 5 # emonPi / emonBase nodeID + quiet = true # Report incomplete RF packets (no implemented on emonPi) + calibration = 230V # (UK/EU: 230V, US: 110V) + # interval = 0 # Interval to transmit time to emonGLCD (seconds) + +[[MQTT]] + + Type = EmonHubMqttInterfacer + [[[init_settings]]] + mqtt_host = 127.0.0.1 + mqtt_port = 1883 + mqtt_user = '' + mqtt_passwd = '' + + [[[runtimesettings]]] + pubchannels = ToRFM12, + subchannels = ToEmonCMS, + + # emonhub/rx/10/values format + # Use with emoncms Nodes module + node_format_enable = 1 + node_format_basetopic = emonhub/ + + # emon/emontx/power1 format - use with Emoncms MQTT input + # http://github.com/emoncms/emoncms/blob/master/docs/RaspberryPi/MQTT.md + nodevar_format_enable = 0 + nodevar_format_basetopic = emon/ + +[[emoncmsorg]] + Type = EmonHubEmoncmsHTTPInterfacer + [[[init_settings]]] + [[[runtimesettings]]] + pubchannels = ToRFM12, + subchannels = ToEmonCMS, + url = https://emoncms.org + apikey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + senddata = 1 # Enable sending data to Emoncms.org + sendstatus = 1 # Enable sending WAN IP to Emoncms.org MyIP > https://emoncms.org/myip/list + sendinterval= 30 # Bulk send interval to Emocnms.org in seconds + +####################################################################### +####################### Nodes ####################### +####################################################################### + +[nodes] + +## See config user guide: http://github.com/openenergymonitor/emonhub/blob/master/configuration.md + +[[5]] + nodename = emonpi + [[[rx]]] + names = power1,power2,power1pluspower2,vrms,t1,t2,t3,t4,t5,t6,pulsecount + datacodes = h, h, h, h, h, h, h, h, h, h, L + scales = 1,1,1,0.01,0.1,0.1,0.1,0.1,0.1,0.1,1 + units = W,W,W,V,C,C,C,C,C,C,p + +[[6]] + nodename = emontxshield + [[[rx]]] + names = power1, power2, power3, power4, vrms + datacode = h + scales = 1,1,1,1,0.01 + units =W,W,W,W,V + +[[7]] + nodename = emontx4 + [[[rx]]] + names = power1, power2, power3, power4, vrms, temp1, temp2, temp3, temp4, temp5, temp6, pulse + datacodes = h,h,h,h,h,h,h,h,h,h,h,L + scales = 1,1,1,1,0.01,0.1,0.1, 0.1,0.1,0.1,0.1,1 + units =W,W,W,W,V,C,C,C,C,C,C,p + +[[8]] + nodename = emontx3 + [[[rx]]] + names = power1, power2, power3, power4, vrms, temp1, temp2, temp3, temp4, temp5, temp6, pulse + datacodes = h,h,h,h,h,h,h,h,h,h,h,L + scales = 1,1,1,1,0.01,0.1,0.1, 0.1,0.1,0.1,0.1,1 + units =W,W,W,W,V,C,C,C,C,C,C,p + +[[9]] + nodename = emontx2 + [[[rx]]] + names = power1, power2, power3, power4, vrms, temp1, temp2, temp3, temp4, temp5, temp6, pulse + datacode = h + scales = 1,1,1,1,0.01,0.1,0.1, 0.1,0.1,0.1,0.1,1 + units =W,W,W,W,V,C,C,C,C,C,C,p + +[[10]] + nodename = emontx1 + [[[rx]]] + names = power1, power2, power3, power4, vrms, temp1, temp2, temp3, temp4, temp5, temp6, pulse + datacode = h + scales = 1,1,1,1,0.01,0.1,0.1, 0.1,0.1,0.1,0.1,1 + units =W,W,W,W,V,C,C,C,C,C,C,p + +[[19]] + nodename = emonth1 + [[[rx]]] + names = temperature, external temperature, humidity, battery + datacode = h + scales = 0.1,0.1,0.1,0.1 + units = C,C,%,V + +[[20]] + nodename = emonth2 + [[[rx]]] + names = temperature, external temperature, humidity, battery + datacode = h + scales = 0.1,0.1,0.1,0.1 + units = C,C,%,V + +[[21]] + nodename = emonth3 + [[[rx]]] + names = temperature, external temperature, humidity, battery + datacode = h + scales = 0.1,0.1,0.1,0.1 + units = C,C,%,V + +[[22]] + nodename = emonth4 + [[[rx]]] + names = temperature, external temperature, humidity, battery + datacode = h + scales = 0.1,0.1,0.1,0.1 + units = C,C,%,V +[[23]] + nodename = emonth5 + [[[rx]]] + names = temperature, external temperature, humidity, battery, pulsecount + datacodes = h,h,h,h,L + scales = 0.1,0.1,0.1,0.1,1 + units = C,C,%,V,p + +[[24]] + nodename = emonth6 + [[[rx]]] + names = temperature, external temperature, humidity, battery, pulsecount + datacodes = h,h,h,h,L + scales = 0.1,0.1,0.1,0.1,1 + units = C,C,%,V,p + +[[25]] + nodename = emonth7 + [[[rx]]] + names = temperature, external temperature, humidity, battery, pulsecount + datacodes = h,h,h,h,L + scales = 0.1,0.1,0.1,0.1,1 + units = C,C,%,V,p + +[[26]] + nodename = emonth8 + [[[rx]]] + names = temperature, external temperature, humidity, battery, pulsecount + datacodes = h,h,h,h,L + scales = 0.1,0.1,0.1,0.1,1 + units = C,C,%,V,p diff --git a/emonhub/conf/vedirect.emonhub.conf b/emonhub/conf/vedirect.emonhub.conf new file mode 100755 index 0000000..aeee4b4 --- /dev/null +++ b/emonhub/conf/vedirect.emonhub.conf @@ -0,0 +1,60 @@ +####################################################################### +####################### emonhub.conf ######################### +####################################################################### + +## **LEGACY CONFIG: For use with 17thJune2015 emonPi/emonBase image and older ** +## (check image version by looking for file in /boot) +## Uses old CSV MQTT topic structure compatible with Emoncms Nodes +## Does not use MQTT server authentication + +### emonHub configuration file, for info see documentation: +### http://github.com/openenergymonitor/emonhub/blob/master/configuration.md +####################################################################### +####################### emonHub settings ####################### +####################################################################### + +[hub] +### loglevel must be one of DEBUG, INFO, WARNING, ERROR, and CRITICAL +loglevel = DEBUG #(default:WARNING) + +####################################################################### +####################### Interfacers ####################### +####################################################################### + +[interfacers] +### This interfacer manages the RFM12Pi/RFM69Pi/emonPi module + +# Sample configuration for Victron Product with VEDirect connection over USB +# Configuration is for BMV 700 +[[VEDirect]] + Type = EmonHubVEDirectInterfacer + [[[init_settings]]] + com_port = /dev/ttyUSB0 + com_baud = 19200 + toextract = SOC,CE,TTG,V,I,Relay,Alarm # These are the fields we wish to extract + poll_interval = 10 # More fields can be found in datalist.py + [[[runtimesettings]]] + nodeoffset = 9 #make sure this matches with nodename below + pubchannels = ToEmonCMS, + subchannels = ToBMV, + basetopic = emonhub/ + + +####################################################################### +####################### Nodes ####################### +####################################################################### + +[nodes] + +## See config user guide: http://github.com/openenergymonitor/emonhub/blob/master/configuration.md + + +[[9]] + nodename = emonDC + firmware =V1_6_emonTxV3_4_DiscreteSampling + hardware = emonTx_(NodeID_DIP_Switch1:ON) + [[[rx]]] + names = SOC,CE,TTG,V,I,Relay,Alarm # Make sure this matches 'toextract' in interfacer + datacode = 0 + scales = 0.1,1,1,0.001,1,1,1 + units =%,Ah,s,V,A,S,S #FirmwareV1.6 diff --git a/emonhub/configuration.md b/emonhub/configuration.md new file mode 100755 index 0000000..e9d6fc1 --- /dev/null +++ b/emonhub/configuration.md @@ -0,0 +1,110 @@ +######################################################### +####################### emonhub.conf ######################### +####################################################################### +### +### SPECIMEN emonHub configuration file +### Note that when installed from apt, a new config file is written +### by the debian/postinst script, so changing this file will do +### nothing in and of itself. +### +### Each Interfacer and each Reporter has +### - a [[name]]: a unique string +### - a type: the name of the class it instantiates +### - a set of init_settings (depends on the type) +### - a set of runtimesettings (depends on the type) +### Both init_settings and runtimesettings sections must be defined, +### even if empty. Init settings are used at initialization, +### and runtime settings are refreshed on a regular basis. +### Many settings below are "commented out" as they are not mandatory and +### have been included as a template or to provide alternative options +### removing the leading # will enable the setting and override the default +### Default settings are shown as comments on the same line as the setting +### eg #(default:xyz) "xyz" is set if the setting is "commented out". +### +### All lines beginning with '###' are comments and can be safely removed. +### +####################################################################### +####################### emonHub settings ####################### +####################################################################### + +[hub] + +### loglevel must be one of DEBUG, INFO, WARNING, ERROR, and CRITICAL +### see here : http://docs.python.org/2/library/logging.html +loglevel = DEBUG #(default:WARNING) + +####################################################################### +####################### Interfacers ####################### +####################################################################### + +[interfacers] + +### This interfacer manages the RFM2Pi module +[[RFM2Pi]] + Type = EmonHubJeeInterfacer + [[[init_settings]]] + com_port = /dev/ttyAMA0 + com_baud = 38400 + [[[runtimesettings]]] + pubchannels = ToCloud, + subchannels = ToRFM12, + + # datacode = B #(default:h) + # scale = 100 #(default:1) + group = 210 #(default:210) + frequency = 433 #(default:433) + baseid = 5 #(emonPi default:5) + quiet = false #(default:true) + calibration = 230V #(UK/EU: 230V, US: 110V) + # interval = 300 #(default:0) + # nodeoffset = 32 #(default:0) + +### This interfacer manages the RFM2Pi module +[[MQTT]] + + Type = EmonHubMqttInterfacer + [[[init_settings]]] + mqtt_host = 127.0.0.1 + mqtt_port = 1883 + mqtt_user = emonpi + mqtt_passwd = emonpimqtt2016 + + [[[runtimesettings]]] + pubchannels = ToRFM12, + subchannels = ToEmonCMS, + basetopic = emonhub/ + + +[[scnordic]] + Type = EmonHubSCNordicHTTPInterfacer + [[[init_settings]]] + [[[runtimesettings]]] + pubchannels = ToRFM12, + subchannels = ToCloud, + url = https://scsmartgrid.dk/api/v3 + apikey = fd9b1def9a1cb1f5e387ab153de0332bfb0f3b48d8359ca5384b07c7c8a763eee9d9de33fde04291b8bceac354d8273ab67c3e5a + +####################################################################### +####################### Nodes ####################### +####################################################################### + +[nodes] +[[5]] + nodename = emonpi + [[[rx]]] + names = power1,power2,power1pluspower2********,vrms,t1,t2,t3,t4,t5,t6,pulsecount + datacodes = h, h, h, h, h, h, h, h, h, h, L + scales = 1,1,1,0.01,0.1,0.1,0.1,0.1,0.1,0.1,1 + units = W,W,W,V,C,C,C,C,C,C,p + senddata = 0,0,0,0,0,0,0,0,0,0,0 + +[[10]] + nodename = EMONTX10 + firmware =V120 + hardware = SC-EmonTx + [[[rx]]] + names = power1, power2, power3, power4, Vrms, pulse, Wh1, Wh2, Wh3, Wh4 + datacodes = h, h, h, h, h, L, l, l, l, l + scales = 1, 1, 1, 1, 0.01, 1, 1, 1, 1, 1 + units = W, W, W, W, V, p, Wh, Wh, Wh, Wh + senddata = 0,0,0,0,0,0,1,1,1,1 \ No newline at end of file diff --git a/emonhub/examples/control_sender.py b/emonhub/examples/control_sender.py new file mode 100755 index 0000000..889b7e6 --- /dev/null +++ b/emonhub/examples/control_sender.py @@ -0,0 +1,16 @@ +import time +import paho.mqtt.client as mqtt + +client = mqtt.Client() +client.connect("127.0.0.1", 1883, 60) + +while True: + topic = "emonhub/tx/30/values" + payload = "1,1850" + client.publish(topic, payload=payload, qos=0, retain=False) + # client.loop() + time.sleep(5.0) + payload = "0,1850" + client.publish(topic, payload=payload, qos=0, retain=False) + # client.loop() + time.sleep(5.0) diff --git a/emonhub/examples/mqtt_reader.py b/emonhub/examples/mqtt_reader.py new file mode 100755 index 0000000..765eb5b --- /dev/null +++ b/emonhub/examples/mqtt_reader.py @@ -0,0 +1,18 @@ +import time +import paho.mqtt.client as mqtt + +def on_connect(client, userdata, rc): + print("Connected with result code "+str(rc)) + client.subscribe("emonhub/#") + +def on_message(client, userdata, msg): + print(msg.topic+" "+str(msg.payload)) + +client = mqtt.Client() +client.on_connect = on_connect +client.on_message = on_message +client.connect("127.0.0.1", 1883, 60) + +while True: + client.loop() + time.sleep(0.1) diff --git a/emonhub/install b/emonhub/install new file mode 100755 index 0000000..c1741b1 --- /dev/null +++ b/emonhub/install @@ -0,0 +1,43 @@ +#!/bin/sh + +echo "Emonhub installation script for emonPi" + +### set git cloned location +GIT_PATH=/home/pi/emonhub + +if [ ! -d /home/pi ] ; then + { + echo "Directory /home/pi does not exist, this installation script is for raspberrypi installation" + exit + } +fi + + +### set location to install emonhub.py etc +INST_PATH=/usr/share/emonhub + +### create linked directory for emonhub.py etc +sudo rm -r -f $INST_PATH +sudo ln -s $GIT_PATH/src $INST_PATH + +### link init script +sudo rm -f /etc/init.d/emonhub +sudo ln -s $GIT_PATH/service/emonhub /etc/init.d/emonhub + +### link default locations file +sudo rm -f /etc/default/emonhub +sudo ln -s $GIT_PATH/conf/default/emonhub /etc/default/emonhub + +### create folder and move settings file (unless it exists already) +if [ ! -f /home/pi/data/emonhub.conf ] ; then + { + sudo mv $GIT_PATH/conf/emonpi.default.emonhub.conf /home/pi/data/emonhub.conf + } +fi + +# launch at start-ip +sudo update-rc.d emonhub defaults 99 + + +### create "emonhub" user +sudo useradd -M -r -G dialout,tty -c "emonHub user" emonhub diff --git a/emonhub/run.sh b/emonhub/run.sh new file mode 100755 index 0000000..2fdcbe2 --- /dev/null +++ b/emonhub/run.sh @@ -0,0 +1 @@ +mosquitto -c /usr/local/etc/mosquitto/mosquitto.conf diff --git a/emonhub/service/emonhub b/emonhub/service/emonhub new file mode 100755 index 0000000..74b7a99 --- /dev/null +++ b/emonhub/service/emonhub @@ -0,0 +1,239 @@ +#! /bin/sh + +### +# +# This code is released under the GNU Affero General Public License. +# +# OpenEnergyMonitor project: +# http://openenergymonitor.org +# +### + +### BEGIN INIT INFO +# Provides: emonhub +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start/stop emonHub +### END INIT INFO + +NAME=emonhub +DAEMONUSER="emonhub" +SYSCONF_PATH=/etc/default/ + +# If there's no configuration file, die!! +[ ! -f $SYSCONF_PATH$NAME ] && echo "Fatal: cannot find $SYSCONF_FILE$NAME config file!" && exit 1 + +# Pull in the config settings and echo them out for easy troubleshooting. +. $SYSCONF_PATH$NAME + +[ ! -f $EMONHUB_CONFIG ] && echo "Fatal: cannot find $EMONHUB_CONFIG" && exit 1 +[ ! -f $EMONHUB_PATH$NAME.py ] && echo "Fatal: cannot find $EMONHUB_PATH$NAME.py" && exit 1 +[ ! -f $EMONHUB_LOG ] && sudo mkdir -p "$(dirname "$EMONHUB_LOG")" && sudo touch "$EMONHUB_LOG" && sudo chown -R $DAEMONUSER "$(dirname "$EMONHUB_LOG")" +sudo chown -R $DAEMONUSER "$(dirname "$EMONHUB_LOG")" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="OpenEnergyMonitor emonHub" +# Enter your installation path here +DAEMON=$EMONHUB_PATH$NAME.py + +# Specify command line arguments here +DAEMON_ARGS="--logfile $EMONHUB_LOG --config-file $EMONHUB_CONFIG" + +PIDFILE=/var/run/$NAME.pid +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || echo "Not starting - cannot find $DAEMON" || exit 1 + +# Exit if not run as root +case `id -u` in + 0) ;; + *) echo "This script must be run as root" >&2; exit 1 ;; +esac + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh +# Override VERBOSE setting +VERBOSE=yes + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() { + do_status + case "$?" in + 0) return 1 ;; + 1) rm -f $PIDFILE;; + 3) ;; + 4) PID=`ps -ef | grep '[p]ython '$DAEMON | awk '{ print $2 }'` + echo "$PID" > $PIDFILE;; + *) return "$?" ;; + esac + start-stop-daemon --start --quiet --background --make-pidfile --chuid=$DAEMONUSER --pidfile $PIDFILE --startas $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --background --no-close --make-pidfile --chuid=$DAEMONUSER --pidfile $PIDFILE --startas $DAEMON -- \ + $DAEMON_ARGS \ + || return 2 + # Add code here, if necessary, that waits for the process to be ready + # to handle requests from services started subsequently which depend + # on this one. As a last resort, sleep for some time. +} + +# +# Function that stops the daemon/service +# +do_stop() { + do_status + case "$?" in + 0) ;; + 1) rm -f $PIDFILE;; + 3) return 1 ;; + 4) PID=`ps -ef | grep '[p]ython '$DAEMON | awk '{ print $2 }'` + echo "$PID" > $PIDFILE;; + *) return "$?" ;; + esac + start-stop-daemon --stop --quiet --retry=INT/30/KILL/5 --pidfile $PIDFILE >/dev/null || RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + rm -f $PIDFILE + return "$?" +} + +# +# Function that restarts the daemon/service +# +do_restart() { + do_stop + case "$?" in + 0|1) ;; + *) return 2;; + esac + do_start + [ "$?" = 0 ] && return 0 + return 2 +} + +# +# Function that status checks the daemon/service +# +do_status() { + status="0" + pidofproc -p $PIDFILE $DAEMON >/dev/null || status="$?" + if [ "$status" = 3 ]; then + pid=`ps -ef | grep '[p]ython '$DAEMON | awk '{ print $2 }'` + [ "$pid" != "" ] && return 4 + fi + return $status +} + +# +# Function that sends a SIGHUP to the daemon/service +# +#do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # +# start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME +# return 0 +#} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0) [ "$VERBOSE" != no ] && log_progress_msg "has been started ok" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 1) [ "$VERBOSE" != no ] && log_progress_msg "is already running" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_progress_msg "start attempt" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + *) [ "$VERBOSE" != no ] && log_progress_msg "error: $?" + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0) [ "$VERBOSE" != no ] && log_progress_msg "has been stopped ok" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 1) [ "$VERBOSE" != no ] && log_progress_msg "had already stopped" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_progress_msg "stop attempt" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + *) [ "$VERBOSE" != no ] && log_progress_msg "error: $?" + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + [ "$VERBOSE" != no ] && log_daemon_msg "Checking $DESC" "$NAME" + do_status + case "$?" in + 0) [ "$VERBOSE" != no ] && log_progress_msg "process is running" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 1) [ "$VERBOSE" != no ] && log_progress_msg "process has" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + 3) [ "$VERBOSE" != no ] && log_progress_msg "process not running" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 4) [ "$VERBOSE" != no ] && log_progress_msg "running but PID file has" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + *) [ "$VERBOSE" != no ] && log_progress_msg "status unknown as checks" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + [ "$VERBOSE" != no ] && log_daemon_msg "Restarting $DESC" "$NAME" + do_restart + case "$?" in + 0) [ "$VERBOSE" != no ] && log_progress_msg "has been restarted ok" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_progress_msg "restart attempt has" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + *) [ "$VERBOSE" != no ] && log_progress_msg "error: $?" + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + killp) + # use only for crash testing - kills process without removing the pid file + # also used to "tidy up" a process that's missing it's pid file (eg if rmpid used) + # can be commented out or deleted, (not included in "Usage" help list). + pid=`ps -ef | grep '[p]ython '$DAEMON | awk '{ print $2 }'` + [ "$pid" != "" ] && kill -9 "${pid:-}" + ;; + rmpid) + # use only for crash testing - removes the pid file without killing process + # also used to "tidy up" a crashed process's redundant pid file (eg if killp used) + # can be commented out or deleted, (not included in "Usage" help list). + [ -e $PIDFILE ] && rm $PIDFILE + ;; + *) + #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/emonhub/src/emonhub.py b/emonhub/src/emonhub.py new file mode 100755 index 0000000..83f5b55 --- /dev/null +++ b/emonhub/src/emonhub.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python + +""" + + This code is released under the GNU Affero General Public License. + + OpenEnergyMonitor project: + http://openenergymonitor.org + +""" + +import sys +import time +import logging +import logging.handlers +import signal +import argparse +import pprint +import traceback + +import emonhub_setup as ehs +import interfacers.emonhub_interfacer as ehi +import emonhub_coder as ehc + +import interfacers.EmonHubSerialInterfacer +import interfacers.EmonHubJeeInterfacer +import interfacers.EmonHubSocketInterfacer +import interfacers.EmonHubPacketGenInterfacer +import interfacers.EmonHubMqttInterfacer +import interfacers.EmonHubTesterInterfacer +import interfacers.EmonHubEmoncmsHTTPInterfacer +import interfacers.EmonHubSCNordicHTTPInterfacer +import interfacers.EmonHubSmilicsInterfacer + +ehi.EmonHubSerialInterfacer = interfacers.EmonHubSerialInterfacer.EmonHubSerialInterfacer +ehi.EmonHubJeeInterfacer = interfacers.EmonHubJeeInterfacer.EmonHubJeeInterfacer +ehi.EmonHubSocketInterfacer = interfacers.EmonHubSocketInterfacer.EmonHubSocketInterfacer +ehi.EmonHubPacketGenInterfacer = interfacers.EmonHubPacketGenInterfacer.EmonHubPacketGenInterfacer +ehi.EmonHubMqttInterfacer = interfacers.EmonHubMqttInterfacer.EmonHubMqttInterfacer +ehi.EmonHubTesterInterfacer = interfacers.EmonHubTesterInterfacer.EmonHubTesterInterfacer +ehi.EmonHubEmoncmsHTTPInterfacer = interfacers.EmonHubEmoncmsHTTPInterfacer.EmonHubEmoncmsHTTPInterfacer +ehi.EmonHubSCNordicHTTPInterfacer = interfacers.EmonHubSCNordicHTTPInterfacer.EmonHubSCNordicHTTPInterfacer +ehi.EmonHubSmilicsInterfacer = interfacers.EmonHubSmilicsInterfacer.EmonHubSmilicsInterfacer + +"""class EmonHub + +Monitors data inputs through EmonHubInterfacer instances, +and (currently) sends data to +target servers through EmonHubEmoncmsReporter instances. + +Controlled by the user via EmonHubSetup + +""" + +class EmonHub(object): + + __version__ = "emonHub 'emon-pi' variant v1.1" + + def __init__(self, setup): + """Setup an OpenEnergyMonitor emonHub. + + Interface (EmonHubSetup): User interface to the hub. + + """ + + # Initialize exit request flag + self._exit = False + + # Initialize setup and get settings + self._setup = setup + settings = self._setup.settings + + # Initialize logging + self._log = logging.getLogger("EmonHub") + self._set_logging_level('WARNING', False) + self._log.info("EmonHub %s" % self.__version__) + self._log.info("Opening hub...") + + # Initialize Interfacers + self._interfacers = {} + + # Update settings + self._update_settings(settings) + + def run(self): + """Launch the hub. + + Monitor the interfaces and process data. + Check settings on a regular basis. + + """ + + # Set signal handler to catch SIGINT and shutdown gracefully + signal.signal(signal.SIGINT, self._sigint_handler) + + # Until asked to stop + while not self._exit: + + # Run setup and update settings if modified + self._setup.run() + if self._setup.check_settings(): + self._update_settings(self._setup.settings) + + # For all Interfacers + for I in self._interfacers.itervalues(): + # Check thread is still running + if not I.isAlive(): + #I.start() + self._log.warning(I.name + " thread is dead") # had to be restarted") + + # Sleep until next iteration + time.sleep(0.2) + + def close(self): + """Close hub. Do some cleanup before leaving.""" + + self._log.info("Exiting hub...") + + for I in self._interfacers.itervalues(): + I.stop = True + I.join() + + self._log.info("Exit completed") + logging.shutdown() + + def _sigint_handler(self, signal, frame): + """Catch SIGINT (Ctrl+C).""" + + self._log.debug("SIGINT received.") + # hub should exit at the end of current iteration. + self._exit = True + + def _update_settings(self, settings): + """Check settings and update if needed.""" + + # EmonHub Logging level + if 'loglevel' in settings['hub']: + self._set_logging_level(settings['hub']['loglevel']) + else: + self._set_logging_level() + + # Create a place to hold buffer contents whilst a deletion & rebuild occurs + self.temp_buffer = {} + + # Interfacers + for name in self._interfacers.keys(): + # Delete interfacers if not listed or have no 'Type' in the settings without further checks + # (This also provides an ability to delete & rebuild by commenting 'Type' in conf) + if not name in settings['interfacers'] or not 'Type' in settings['interfacers'][name]: + pass + else: + try: + # test for 'init_settings' and 'runtime_setting' sections + settings['interfacers'][name]['init_settings'] + settings['interfacers'][name]['runtimesettings'] + except Exception as e: + # If interfacer's settings are incomplete, continue without updating + self._log.error("Unable to update '" + name + "' configuration: " + str(e)) + continue + else: + # check init_settings against the file copy, if they are the same move on to the next + if self._interfacers[name].init_settings == settings['interfacers'][name]['init_settings']: + continue + # Delete interfacers if setting changed or name is unlisted or Type is missing + self._log.info("Deleting interfacer '%s' ", name) + self._interfacers[name].stop = True + del(self._interfacers[name]) + + for name, I in settings['interfacers'].iteritems(): + # If interfacer does not exist, create it + if name not in self._interfacers: + try: + if not 'Type' in I: + continue + self._log.info("Creating " + I['Type'] + " '%s' ", name) + # This gets the class from the 'Type' string + interfacer = getattr(ehi, I['Type'])(name, **I['init_settings']) + interfacer.set(**I['runtimesettings']) + interfacer.init_settings = I['init_settings'] + interfacer.start() + except ehi.EmonHubInterfacerInitError as e: + # If interfacer can't be created, log error and skip to next + self._log.error("Failed to create '" + name + "' interfacer: " + str(e)) + continue + except Exception as e: + # If interfacer can't be created, log error and skip to next + self._log.error("Unable to create '" + name + "' interfacer: " + str(e)) + traceback.print_exc() + continue + else: + self._interfacers[name] = interfacer + else: + # Otherwise just update the runtime settings if possible + if 'runtimesettings' in I: + self._interfacers[name].set(**I['runtimesettings']) + + if 'nodes' in settings: + ehc.nodelist = settings['nodes'] + + def _set_logging_level(self, level='WARNING', log=True): + """Set logging level. + + level (string): log level name in + ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL') + + """ + + # Ensure "level" is all upper case + level = level.upper() + + # Check level argument is valid + try: + loglevel = getattr(logging, level) + except AttributeError: + self._log.error('Logging level %s invalid' % level) + return False + except Exception as e: + self._log.error('Logging level %s ' % str(e)) + return False + + # Change level if different from current level + if loglevel != self._log.getEffectiveLevel(): + self._log.setLevel(level) + if log: + self._log.info('Logging level set to %s' % level) + + +if __name__ == "__main__": + + # Command line arguments parser + parser = argparse.ArgumentParser(description='OpenEnergyMonitor emonHub') + + # Configuration file + parser.add_argument("--config-file", action="store", + help='Configuration file', default=sys.path[0]+'/../conf/emonhub.conf') + # Log file + parser.add_argument('--logfile', action='store', type=argparse.FileType('a'), + help='Log file (default: log to Standard error stream STDERR)') + # Show settings + parser.add_argument('--show-settings', action='store_true', + help='show settings and exit (for debugging purposes)') + # Show version + parser.add_argument('--version', action='store_true', + help='display version number and exit') + # Parse arguments + args = parser.parse_args() + + # Display version number and exit + if args.version: + print('emonHub %s' % EmonHub.__version__) + sys.exit() + + # Logging configuration + logger = logging.getLogger("EmonHub") + if args.logfile is None: + # If no path was specified, everything goes to sys.stderr + loghandler = logging.StreamHandler() + else: + # Otherwise, rotating logging over two 5 MB files + # If logfile is supplied, argparse opens the file in append mode, + # this ensures it is writable + # Close the file for now and get its path + args.logfile.close() + loghandler = logging.handlers.RotatingFileHandler(args.logfile.name, + 'a', 5000 * 1024, 1) + # Format log strings + loghandler.setFormatter(logging.Formatter( + '%(asctime)s %(levelname)-8s %(threadName)-10s %(message)s')) + logger.addHandler(loghandler) + + # Initialize hub setup + try: + setup = ehs.EmonHubFileSetup(args.config_file) + except ehs.EmonHubSetupInitError as e: + logger.critical(e) + sys.exit("Unable to load configuration file: " + args.config_file) + + # If in "Show settings" mode, print settings and exit + if args.show_settings: + setup.check_settings() + pprint.pprint(setup.settings) + + # Otherwise, create, run, and close EmonHub instance + else: + try: + hub = EmonHub(setup) + except Exception as e: + sys.exit("Could not start EmonHub: " + str(e)) + else: + hub.run() + # When done, close hub + hub.close() diff --git a/emonhub/src/emonhub_coder.py b/emonhub/src/emonhub_coder.py new file mode 100755 index 0000000..6e4df14 --- /dev/null +++ b/emonhub/src/emonhub_coder.py @@ -0,0 +1,51 @@ +import struct + +# Initialize nodes data +nodelist = {} + + +def check_datacode(datacode): + + # Data types & sizes (number of bytes) + datacodes = {'b': '1', 'h': '2', 'i': '4', 'l': '4', 'q': '8', 'f': '4', 'd': '8', + 'B': '1', 'H': '2', 'I': '4', 'L': '4', 'Q': '8', 'c': '1', '?': '1'} + + # if datacode is valid return the data size in bytes + if datacode in datacodes: + return int(datacodes[datacode]) + # if not valid return False + else: + return False + + +def decode(datacode, frame): + # Ensure little-endian & standard sizes used + e = '<' + + # set the base data type to bytes + b = 'B' + + # get data size from data code + s = int(check_datacode(datacode)) + + result = struct.unpack(e + datacode[0], struct.pack(e + b*s, *frame)) + if datacode in ['l', 'L']: + if result[0] == 2147483647: + return 0 + + return result[0] + +def encode(datacode, value): + # Ensure little-endian & standard sizes used + e = '<' + + # set the base data type to bytes + b = 'B' + + # get data size from data code + s = int(check_datacode(datacode)) + + #value = 60 + #datacode = "b" + result = struct.unpack(e + b*s, struct.pack(e + datacode, value)) + return result diff --git a/emonhub/src/emonhub_setup.py b/emonhub/src/emonhub_setup.py new file mode 100755 index 0000000..0ca5f2b --- /dev/null +++ b/emonhub/src/emonhub_setup.py @@ -0,0 +1,174 @@ +""" + + This code is released under the GNU Affero General Public License. + + OpenEnergyMonitor project: + http://openenergymonitor.org + +""" + +import time +import logging +from configobj import ConfigObj +import json + +"""class EmonHubSetup + +User interface to setup the hub. + +The settings attribute stores the settings of the hub. It is a +dictionary with the following keys: + + 'hub': a dictionary containing the hub settings + 'interfacers': a dictionary containing the interfacers + + The hub settings are: + 'loglevel': the logging level + + interfacers are dictionaries with the following keys: + 'Type': class name + 'init_settings': dictionary with initialization settings + 'runtimesettings': dictionary with runtime settings + Initialization and runtime settings depend on the interfacer type. + +The run() method is supposed to be run regularly by the instantiater, to +perform regular communication tasks. + +The check_settings() method is run regularly as well. It checks the settings +and returns True is settings were changed. + +This almost empty class is meant to be inherited by subclasses specific to +each setup. + +""" + +class EmonHubSetup(object): + + def __init__(self): + + # Initialize logger + self._log = logging.getLogger("EmonHub") + + # Initialize settings + self.settings = None + + def run(self): + """Run in background. + + To be implemented in child class. + + """ + pass + + def check_settings(self): + """Check settings + + Update attribute settings and return True if modified. + + To be implemented in child class. + + """ + + +class EmonHubFileSetup(EmonHubSetup): + + def __init__(self, filename): + + # Initialization + super(EmonHubFileSetup, self).__init__() + + self._fileformat = "ConfigObj" # or "ConfigObj" + + self._filename = filename + + # Initialize update timestamp + self._settings_update_timestamp = 0 + self._retry_time_interval = 5 + + # create a timeout message if time out is set (>0) + if self._retry_time_interval > 0: + self.retry_msg = " Retry in " + str(self._retry_time_interval) + " seconds" + else: + self.retry_msg = "" + + # Initialize attribute settings as a ConfigObj instance + try: + + if self._fileformat == "ConfigObj": + self.settings = ConfigObj(filename, file_error=True) + else: + with open(filename) as f: + self.settings = json.loads(f.read()) + + # Check the settings file sections + self.settings['hub'] + self.settings['interfacers'] + except IOError as e: + raise EmonHubSetupInitError(e) + except SyntaxError as e: + raise EmonHubSetupInitError( + 'Error parsing config file \"%s\": ' % filename + str(e)) + except KeyError as e: + raise EmonHubSetupInitError( + 'Configuration file error - section: ' + str(e)) + + def check_settings(self): + """Check settings + + Update attribute settings and return True if modified. + + """ + + # Check settings only once per second + now = time.time() + if now - self._settings_update_timestamp < 0: + return + # Update timestamp + self._settings_update_timestamp = now + + # Backup settings + settings = dict(self.settings) + + # Get settings from file + try: + if self._fileformat == "ConfigObj": + self.settings.reload() + else: + with open(self._filename) as f: + self.settings = json.loads(f.read()) + + except IOError as e: + self._log.warning('Could not get settings: ' + str(e) + self.retry_msg) + self._settings_update_timestamp = now + self._retry_time_interval + return + except SyntaxError as e: + self._log.warning('Could not get settings: ' + + 'Error parsing config file: ' + str(e) + self.retry_msg) + self._settings_update_timestamp = now + self._retry_time_interval + return + except Exception: + import traceback + self._log.warning("Couldn't get settings, Exception: " + + traceback.format_exc() + self.retry_msg) + self._settings_update_timestamp = now + self._retry_time_interval + return + + if self.settings != settings: + # Check the settings file sections + try: + self.settings['hub'] + self.settings['interfacers'] + except KeyError as e: + self._log.warning("Configuration file missing section: " + str(e)) + else: + return True + +"""class EmonHubSetupInitError + +Raise this when init fails. + +""" + + +class EmonHubSetupInitError(Exception): + pass diff --git a/emonhub/src/interfacers/Cargo.py b/emonhub/src/interfacers/Cargo.py new file mode 100755 index 0000000..774647e --- /dev/null +++ b/emonhub/src/interfacers/Cargo.py @@ -0,0 +1,43 @@ +import time + +class EmonHubCargo(object): + uri = 0 + timestamp = 0.0 + target = 0 + nodeid = 0 + nodename = False + names = [] + realdata = [] + rssi = 0 + + # The class "constructor" - It's actually an initializer + def __init__(self, timestamp, target, nodeid, nodename, names, realdata, rssi, rawdata): + EmonHubCargo.uri += 1 + self.uri = EmonHubCargo.uri + self.timestamp = float(timestamp) + self.target = int(target) + self.nodeid = int(nodeid) + self.nodename = nodename + self.names = names + + self.realdata = realdata + self.rssi = int(rssi) + + # self.datacodes = [] + # self.datacode = "" + # self.scale = 0 + # self.scales = [] + self.rawdata = rawdata + self.encoded = {} + # self.realdatacodes = [] + +def new_cargo(rawdata="", nodename=False, names=[], realdata=[], nodeid=0, timestamp=0.0, target=0, rssi=0.0): + """ + + :rtype : object + """ + + if not timestamp: + timestamp = time.time() + cargo = EmonHubCargo(timestamp, target, nodeid, nodename, names, realdata, rssi, rawdata) + return cargo diff --git a/emonhub/src/interfacers/EmonHubEmoncmsHTTPInterfacer.py b/emonhub/src/interfacers/EmonHubEmoncmsHTTPInterfacer.py new file mode 100755 index 0000000..6654918 --- /dev/null +++ b/emonhub/src/interfacers/EmonHubEmoncmsHTTPInterfacer.py @@ -0,0 +1,163 @@ +"""class EmonHubEmoncmsHTTPInterfacer +""" +import time +import json +import urllib2 +import httplib +from pydispatch import dispatcher +from emonhub_interfacer import EmonHubInterfacer + +class EmonHubEmoncmsHTTPInterfacer(EmonHubInterfacer): + + def __init__(self, name): + # Initialization + super(EmonHubEmoncmsHTTPInterfacer, self).__init__(name) + + self._name = name + + self._settings = { + 'subchannels':['ch1'], + 'pubchannels':['ch2'], + + 'apikey': "", + 'url': "http://emoncms.org", + 'senddata': 1, + 'sendstatus': 0, + 'sendinterval': 30 + } + + self.buffer = [] + self.lastsent = time.time() + self.lastsentstatus = time.time() + + def receiver(self, cargo): + + # Create a frame of data in "emonCMS format" + f = [] + f.append(int(cargo.timestamp)) + f.append(cargo.nodeid) + for i in cargo.realdata: + f.append(i) + if cargo.rssi: + f.append(cargo.rssi) + + self._log.debug(str(cargo.uri) + " adding frame to buffer => "+ str(f)) + + # Append to bulk post buffer + self.buffer.append(f) + + def action(self): + + now = time.time() + + if (now-self.lastsent) > (int(self._settings['sendinterval'])): + self.lastsent = now + # print json.dumps(self.buffer) + if int(self._settings['senddata']): + self.bulkpost(self.buffer) + self.buffer = [] + + if (now-self.lastsentstatus)> (int(self._settings['sendinterval'])): + self.lastsentstatus = now + if int(self._settings['sendstatus']): + self.sendstatus() + + def bulkpost(self,databuffer): + + if not 'apikey' in self._settings.keys() or str.__len__(str(self._settings['apikey'])) != 32 \ + or str.lower(str(self._settings['apikey'])) == 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx': + return + + data_string = json.dumps(databuffer, separators=(',', ':')) + + # Prepare URL string of the form + # http://domain.tld/emoncms/input/bulk.json?apikey=12345 + # &data=[[0,10,82,23],[5,10,82,23],[10,10,82,23]] + # &sentat=15' (requires emoncms >= 8.0) + + # time that the request was sent at + sentat = int(time.time()) + + # Construct post_url (without apikey) + post_url = self._settings['url']+'/input/bulk'+'.json?apikey=' + post_body = "data="+data_string+"&sentat="+str(sentat) + + # logged before apikey added for security + self._log.info("sending: " + post_url + "E-M-O-N-C-M-S-A-P-I-K-E-Y&" + post_body) + + # Add apikey to post_url + post_url = post_url + self._settings['apikey'] + + # The Develop branch of emoncms allows for the sending of the apikey in the post + # body, this should be moved from the url to the body as soon as this is widely + # adopted + + reply = self._send_post(post_url, post_body) + if reply == 'ok': + self._log.debug("acknowledged receipt with '" + reply + "' from " + self._settings['url']) + return True + else: + self._log.warning("send failure: wanted 'ok' but got '" +reply+ "'") + + def _send_post(self, post_url, post_body=None): + """ + + :param post_url: + :param post_body: + :return: the received reply if request is successful + """ + """Send data to server. + + data (list): node and values (eg: '[node,val1,val2,...]') + time (int): timestamp, time when sample was recorded + + return True if data sent correctly + + """ + + reply = "" + request = urllib2.Request(post_url, post_body) + try: + response = urllib2.urlopen(request, timeout=60) + except urllib2.HTTPError as e: + self._log.warning(self.name + " couldn't send to server, HTTPError: " + + str(e.code)) + except urllib2.URLError as e: + self._log.warning(self.name + " couldn't send to server, URLError: " + + str(e.reason)) + except httplib.HTTPException: + self._log.warning(self.name + " couldn't send to server, HTTPException") + except Exception: + import traceback + self._log.warning(self.name + " couldn't send to server, Exception: " + + traceback.format_exc()) + else: + reply = response.read() + finally: + return reply + + def sendstatus(self): + if not 'apikey' in self._settings.keys() or str.__len__(str(self._settings['apikey'])) != 32 \ + or str.lower(str(self._settings['apikey'])) == 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx': + return + + # MYIP url + post_url = self._settings['url']+'/myip/set.json?apikey=' + # Print info log + self._log.info("sending: " + post_url + "E-M-O-N-C-M-S-A-P-I-K-E-Y") + # add apikey + post_url = post_url + self._settings['apikey'] + # send request + reply = self._send_post(post_url,None) + + def set(self, **kwargs): + for key,setting in self._settings.iteritems(): + if key in kwargs.keys(): + # replace default + self._settings[key] = kwargs[key] + + # Subscribe to internal channels + for channel in self._settings["subchannels"]: + dispatcher.connect(self.receiver, channel) + self._log.debug(self._name+" Subscribed to channel' : " + str(channel)) + diff --git a/emonhub/src/interfacers/EmonHubJeeInterfacer.py b/emonhub/src/interfacers/EmonHubJeeInterfacer.py new file mode 100755 index 0000000..487b993 --- /dev/null +++ b/emonhub/src/interfacers/EmonHubJeeInterfacer.py @@ -0,0 +1,255 @@ + +import time +from pydispatch import dispatcher + +import datetime +import Cargo +import EmonHubSerialInterfacer as ehi + +"""class EmonHubJeeInterfacer + +Monitors the serial port for data from "Jee" type device + +""" + +class EmonHubJeeInterfacer(ehi.EmonHubSerialInterfacer): + + def __init__(self, name, com_port='/dev/ttyAMA0', com_baud=0): + """Initialize Interfacer + + com_port (string): path to COM port + + """ + + # Initialization + if com_baud != 0: + super(EmonHubJeeInterfacer, self).__init__(name, com_port, com_baud) + else: + super(EmonHubJeeInterfacer, self).__init__(name, com_port, 38400) + + # Display device firmware version and current settings + self.info = ["",""] + if self._ser is not None: + self._ser.write("v") + time.sleep(2) + self._rx_buf = self._rx_buf + self._ser.readline() + if '\r\n' in self._rx_buf: + self._rx_buf="" + info = self._rx_buf + self._ser.readline()[:-2] + if info != "": + # Split the returned "info" string into firmware version & current settings + self.info[0] = info.strip().split(' ')[0] + self.info[1] = info.replace(str(self.info[0]), "") + self._log.info( self.name + " device firmware version: " + self.info[0]) + self._log.info( self.name + " device current settings: " + str(self.info[1])) + else: + # since "v" command only v11> recommend firmware update ? + #self._log.info( self.name + " device firmware is pre-version RFM12demo.11") + self._log.info( self.name + " device firmware version & configuration: not available") + else: + self._log.warning("Device communication error - check settings") + self._rx_buf="" + self._ser.flushInput() + + # Initialize settings + self._defaults.update({'pause': 'off', 'interval': 0, 'datacode': 'h'}) + + # This line will stop the default values printing to logfile at start-up + # unless they have been overwritten by emonhub.conf entries + # comment out if diagnosing a startup value issue + self._settings.update(self._defaults) + + # Jee specific settings to be picked up as changes not defaults to initialise "Jee" device + self._jee_settings = ({'baseid': '15', 'frequency': '433', 'group': '210', 'quiet': 'True', 'calibration': '230V'}) + self._jee_prefix = ({'baseid': 'i', 'frequency': '', 'group': 'g', 'quiet': 'q', 'calibration': 'p'}) + + # Pre-load Jee settings only if info string available for checks + if all(i in self.info[1] for i in (" i", " g", " @ ", " MHz")): + self._settings.update(self._jee_settings) + + def read(self): + """Read data from serial port and process if complete line received. + + Return data as a list: [NodeID, val1, val2] + + """ + + # Read serial RX + self._rx_buf = self._rx_buf + self._ser.readline() + + # If line incomplete, exit + if '\r\n' not in self._rx_buf: + return + + # Remove CR,LF. + f = self._rx_buf[:-2].strip() + + # Reset buffer + self._rx_buf = '' + + if not f: + return + + if f[0] == '\x01': + #self._log.debug("Ignoring frame consisting of SOH character" + str(f)) + return + + if f[0] == '?': + self._log.debug("Discarding RX frame 'unreliable content'" + str(f)) + return False + + # Discard information messages + if '>' in f: + if '->' in f: + self._log.debug("confirmed sent packet size: " + str(f)) + return + self._log.debug("acknowledged command: " + str(f)) + return + + # Record current device settings + if " i" and " g" and " @ " and " MHz" in f: + self.info[1] = f + self._log.debug("device settings updated: " + str(self.info[1])) + return + + # Save raw packet to new cargo object + c = Cargo.new_cargo(rawdata=f) + + # Convert single string to list of string values + f = f.split(' ') + + # Strip leading 'OK' from frame if needed + if f[0]=='OK': + f = f[1:] + + # Extract RSSI value if it's available + if str(f[-1])[0]=='(' and str(f[-1])[-1]==')': + c.rssi = int(f[-1][1:-1]) + f = f[:-1] + + try: + # Extract node id from frame + c.nodeid = int(f[0]) + int(self._settings['nodeoffset']) + except ValueError: + return + + try: + # Store data as a list of integer values + c.realdata = [int(i) for i in f[1:]] + except ValueError: + return + + return c + + # # unix timestamp + # t = round(time.time(), 2) + # + # # Process data frame + # self._r xq.put(self._process_rx(f, t)) + + def set(self, **kwargs): + """Send configuration parameters to the "Jee" type device through COM port + + **kwargs (dict): settings to be modified. Available settings are + 'baseid', 'frequency', 'group'. Example: + {'baseid': '15', 'frequency': '4', 'group': '210'} + + """ + + for key, setting in self._jee_settings.iteritems(): + # Decide which setting value to use + if key in kwargs.keys(): + setting = kwargs[key] + else: + setting = self._jee_settings[key] + # convert bools to ints + if str.capitalize(str(setting)) in ['True', 'False']: + setting = int(setting == "True") + # confirmation string always contains baseid, group anf freq + if " i" and " g" and " @ " and " MHz" in self.info[1]: + # If setting confirmed as already set, continue without changing + if (self._jee_prefix[key] + str(setting)) in self.info[1].split(): + continue + elif key in self._settings and self._settings[key] == setting: + continue + if key == 'baseid' and int(setting) >=1 and int(setting) <=26: + command = str(setting) + 'i' + elif key == 'frequency' and setting in ['433','868','915']: + command = setting[:1] + 'b' + elif key == 'group'and int(setting) >=0 and int(setting) <=250: + command = str(setting) + 'g' + elif key == 'quiet' and int(setting) >=0 and int(setting) <2: + command = str(setting) + 'q' + elif key == 'calibration' and setting == '230V': + command = '1p' + elif key == 'calibration' and setting == '110V': + command = '2p' + + else: + self._log.warning("In interfacer set '%s' is not a valid setting for %s: %s" % (str(setting), self.name, key)) + continue + self._settings[key] = setting + self._log.info("Setting " + self.name + " %s: %s" % (key, setting) + " (" + command + ")") + self._ser.write(command) + # Wait a sec between two settings + time.sleep(1) + + # include kwargs from parent + super(EmonHubJeeInterfacer, self).set(**kwargs) + + def action(self): + """Actions that need to be done on a regular basis. + + This should be called in main loop by instantiater. + + """ + + t = time.time() + + # Broadcast time to synchronize emonGLCD + interval = int(self._settings['interval']) + if interval: # A value of 0 means don't do anything + if (t - self._interval_timestamp) > interval: + self._interval_timestamp = t + now = datetime.datetime.now() + self._log.debug(self.name + " broadcasting time: %02d:%02d" % (now.hour, now.minute)) + self._ser.write("00,%02d,%02d,00,s" % (now.hour, now.minute)) + + def send (self, cargo): + """ + """ + #self._process_tx(self._txq.get()) + #self._rxq.put( self._process_rx(f, t)) + #dest = f[1] + #packet = f[2:-1] + #self.send_packet(packet, dest) + # TODO amalgamate into 1 send + + #def send_packet(self, packet, id=0, cmd="s"): + """ + + """ + f = cargo + cmd = "s" + + # # If the use of acks gets implemented + # ack = False + # if ack: + # cmd = "a" + if self.getName() in f.encoded: + data = f.encoded[self.getName()] + else: + data = f.realdata + + payload = "" + for value in data: + if int(value) < 0 or int(value) > 255: + self._log.warning(self.name + " discarding Tx packet: values out of scope" ) + return + payload += str(int(value))+"," + + payload += cmd + + self._log.debug(str(f.uri) + " sent TX packet: " + payload) + self._ser.write(payload) + diff --git a/emonhub/src/interfacers/EmonHubMqttInterfacer.py b/emonhub/src/interfacers/EmonHubMqttInterfacer.py new file mode 100755 index 0000000..d25958c --- /dev/null +++ b/emonhub/src/interfacers/EmonHubMqttInterfacer.py @@ -0,0 +1,173 @@ +"""class EmonHubMqttGenInterfacer + +""" +import time +import paho.mqtt.client as mqtt +from pydispatch import dispatcher +from emonhub_interfacer import EmonHubInterfacer +import Cargo + +class EmonHubMqttInterfacer(EmonHubInterfacer): + + def __init__(self, name, mqtt_user=" ", mqtt_passwd=" ", mqtt_host="127.0.0.1", mqtt_port=1883): + # Initialization + super(EmonHubMqttInterfacer, self).__init__(name) + + self._log.info(str(name)+" Init mqtt_host="+str(mqtt_host)+" mqtt_port="+str(mqtt_port)+ " mqtt_user="+str(mqtt_user)) + self._name = name + self._host = mqtt_host + self._port = mqtt_port + self._user = mqtt_user + self._passwd = mqtt_passwd + self._connected = False + + self._settings = { + 'subchannels':['ch1'], + 'pubchannels':['ch2'], + + # emonhub/rx/10/values format - default emoncms nodes module + 'node_format_enable': 1, + 'node_format_basetopic': 'emonhub/', + + # nodes/emontx/power1 format + 'nodevar_format_enable': 0, + 'nodevar_format_basetopic': "nodes/" + }; + + self._mqttc = mqtt.Client() + self._mqttc.on_connect = self.on_connect + self._mqttc.on_disconnect = self.on_disconnect + self._mqttc.on_message = self.on_message + self._mqttc.on_subscribe = self.on_subscribe + + + def action(self): + if not self._connected: + self._log.info("Connecting to MQTT Server") + try: + self._mqttc.username_pw_set(self._user, self._passwd) + self._mqttc.connect(self._host, self._port, 60) + except: + self._log.info("Could not connect...") + time.sleep(1.0) + self._mqttc.loop(0) + + def on_connect(self, client, userdata, flags, rc): + + connack_string = {0:'Connection successful', + 1:'Connection refused - incorrect protocol version', + 2:'Connection refused - invalid client identifier', + 3:'Connection refused - server unavailable', + 4:'Connection refused - bad username or password', + 5:'Connection refused - not authorised'} + + if rc: + self._log.warning(connack_string[rc]) + else: + self._log.info("connection status: "+connack_string[rc]) + self._connected = True + # Subscribe to MQTT topics + self._mqttc.subscribe(str(self._settings["node_format_basetopic"])+"tx/#") + + self._log.debug("CONACK => Return code: "+str(rc)) + + def on_disconnect(self, client, userdata, rc): + if rc != 0: + self._log.info("Unexpected disconnection") + self._connected = False + + def on_subscribe(self, mqttc, obj, mid, granted_qos): + self._log.info("on_subscribe") + + def on_message(self, client, userdata, msg): + topic_parts = msg.topic.split("/") + + if topic_parts[0] == self._settings["node_format_basetopic"][:-1]: + if topic_parts[1] == "tx": + if topic_parts[3] == "values": + nodeid = int(topic_parts[2]) + + payload = msg.payload + realdata = payload.split(",") + self._log.debug("Nodeid: "+str(nodeid)+" values: "+msg.payload) + + rxc = Cargo.new_cargo(realdata=realdata) + rxc.nodeid = nodeid + + if rxc: + # rxc = self._process_tx(rxc) + if rxc: + for channel in self._settings["pubchannels"]: + dispatcher.send(channel, cargo=rxc) + self._log.debug(str(rxc.uri) + " Sent to channel' : " + str(channel)) + + def receiver(self, cargo): + if self._connected: + # ---------------------------------------------------------- + # General MQTT format: emonhub/rx/emonpi/power1 ... 100 + # ---------------------------------------------------------- + if int(self._settings["nodevar_format_enable"])==1: + + # Node id or nodename if given + nodestr = str(cargo.nodeid) + if cargo.nodename!=False: nodestr = str(cargo.nodename) + + varid = 1 + for value in cargo.realdata: + # Variable id or variable name if given + varstr = str(varid) + if (varid-1) self._control_interval: + return + + req = self._settings['url'] + \ + "/emoncms/packetgen/getpacket.json?apikey=" + + try: + packet = urllib2.urlopen(req + self._settings['apikey']).read() + except: + return + + # logged without apikey added for security + self._log.info("requesting packet: " + req + "E-M-O-N-C-M-S-A-P-I-K-E-Y") + + try: + packet = json.loads(packet) + except ValueError: + self._log.warning("no packet returned") + return + + raw = "" + target = 0 + values = [] + datacodes = [] + + for v in packet: + raw += str(v['value']) + " " + values.append(int(v['value'])) + # PacketGen datatypes are 0, 1 or 2 for bytes, ints & bools + # bools are currently read as bytes 0 & 1 + datacodes.append(['B', 'h', 'B'][v['type']]) + + c = new_cargo(rawdata=raw) + + # Extract the Target id if one is expected + if self._settings['targeted']: + #setting = str.capitalize(str(setting)) + c.target = int(values[0]) + values = values[1:] + datacodes = datacodes[1:] + + c.realdata = values + c.realdatacodes = datacodes + + self._control_timestamp = t + c.timestamp = t + + # Return a Payload object + #x = new_cargo(realdata=data) + #x.realdatacodes = datacodes + return c + + + def action(self): + """Actions that need to be done on a regular basis. + + This should be called in main loop by instantiater. + + """ + + t = time.time() + + # Keep in touch with PacketGen and update refresh time + interval = int(self._settings['interval']) + if interval: # A value of 0 means don't do anything + if not (t - self._interval_timestamp) > interval: + return + + try: + z = urllib2.urlopen(self._settings['url'] + + "/emoncms/packetgen/getinterval.json?apikey=" + + self._settings['apikey']).read() + i = int(z[1:-1]) + except: + self._log.info("request interval not returned") + return + + if self._control_interval != i: + self._control_interval = i + self._log.info("request interval set to: " + str(i) + " seconds") + + self._interval_timestamp = t + + return + + def set(self, **kwargs): + """ + + """ + + for key, setting in self._pg_settings.iteritems(): + # Decide which setting value to use + if key in kwargs.keys(): + setting = kwargs[key] + else: + setting = self._pg_settings[key] + if key in self._settings and self._settings[key] == setting: + continue + elif key == 'apikey': + if str.lower(setting[:4]) == 'xxxx': + self._log.warning("Setting " + self.name + " apikey: obscured") + pass + elif str.__len__(setting) == 32 : + self._log.info("Setting " + self.name + " apikey: set") + pass + elif setting == "": + self._log.info("Setting " + self.name + " apikey: null") + pass + else: + self._log.warning("Setting " + self.name + " apikey: invalid format") + continue + self._settings[key] = setting + # Next line will log apikey if uncommented (privacy ?) + #self._log.debug(self.name + " apikey: " + str(setting)) + continue + elif key == 'url' and setting[:4] == "http": + self._log.info("Setting " + self.name + " url: " + setting) + self._settings[key] = setting + continue + else: + self._log.warning("'%s' is not valid for %s: %s" % (str(setting), self.name, key)) + + # include kwargs from parent + super(EmonHubPacketGenInterfacer, self).set(**kwargs) + diff --git a/emonhub/src/interfacers/EmonHubSCNordicHTTPInterfacer.py b/emonhub/src/interfacers/EmonHubSCNordicHTTPInterfacer.py new file mode 100755 index 0000000..6b9527c --- /dev/null +++ b/emonhub/src/interfacers/EmonHubSCNordicHTTPInterfacer.py @@ -0,0 +1,137 @@ +"""class EmonHubEmoncmsHTTPInterfacer +""" +import time + +from configobj import ConfigObj +from pydispatch import dispatcher +from emonhub_interfacer import EmonHubInterfacer +import emonhub_coder as ehc +from interfacers.portal_package import PortalPackage +from scnordic_bridge import RequestHandler + + +class EmonHubSCNordicHTTPInterfacer(EmonHubInterfacer): + + def __init__(self, name): + # Initialization + super(EmonHubSCNordicHTTPInterfacer, self).__init__(name) + + self._name = name + + self._settings = { + 'subchannels':['ch1'], + 'pubchannels':['ch2'], + + 'apikey': "", + 'url': "http://emoncms.org", + 'sendinterval': 20, + 'prev_values_path': "/home/pi/data/prev_values.conf" + } + + self.buffer = [] + self.lastsent = time.time() + self.queue = [] + + self.prev_values = {} + self.correction_values = {} + + def receiver(self, cargo): + ''' + Append cargo to sendbuffer if it's not in it allready + ''' + + if not [c for c in self.buffer if c.nodeid == cargo.nodeid]: + self._log.debug(str(cargo.uri) + " adding cargo to buffer") + self.buffer.append(cargo) + + def cargo_to_portal_packages(self, cargo): + packages = [] + + for index, value in enumerate(cargo.realdata): + senddata = ehc.nodelist[str(cargo.nodeid)]['rx']['senddata'][index] + if senddata == '1': + unit = ehc.nodelist[str(cargo.nodeid)]['rx']['units'][index] + name = "%s-%s" % (cargo.nodename, cargo.names[index]) + name = name.upper() + value = float(value) + if unit in ['Wh', 'p', 'sec']: + value = self.value_check(name, value) + + packages.append(PortalPackage(name, cargo.timestamp, value, unit)) + + if unit in ['Wh', 'p', 'sec']: + self.prev_values[name] = value + + self.prev_values.write() + + return packages + + def action(self): + now = time.time() + + if (now-self.lastsent) > (int(self._settings['sendinterval'])): + self.lastsent = now + # print json.dumps(self.buffer) + + self.bulkpost(self.buffer) + self.buffer = [] + + def bulkpost(self, databuffer): + + if not 'apikey' in self._settings.keys() or str.__len__(str(self._settings['apikey'])) != 104 \ + or str.lower(str(self._settings['apikey'])) == 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx': + return + + request = RequestHandler(self._settings['apikey'], self._settings['url']) + failed_packages = [] + + for data in databuffer: + packages = self.cargo_to_portal_packages(data) + + for package in packages: + self.queue.append(package) + + failure = False + for package in self.queue: + + sent = 500 + if not failure: + sent = request.send_measurement(package) + + if sent in (500, 502): + failure = True + self._log.warning("send failure: wanted '200' but got '" + str(sent) + "'") + failed_packages.append(package) + + self.queue = failed_packages + + return True + + def set(self, **kwargs): + for key,setting in self._settings.iteritems(): + if key in kwargs.keys(): + # replace default + self._settings[key] = kwargs[key] + + # Subscribe to internal channels + for channel in self._settings["subchannels"]: + dispatcher.connect(self.receiver, channel) + self._log.debug(self._name+" Subscribed to channel' : " + str(channel)) + + self.prev_values = ConfigObj(self._settings['prev_values_path']) + + def value_correction(self, name, value): + return value + float(self.correction_values[name]) + + def value_check(self, name, value): + + if name in self.correction_values: + self._log.debug("Correcting value for: " + name) + value = self.value_correction(name, value) + + if name in self.prev_values and value < self.prev_values[name]: + self._log.debug("New value lower than the last. Setting up correction for: " + name) + self.correction_values[name] = float(self.prev_values[name]) + value = self.value_correction(name, value) + + return value diff --git a/emonhub/src/interfacers/EmonHubSerialInterfacer.py b/emonhub/src/interfacers/EmonHubSerialInterfacer.py new file mode 100755 index 0000000..0e44de8 --- /dev/null +++ b/emonhub/src/interfacers/EmonHubSerialInterfacer.py @@ -0,0 +1,94 @@ +import serial +import time +import Cargo +from pydispatch import dispatcher +import emonhub_interfacer as ehi + +"""class EmonhubSerialInterfacer + +Monitors the serial port for data + +""" + + +class EmonHubSerialInterfacer(ehi.EmonHubInterfacer): + + def __init__(self, name, com_port='', com_baud=9600): + """Initialize interfacer + + com_port (string): path to COM port + + """ + + # Initialization + super(EmonHubSerialInterfacer, self).__init__(name) + + # Open serial port + self._ser = self._open_serial_port(com_port, com_baud) + + # Initialize RX buffer + self._rx_buf = '' + + def close(self): + """Close serial port""" + + # Close serial port + if self._ser is not None: + self._log.debug("Closing serial port") + self._ser.close() + + def _open_serial_port(self, com_port, com_baud): + """Open serial port + + com_port (string): path to COM port + + """ + + #if not int(com_baud) in [75, 110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]: + # self._log.debug("Invalid 'com_baud': " + str(com_baud) + " | Default of 9600 used") + # com_baud = 9600 + + try: + s = serial.Serial(com_port, com_baud, timeout=0) + self._log.debug("Opening serial port: " + str(com_port) + " @ "+ str(com_baud) + " bits/s") + except serial.SerialException as e: + self._log.error(e) + raise EmonHubInterfacerInitError('Could not open COM port %s' % + com_port) + else: + return s + + def read(self): + """Read data from serial port and process if complete line received. + + Return data as a list: [NodeID, val1, val2] + + """ + + # Read serial RX + self._rx_buf = self._rx_buf + self._ser.readline() + + # If line incomplete, exit + if '\r\n' not in self._rx_buf: + return + + # Remove CR,LF + f = self._rx_buf[:-2] + + # Reset buffer + self._rx_buf = '' + + # Create a Payload object + c = Cargo.new_cargo(rawdata=f) + + f = f.split() + + if int(self._settings['nodeoffset']): + c.nodeid = int(self._settings['nodeoffset']) + c.realdata = f + else: + c.nodeid = int(f[0]) + c.realdata = f[1:] + + return c + diff --git a/emonhub/src/interfacers/EmonHubSmilicsInterfacer.py b/emonhub/src/interfacers/EmonHubSmilicsInterfacer.py new file mode 100644 index 0000000..9a4a2e0 --- /dev/null +++ b/emonhub/src/interfacers/EmonHubSmilicsInterfacer.py @@ -0,0 +1,193 @@ +''' + Interface conf: + [[SMILICS_INTERFACE]] + Type = EmonHubSmilicsInterfacer + [[[init_settings]]] + port = 8080 + [[[runtimesettings]]] + pubchannels = ToCloud + subchannels = ToNothing + + Node conf: + Using the Wibeee mac-address as node id + + [[121111111111]] + nodename = SMILICS01 + firmware =V120 + hardware = Smilics Wibeee + [[[rx]]] + names = power1, power2, power3, power_total, wh1, wh2, wh3, wh_total + datacodes = h, h, h, h, h, h, h, h + scales = 1, 1, 1, 1, 1, 1, 1, 1 + units = W, W, W, W, Wh, Wh, Wh, Wh +''' + +import threading +import datetime +import time +import traceback + +from BaseHTTPServer import BaseHTTPRequestHandler +from Queue import Queue +from SocketServer import TCPServer, ThreadingMixIn +from urlparse import parse_qs +from pydispatch import dispatcher + +import Cargo +import emonhub_coder as ehc +from emonhub_interfacer import EmonHubInterfacer + + +class ThreadedTCPServer(ThreadingMixIn, TCPServer): + def serve_forever(self, queue): + self.RequestHandlerClass.queue = queue + TCPServer.serve_forever(self) + + +class ServerHandler(BaseHTTPRequestHandler): + def do_GET(self): + data = parse_qs(self.path[17:]) + data['timestamp'] = datetime.datetime.now() + print data + #self.queue.put(data) + + +class EmonHubSmilicsInterfacer(EmonHubInterfacer): + """ Interface for the Smilics Wibee + + Listen for get request on the specified port + """ + + def __init__(self, name, port): + """ + Args: + name (str): Configuration name. + port (int): The port the webserver should listen on. + """ + super(EmonHubSmilicsInterfacer, self).__init__(name) + + self._settings = { + 'subchannels': ['ch1'], + 'pubchannels': ['ch2'], + } + self._queue = Queue() + self._server = ThreadedTCPServer(("0.0.0.0", int(port)), ServerHandler) + self.last_reading = None + self.wh_counter1 = 0 + self.wh_counter2 = 0 + self.wh_counter3 = 0 + self.wh_counter4 = 0 + self.acc_power1 = 0 + self.acc_power2 = 0 + self.acc_power3 = 0 + self.acc_power4 = 0 + + def close(self): + """Cleanup when the interface closes""" + if self._server is not None: + self._log.debug('Closing server') + self._server.shutdown() + self._server.server_close() + + def run(self): + """Starts the server on a new thread and processes the queue""" + server_thread = threading.Thread( + target=self._server.serve_forever, args=(self._queue,)) + server_thread.daemon = True + server_thread.start() + + while not self.stop: + while not self._queue.empty(): + rxc = self._process_rx(self._queue.get(False)) + self._queue.task_done() + + if rxc: + for channel in self._settings["pubchannels"]: + dispatcher.send(channel, cargo=rxc) + self._log.debug( + str(rxc.uri) + " Sent to channel' : " + + str(channel)) + time.sleep(0.1) + + self.close() + + def _process_rx(self, smilics_dict): + """ Converts the data recieved on the webserver to an instance of + the Cargo class + + Args: + smilics_dict: Dict with smilics data. + + Returns: + Cargo if successful, None otherwise. + """ + try: + c = Cargo.new_cargo() + if 'mac' not in smilics_dict.keys(): + return None + + c.nodeid = smilics_dict['mac'][0] + if c.nodeid not in ehc.nodelist.keys(): + self._log.debug(str(c.nodeid) + " Not in config") + return None + + timestamp = smilics_dict['timestamp'] + if not self.last_reading: + self.last_reading = timestamp + return None + + time_between = timestamp - self.last_reading + time_between = time_between.total_seconds() + + self.last_reading = timestamp + + self.wh_counter1 += float(smilics_dict['a1'][0]) + self.wh_counter2 += float(smilics_dict['a2'][0]) + self.wh_counter3 += float(smilics_dict['a3'][0]) + self.wh_counter4 += float(smilics_dict['at'][0]) + + i_delta = self.wh_counter1 / (3600 / time_between) + self.acc_power1 += i_delta + self.wh_counter1 -= (i_delta * (3600 / time_between)) + + i_delta = self.wh_counter2 / (3600 / time_between) + self.acc_power2 += i_delta + self.wh_counter2 -= (i_delta * (3600 / time_between)) + + i_delta = self.wh_counter3 / (3600 / time_between) + self.acc_power3 += i_delta + self.wh_counter3 -= (i_delta * (3600 / time_between)) + + i_delta = self.wh_counter4 / (3600 / time_between) + self.acc_power4 += i_delta + self.wh_counter4 -= (i_delta * (3600 / time_between)) + + node_config = ehc.nodelist[str(c.nodeid)] + + c.names = node_config['rx']['names'] + c.nodename = node_config['nodename'] + + c.realdata = [ + smilics_dict['a1'][0], + smilics_dict['a2'][0], + smilics_dict['a3'][0], + smilics_dict['at'][0], + self.acc_power1, + self.acc_power2, + self.acc_power3, + self.acc_power4, + ] + c.timestamp = time.mktime(timestamp.timetuple()) + + return c + except: + traceback.print_exc() + return None + + def set(self, **kwargs): + """ Override default settings with settings entered in the config file + """ + for key, setting in self._settings.iteritems(): + if key in kwargs.keys(): + # replace default + self._settings[key] = kwargs[key] diff --git a/emonhub/src/interfacers/EmonHubSocketInterfacer.py b/emonhub/src/interfacers/EmonHubSocketInterfacer.py new file mode 100755 index 0000000..ba83904 --- /dev/null +++ b/emonhub/src/interfacers/EmonHubSocketInterfacer.py @@ -0,0 +1,173 @@ +import socket +import select +import Cargo + +from pydispatch import dispatcher +from emonhub_interfacer import EmonHubInterfacer + +"""class EmonHubSocketInterfacer + +Monitors a socket for data, typically from ethernet link + +""" + +class EmonHubSocketInterfacer(EmonHubInterfacer): + + def __init__(self, name, port_nb=50011): + """Initialize Interfacer + + port_nb (string): port number on which to open the socket + + """ + + # Initialization + super(EmonHubSocketInterfacer, self).__init__(name) + + # add an apikey setting + self._skt_settings = {'apikey':""} + self._settings.update(self._skt_settings) + + # Open socket + self._socket = self._open_socket(port_nb) + + # Initialize RX buffer for socket + self._sock_rx_buf = '' + + def _open_socket(self, port_nb): + """Open a socket + + port_nb (string): port number on which to open the socket + + """ + + self._log.debug('Opening socket on port %s', port_nb) + + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(('', int(port_nb))) + s.listen(1) + except socket.error as e: + self._log.error(e) + raise EmonHubInterfacerInitError('Could not open port %s' % + port_nb) + else: + return s + + def close(self): + """Close socket.""" + # Close socket + if self._socket is not None: + self._log.debug('Closing socket') + self._socket.close() + + def read(self): + """Read data from socket and process if complete line received. + + Return data as a list: [NodeID, val1, val2] + + """ + + # Check if data received + ready_to_read, ready_to_write, in_error = \ + select.select([self._socket], [], [], 0) + + # If data received, add it to socket RX buffer + if self._socket in ready_to_read: + + # Accept connection + conn, addr = self._socket.accept() + + # Read data + self._sock_rx_buf = self._sock_rx_buf + conn.recv(1024) + + # Close connection + conn.close() + + # If there is at least one complete frame in the buffer + if not '\r\n' in self._sock_rx_buf: + return + + # Process and return first frame in buffer: + f, self._sock_rx_buf = self._sock_rx_buf.split('\r\n', 1) + + # create a new cargo + c = Cargo.new_cargo(rawdata=f) + + # Split string into values + f = f.split(' ') + + # If apikey is specified, 32chars and not all x's + if 'apikey' in self._settings: + if len(self._settings['apikey']) == 32 and self._settings['apikey'].lower != "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx": + # Discard if apikey is not in received frame + if not self._settings['apikey'] in f: + self._log.warning(str(c.uri) +" discarded frame: apikey not matched") + return + # Otherwise remove apikey from frame + f = [ v for v in f if self._settings['apikey'] not in v ] + c.rawdata = ' '.join(f) + else: + pass + + + # Extract timestamp value if one is expected or use 0 + timestamp = 0.0 + if self._settings['timestamped']: + c.timestamp=f[0] + f = f[1:] + # Extract source's node id + c.nodeid = int(f[0]) + int(self._settings['nodeoffset']) + f=f[1:] + # Extract the Target id if one is expected + if self._settings['targeted']: + #setting = str.capitalize(str(setting)) + c.target = int(f[0]) + f = f[1:] + # Extract list of data values + c.realdata = f#[1:] + # Create a Payload object + #f = new_cargo(data, node, timestamp, dest) + + return c + + + def set(self, **kwargs): + """ + + """ + + for key, setting in self._skt_settings.iteritems(): + # Decide which setting value to use + if key in kwargs.keys(): + setting = kwargs[key] + else: + setting = self._skt_settings[key] + if key in self._settings and self._settings[key] == setting: + continue + elif key == 'apikey': + if str.lower(setting[:4]) == 'xxxx': + self._log.warning("Setting " + self.name + " apikey: obscured") + pass + elif str.__len__(setting) == 32 : + self._log.info("Setting " + self.name + " apikey: set") + pass + elif setting == "": + self._log.info("Setting " + self.name + " apikey: null") + pass + else: + self._log.warning("Setting " + self.name + " apikey: invalid format") + continue + self._settings[key] = setting + # Next line will log apikey if uncommented (privacy ?) + #self._log.debug(self.name + " apikey: " + str(setting)) + continue + elif key == 'url' and setting[:4] == "http": + self._log.info("Setting " + self.name + " url: " + setting) + self._settings[key] = setting + continue + else: + self._log.warning("'%s' is not valid for %s: %s" % (str(setting), self.name, key)) + + # include kwargs from parent + super(EmonHubSocketInterfacer, self).set(**kwargs) + diff --git a/emonhub/src/interfacers/EmonHubTesterInterfacer.py b/emonhub/src/interfacers/EmonHubTesterInterfacer.py new file mode 100755 index 0000000..daa14db --- /dev/null +++ b/emonhub/src/interfacers/EmonHubTesterInterfacer.py @@ -0,0 +1,74 @@ +"""class EmonHubTesterGenInterfacer + +""" +import time +import Cargo +from pydispatch import dispatcher +from emonhub_interfacer import EmonHubInterfacer + +class EmonHubTesterInterfacer(EmonHubInterfacer): + + def __init__(self, name, mqtt_host="127.0.0.1", mqtt_port=1883): + # Initialization + super(EmonHubTesterInterfacer, self).__init__(name) + + self._name = name + + self._settings = { + 'subchannels':['ch1'], + 'pubchannels':['ch2'] + }; + + + def run(self): + + last = time.time() + consumption = 0 + time_consumption = 0 + while not self.stop: + # Read the input and process data if available + + now = time.time() + if (now-last)>5.0: + time_consumption += int(now-last) + last = now + + #if time_consumption == 30: + # consumption = 0 + + self._log.debug("5s loop") + rxc = Cargo.new_cargo() + rxc.nodeid = 10 + rxc.nodename = "EMONTEST" + rxc.names = ['power1', 'power2', 'power3', 'power4', 'Vrms', 'pulse', + 'Wh1', 'Wh2', 'Wh3', 'Wh4', 'RunHours1', 'RunHours2', 'RunHours3', 'RunHours4'] + + rxc.realdata = [10,10,10,10,230,0,consumption,consumption,consumption,consumption, + time_consumption,time_consumption,time_consumption,time_consumption] + + consumption += 10 + + + for channel in self._settings["pubchannels"]: + dispatcher.send(channel, cargo=rxc) + self._log.debug(str(rxc.uri) + " Sent to channel' : " + str(channel)) + + # Don't loop to fast + time.sleep(0.1) + # Action reporter tasks + # self.action() + + def receiver(self, cargo): + pass + + + def set(self, **kwargs): + for key,setting in self._settings.iteritems(): + if key in kwargs.keys(): + # replace default + self._settings[key] = kwargs[key] + + # Subscribe to internal channels + for channel in self._settings["subchannels"]: + dispatcher.connect(self.receiver, channel) + self._log.debug(self._name+" Subscribed to channel' : " + str(channel)) diff --git a/emonhub/src/interfacers/EmonHubVEDirectInterfacer.py b/emonhub/src/interfacers/EmonHubVEDirectInterfacer.py new file mode 100755 index 0000000..7d90a6d --- /dev/null +++ b/emonhub/src/interfacers/EmonHubVEDirectInterfacer.py @@ -0,0 +1,205 @@ +import time +import serial +import Cargo +from pydispatch import dispatcher +import emonhub_interfacer as ehi + +"""class EmonhubSerialInterfacer + +Monitors the serial port for data + +""" + + +class EmonHubVEDirectInterfacer(ehi.EmonHubInterfacer): + + (WAIT_HEADER, IN_KEY, IN_VALUE, IN_CHECKSUM) = range(4) + + def __init__(self, name, com_port='', com_baud=9600, toextract='' , poll_interval=30): + """Initialize interfacer + + com_port (string): path to COM port + + """ + + # Initialization + super(EmonHubVEDirectInterfacer, self).__init__(name) + + # Open serial port + self._ser = self._open_serial_port(com_port, com_baud) + + # Initialize RX buffer + self._rx_buf = '' + + #VE Direct requirements + self.header1 = '\r' + self.header2 = '\n' + self.delimiter = '\t' + self.key = '' + self.value = '' + self.bytes_sum = 0; + self.state = self.WAIT_HEADER + self.dict = {} + self.poll_interval = int(poll_interval) + self.last_read = time.time() + + #Parser requirments + self._extract = toextract + #print "init system with to extract %s"%self._extract + + + def input(self, byte): + """ + Parse serial byte code from VE.Direct + """ + if self.state == self.WAIT_HEADER: + self.bytes_sum += ord(byte) + if byte == self.header1: + self.state = self.WAIT_HEADER + elif byte == self.header2: + self.state = self.IN_KEY + + return None + elif self.state == self.IN_KEY: + self.bytes_sum += ord(byte) + if byte == self.delimiter: + if (self.key == 'Checksum'): + self.state = self.IN_CHECKSUM + else: + self.state = self.IN_VALUE + else: + self.key += byte + return None + elif self.state == self.IN_VALUE: + self.bytes_sum += ord(byte) + if byte == self.header1: + self.state = self.WAIT_HEADER + self.dict[self.key] = self.value; + self.key = ''; + self.value = ''; + else: + self.value += byte + return None + elif self.state == self.IN_CHECKSUM: + self.bytes_sum += ord(byte) + self.key = '' + self.value = '' + self.state = self.WAIT_HEADER + if (self.bytes_sum % 256 == 0): + self.bytes_sum = 0 + return self.dict + else: + self.bytes_sum = 0 + + else: + raise AssertionError() + + def close(self): + """Close serial port""" + + # Close serial port + if self._ser is not None: + self._log.debug("Closing serial port") + self._ser.close() + + def _open_serial_port(self, com_port, com_baud): + """Open serial port + + com_port (string): path to COM port + + """ + + #if not int(com_baud) in [75, 110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]: + # self._log.debug("Invalid 'com_baud': " + str(com_baud) + " | Default of 9600 used") + # com_baud = 9600 + + try: + s = serial.Serial(com_port, com_baud, timeout=10) + self._log.debug("Opening serial port: " + str(com_port) + " @ "+ str(com_baud) + " bits/s") + except serial.SerialException as e: + self._log.error(e) + raise EmonHubInterfacerInitError('Could not open COM port %s' % + com_port) + else: + return s + + def parse_package(self,data): + """ + Convert package from vedirect dictionary format to emonhub expected format + + """ + clean_data = "%s"%self._settings['nodeoffset'] + for key in self._extract: + if data.has_key(key): + #Emonhub doesn't like strings so we convert them to ints + tempval = 0 + try: + tempval = float(data[key]) + except Exception,e: + tempval = data[key] + if not isinstance(tempval,float): + if data[key] == "OFF": + data[key] = 0 + else: + data[key] = 1 + + clean_data = clean_data + " " + str(data[key]) + return clean_data + + + def _read_serial(self): + self._log.debug(" Starting Serial read") + try: + while self._rx_buf == '': + byte = self._ser.read(1) + packet = self.input(byte) + if packet != None: + self._rx_buf = packet + + except Exception,e: + self._log.error(e) + self._rx_buf = "" + + + def read(self): + """Read data from serial port and process if complete line received. + + Return data as a list: [NodeID, val1, val2] + + """ + + # Read serial RX + now = time.time() + if not (now - self.last_read) > self.poll_interval: + #self._log.debug(" Waiting for %s seconds "%(str(now - self.last_read))) + # Wait to read based on poll_interval + return + + # Read from serial + self._read_serial() + # Update last read time + self.last_read = now + # If line incomplete, exit + if self._rx_buf == None: + return + + #Sample data looks like {'FW': '0307', 'SOC': '1000', 'Relay': 'OFF', 'PID': '0x203', 'H10': '6', 'BMV': '700', 'TTG': '-1', 'H12': '0', 'H18': '0', 'I': '0', 'H11': '0', 'Alarm': 'OFF', 'CE': '0', 'H17': '9', 'P': '0', 'AR': '0', 'V': '26719', 'H8': '29011', 'H9': '0', 'H2': '0', 'H3': '0', 'H1': '-1633', 'H6': '-5775', 'H7': '17453', 'H4': '0', 'H5': '0'} + + # Create a Payload object + c = Cargo.new_cargo(rawdata = self._rx_buf) + f = self.parse_package(self._rx_buf) + f = f.split() + + # Reset buffer + self._rx_buf = '' + + if f: + if int(self._settings['nodeoffset']): + c.nodeid = int(self._settings['nodeoffset']) + c.realdata = f[1:] + else: + self._log.error("nodeoffset needed in emonhub configuratio, make sure it exits ans is integer ") + pass + + return c + diff --git a/emonhub/src/interfacers/__init__.py b/emonhub/src/interfacers/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/emonhub/src/interfacers/emonhub_interfacer.py b/emonhub/src/interfacers/emonhub_interfacer.py new file mode 100755 index 0000000..2c9a1e1 --- /dev/null +++ b/emonhub/src/interfacers/emonhub_interfacer.py @@ -0,0 +1,501 @@ +""" + + This code is released under the GNU Affero General Public License. + + OpenEnergyMonitor project: + http://openenergymonitor.org + +""" + +import serial +import time +import datetime +import logging +import socket +import select +import threading +import urllib2 +import json +import uuid + +import paho.mqtt.client as mqtt + +import emonhub_coder as ehc + +from pydispatch import dispatcher + +"""class EmonHubInterfacer + +Monitors a data source. + +This almost empty class is meant to be inherited by subclasses specific to +their data source. + +""" + +class EmonHubInterfacer(threading.Thread): + + def __init__(self, name): + + # Initialize logger + self._log = logging.getLogger("EmonHub") + + # Initialise thread + threading.Thread.__init__(self) + self.setName(name) + + # Initialise settings + self.init_settings = {} + self._defaults = {'pause': 'off', 'interval': 0, 'datacode': '0', + 'scale':'1', 'timestamped': False, 'targeted': False, 'nodeoffset' : '0','pubchannels':["ch1"],'subchannels':["ch2"]} + self._settings = {} + + # This line will stop the default values printing to logfile at start-up + # unless they have been overwritten by emonhub.conf entries + # comment out if diagnosing a startup value issue + self._settings.update(self._defaults) + + # Initialize interval timer's "started at" timestamp + self._interval_timestamp = 0 + + # create a stop + self.stop = False + + def run(self): + """ + Run the interfacer. + Any regularly performed tasks actioned here along with passing received values + + """ + + while not self.stop: + # Read the input and process data if available + rxc = self.read() + # if 'pause' in self._settings and \ + # str.lower(self._settings['pause']) in ['all', 'in']: + # pass + # else: + if rxc: + rxc = self._process_rx(rxc) + if rxc: + for channel in self._settings["pubchannels"]: + dispatcher.send(channel, cargo=rxc) + self._log.debug(str(rxc.uri) + " Sent to channel' : " + str(channel)) + + # Don't loop to fast + time.sleep(0.1) + # Action reporter tasks + self.action() + + # Subscribed channels entry + def receiver(self, cargo): + txc = self._process_tx(cargo) + self.send(txc) + + def read(self): + """Read raw data from interface and pass for processing. + Specific version to be created for each interfacer + Returns an EmonHubCargo object + """ + pass + + + def send(self, cargo): + """Send data from interface. + Specific version to be created for each interfacer + Accepts an EmonHubCargo object + """ + pass + + + def action(self): + """Action any interfacer tasks, + Specific version to be created for each interfacer + """ + pass + + + def _process_rx(self, cargo): + """Process a frame of data + + f (string): 'NodeID val1 val2 ...' + + This function splits the string into numbers and check its validity. + + 'NodeID val1 val2 ...' is the generic data format. If the source uses + a different format, override this method. + + Return data as a list: [NodeID, val1, val2] + + """ + + # Log data + self._log.debug(str(cargo.uri) + " NEW FRAME : " + cargo.rawdata) + + rxc = cargo + decoded = [] + node = str(rxc.nodeid) + datacode = True + + # Discard if data is non-existent + if len(rxc.realdata) < 1: + self._log.warning(str(cargo.uri) + " Discarded RX frame 'string too short' : " + str(rxc.realdata)) + return False + + # Discard if anything non-numerical found + try: + [float(val) for val in rxc.realdata] + except Exception: + self._log.warning(str(cargo.uri) + " Discarded RX frame 'non-numerical content' : " + str(rxc.realdata)) + return False + + # Discard if first value is not a valid node id + # n = float(rxc.realdata[0]) + # if n % 1 != 0 or n < 0 or n > 31: + # self._log.warning(str(cargo.uri) + " Discarded RX frame 'node id outside scope' : " + str(rxc.realdata)) + # return False + + # check if node is listed and has individual datacodes for each value + if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'datacodes' in ehc.nodelist[node]['rx']: + + # fetch the string of datacodes + datacodes = ehc.nodelist[node]['rx']['datacodes'] + + # fetch a string of data sizes based on the string of datacodes + datasizes = [] + for code in datacodes: + datasizes.append(ehc.check_datacode(str(code))) + # Discard the frame & return 'False' if it doesn't match the summed datasizes + if len(rxc.realdata) != sum(datasizes): + self._log.warning(str(rxc.uri) + " RX data length: " + str(len(rxc.realdata)) + + " is not valid for datacodes " + str(datacodes)) + return False + else: + # Determine the expected number of values to be decoded + count = len(datacodes) + # Set decoder to "Per value" decoding using datacode 'False' as flag + datacode = False + else: + # if node is listed, but has only a single default datacode for all values + if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'datacode' in ehc.nodelist[node]['rx']: + datacode = ehc.nodelist[node]['rx']['datacode'] + else: + # when node not listed or has no datacode(s) use the interfacers default if specified + datacode = self._settings['datacode'] + # Ensure only int 0 is passed not str 0 + if datacode == '0': + datacode = 0 + # when no (default)datacode(s) specified, pass string values back as numerical values + if not datacode: + for val in rxc.realdata: + if float(val) % 1 != 0: + val = float(val) + else: + val = int(float(val)) + decoded.append(val) + # Discard frame if total size is not an exact multiple of the specified datacode size. + elif len(rxc.realdata) % ehc.check_datacode(datacode) != 0: + self._log.warning(str(rxc.uri) + " RX data length: " + str(len(rxc.realdata)) + + " is not valid for datacode " + str(datacode)) + return False + else: + # Determine the number of values in the frame of the specified code & size + count = len(rxc.realdata) / ehc.check_datacode(datacode) + + # Decode the string of data one value at a time into "decoded" + if not decoded: + bytepos = int(0) + for i in range(0, count, 1): + # Use single datacode unless datacode = False then use datacodes + dc = str(datacode) + if not datacode: + dc = str(datacodes[i]) + # Determine the number of bytes to use for each value by it's datacode + size = int(ehc.check_datacode(dc)) + try: + value = ehc.decode(dc, [int(v) for v in rxc.realdata[bytepos:bytepos+size]]) + except: + self._log.warning(str(rxc.uri) + " Unable to decode as values incorrect for datacode(s)") + return False + bytepos += size + decoded.append(value) + + # check if node is listed and has individual scales for each value + if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'scales' in ehc.nodelist[node]['rx']: + scales = ehc.nodelist[node]['rx']['scales'] + # === Removed check for scales length so that failure mode is more gracious === + # Discard the frame & return 'False' if it doesn't match the number of scales + # if len(decoded) != len(scales): + # self._log.warning(str(rxc.uri) + " Scales " + str(scales) + " for RX data : " + str(rxc.realdata) + " not suitable " ) + # return False + # else: + # Determine the expected number of values to be decoded + # Set decoder to "Per value" scaling using scale 'False' as flag + # scale = False + if len(scales)>1: + scale = False + else: + scale = "1" + else: + # if node is listed, but has only a single default scale for all values + if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'scale' in ehc.nodelist[node]['rx']: + scale = ehc.nodelist[node]['rx']['scale'] + else: + # when node not listed or has no scale(s) use the interfacers default if specified + scale = self._settings['scale'] + + if not scale == "1": + for i in range(0, len(decoded), 1): + x = scale + if not scale: + if i= 0 and int(setting) < 256: + # pass + # elif key == 'txchannels' and int(setting) >= 0 and int(setting) < 256: + # pass + else: + self._log.warning("In interfacer set '%s' is not a valid setting for %s: %s" % (str(setting), self.name, key)) + continue + self._settings[key] = setting + self._log.debug("Setting " + self.name + " " + key + ": " + str(setting)) + + # Is there a better place to put this? + for channel in self._settings["subchannels"]: + dispatcher.connect(self.receiver, channel) + self._log.debug("Interfacer: Subscribed to channel' : " + str(channel)) + + +"""class EmonHubInterfacerInitError + +Raise this when init fails. + +""" +class EmonHubInterfacerInitError(Exception): + pass + + + + + diff --git a/emonhub/src/interfacers/portal_package.py b/emonhub/src/interfacers/portal_package.py new file mode 100644 index 0000000..887ebc9 --- /dev/null +++ b/emonhub/src/interfacers/portal_package.py @@ -0,0 +1,44 @@ +import datetime + +class PortalPackage: + datasource_name = '' + timestamp = 0 + value = None + unit = '' + + WATTHOUR = 'Wh' + WATT = 'W' + SECOND = 'sec' + CELSIUS = 'C' + PULSE = 'p' + + + VALUE_TO_BASEVALUE_MULTIPLIERS = { + WATTHOUR: 1000, + WATT: 1000, + SECOND: 1, + CELSIUS: 273.15, + PULSE: 1, + } + + UNIT_TO_BASEUNIT = { + WATTHOUR: 'milliwatt*hour', + WATT: 'milliwatt', + SECOND: 'impulse', + CELSIUS: 'millikelvin', + PULSE: 'impulse', + } + + def __init__(self, datasource_name, timestamp, value, unit): + self.datasource_name = datasource_name + self.timestamp = datetime.datetime.fromtimestamp(timestamp) + + if value > 0 or value < 0: + if unit == self.CELSIUS: + self.value = int((value + PortalPackage.VALUE_TO_BASEVALUE_MULTIPLIERS[unit]) * 1000) + else: + self.value = int(value * PortalPackage.VALUE_TO_BASEVALUE_MULTIPLIERS[unit]) + else: + self.value = int(value) + + self.unit = PortalPackage.UNIT_TO_BASEUNIT[unit] \ No newline at end of file diff --git a/emonhub/src/scnordic_bridge.py b/emonhub/src/scnordic_bridge.py new file mode 100644 index 0000000..7eae627 --- /dev/null +++ b/emonhub/src/scnordic_bridge.py @@ -0,0 +1,90 @@ +import datetime +import time +import requests + +from configobj import ConfigObj +from requests.auth import AuthBase + + +class TokenAuth(AuthBase): + """Attaches HTTP Token Authentication to the given Request object.""" + + def __init__(self, token): + # setup any auth-related data here + self.token = token + + def __call__(self, r): + # modify and return the request + r.headers['Authorization'] = "token %s" % self.token + return r + + +class RequestHandler(): + def __init__(self, api_key, api_base_url): + + self.auth = TokenAuth(api_key) + self.base_url = api_base_url + self.config = ConfigObj('/tmp/endpoint.cache') + + def fetch_endpoint(self, name): + payload = {'hardware_id': name} + try: + r = requests.get('%s/datasources/customer_datasources/' % self.base_url, auth=self.auth, params=payload, + timeout=1) + except: + return None + response = {} + + if r.status_code == requests.codes.ok: + response = r.json() + + if response['count'] == 1: + self.config[name] = { + 'timestamp': time.time(), + 'endpoint': response['results'][0]['rawData'] + } + self.config.write() + return response['results'][0]['rawData'] + else: + return None + else: + return None + + def get_endpoint(self, name): + try: + cached = self.config[name] + + if (datetime.datetime.fromtimestamp( + float(cached['timestamp'])) > datetime.datetime.now() - datetime.timedelta(minutes=10)): + return cached['endpoint'] + else: + return self.fetch_endpoint(name) + except KeyError: + return self.fetch_endpoint(name) + + # TODO: Handle error logging + def send_measurement(self, package): + print package.datasource_name + endpoint = self.get_endpoint(package.datasource_name) + + if endpoint: + payload = { + "timestamp": package.timestamp.strftime("%Y-%m-%dT%H:%M:%S"), + "value": package.value, + "unit": package.unit, + } + + try: + r = requests.post(endpoint, auth=self.auth, data=payload) + return r.status_code + except: + return 500 + return 500 + + + + + + + + diff --git a/energymanager/__init__.py b/energymanager/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/configuration_site/__init__.py b/energymanager/configuration_site/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/configuration_site/admin.py b/energymanager/configuration_site/admin.py new file mode 100644 index 0000000..69b764b --- /dev/null +++ b/energymanager/configuration_site/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin + +from gridplatform.customer_datasources.models import CustomerDataSource + + +class CustomerDataSourceAdmin(admin.ModelAdmin): + pass + +admin.site.register(CustomerDataSource, CustomerDataSourceAdmin) \ No newline at end of file diff --git a/energymanager/configuration_site/forms.py b/energymanager/configuration_site/forms.py new file mode 100644 index 0000000..822af40 --- /dev/null +++ b/energymanager/configuration_site/forms.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.utils.translation import ugettext_lazy +from django.utils.translation import ugettext as _ +from django import forms + +from legacy.devices.models import Meter, Agent + + +class MeterModelForm(forms.ModelForm): + WIBEEE = 0 + WIBEEE_MAX = 1 + DATAHUB = 2 + TYPE_CHOICES = ( + (WIBEEE, _('Wibeee Box')), + # (WIBEEE_MAX, _('Wibeee Max')), + (DATAHUB, _('Datahub')), + ) + + meter_type = forms.ChoiceField( + label=ugettext_lazy('Type'), + choices=TYPE_CHOICES + ) + + agent = forms.ModelChoiceField( + label=ugettext_lazy('Agent'), + queryset=Agent.objects.none, empty_label=None + ) + + class Meta: + model = Meter + fields = ['name', 'location', 'hardware_id'] + + def __init__(self, *args, **kwargs): + customer_id = kwargs.pop('customer_id', '') + super(MeterModelForm, self).__init__(*args, **kwargs) + self.fields['agent'].queryset = Agent.objects.filter( + customer_id=customer_id) diff --git a/energymanager/configuration_site/models.py b/energymanager/configuration_site/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/energymanager/configuration_site/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/energymanager/configuration_site/templates/configuration_site/_agent_list_content.html b/energymanager/configuration_site/templates/configuration_site/_agent_list_content.html new file mode 100644 index 0000000..ee39505 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/_agent_list_content.html @@ -0,0 +1,24 @@ +{% load i18n %} +{% load utils %} + +{% if object_list %} + + + + + + + {% for object in object_list %} + + + + + {% endfor %} + +
{% trans "Mac" %}{% trans "Location" %}
+ {{ object.mac }} + {{ object.location }}
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No agents present." %} +{% endif %} diff --git a/energymanager/configuration_site/templates/configuration_site/_consumption_list_content.html b/energymanager/configuration_site/templates/configuration_site/_consumption_list_content.html new file mode 100644 index 0000000..d289f29 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/_consumption_list_content.html @@ -0,0 +1,26 @@ +{% load i18n %} +{% load bootstrap_tags %} + +{% load utils %} + +{% if object_list %} + + + + + + + + + {% for object in object_list %} + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Unit" %}
{{ object }}{{ object.unit|buckingham_display }}
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No data sequences present." %} +{% endif %} diff --git a/energymanager/configuration_site/templates/configuration_site/_customer_datasource_list_content.html b/energymanager/configuration_site/templates/configuration_site/_customer_datasource_list_content.html new file mode 100644 index 0000000..b8c7184 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/_customer_datasource_list_content.html @@ -0,0 +1,26 @@ +{% load i18n %} +{% load utils %} + +{% if object_list %} + + + + + + + + {% for object in object_list %} + + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Unit" %}{% trans "Hardware ID" %}
+ {{ object.name_plain }} + {{ object.unit|buckingham_display }}{{ object.hardware_id }}
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No customer data sources present." %} +{% endif %} diff --git a/energymanager/configuration_site/templates/configuration_site/_menu.html b/energymanager/configuration_site/templates/configuration_site/_menu.html new file mode 100644 index 0000000..83c43d6 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/_menu.html @@ -0,0 +1,34 @@ +{% load i18n %} + +{% load bootstrap_tags %} + +{% if customer %} + +{% endif %} diff --git a/energymanager/configuration_site/templates/configuration_site/_meter_list_content.html b/energymanager/configuration_site/templates/configuration_site/_meter_list_content.html new file mode 100644 index 0000000..102c494 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/_meter_list_content.html @@ -0,0 +1,28 @@ +{% load i18n %} +{% load utils %} + +{% if object_list %} + + + + + + + + + {% for object in object_list %} + + + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Location" %}{% trans "Type" %}{% trans "Hardware-Id" %}
+ {{ object.name_plain }} + {{ object.location }}{{ object.get_connection_type_display }}{{ object.hardware_id }}
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No meters present." %} +{% endif %} diff --git a/energymanager/configuration_site/templates/configuration_site/_navbar.html b/energymanager/configuration_site/templates/configuration_site/_navbar.html new file mode 100644 index 0000000..909ca6c --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/_navbar.html @@ -0,0 +1,11 @@ +{% extends "bootstrap/_navbar_base.html" %} + +{% load i18n %} +{% load bootstrap_tags %} + +{% block home_url %}{% url 'configuration_site:home' %}{% endblock home_url %} +{% block title %}{% trans 'Configuration' %}{% endblock title %} + +{% block menu_extra %} +{% include "utils/customer_selection_nav.html" %} +{% endblock menu_extra %} diff --git a/energymanager/configuration_site/templates/configuration_site/_tariff_list_content.html b/energymanager/configuration_site/templates/configuration_site/_tariff_list_content.html new file mode 100644 index 0000000..50e5749 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/_tariff_list_content.html @@ -0,0 +1,24 @@ +{% load i18n %} +{% load bootstrap_tags %} + +{% load utils %} + +{% if object_list %} + + + + + + + + {% for object in object_list %} + + + + {% endfor %} + +
{% trans "Name" %}
{{ object }}
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No energy tariffs present." %} +{% endif %} diff --git a/energymanager/configuration_site/templates/configuration_site/agent_form.html b/energymanager/configuration_site/templates/configuration_site/agent_form.html new file mode 100644 index 0000000..825575f --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/agent_form.html @@ -0,0 +1,12 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Agent Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/agent_list.html b/energymanager/configuration_site/templates/configuration_site/agent_list.html new file mode 100644 index 0000000..a66fa70 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/agent_list.html @@ -0,0 +1,15 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load pagination %} +{% load bootstrap_tags %} + +{% block content %} +{% panel _("Agents") search=True %} + + {% icon "plus" %} + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/base.html b/energymanager/configuration_site/templates/configuration_site/base.html new file mode 100644 index 0000000..ec19adb --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/base.html @@ -0,0 +1,18 @@ +{% extends "bootstrap/base.html" %} + +{% load i18n %} + +{% block page_title %}{% trans 'Configuration' %}{% endblock %} + +{% block navbar %} +{% include "configuration_site/_navbar.html" %} +{% endblock %} + +{% block sidebar %} +{% include "configuration_site/_menu.html" %} +{% endblock %} + + +{% block page_bottom %} +{% include "utils/customer_selection_modal.html" with urlname='configuration_site:customer' %} +{% endblock page_bottom %} diff --git a/energymanager/configuration_site/templates/configuration_site/choose_customer.html b/energymanager/configuration_site/templates/configuration_site/choose_customer.html new file mode 100644 index 0000000..4a96708 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/choose_customer.html @@ -0,0 +1,9 @@ +{% extends "configuration_site/base.html" %} + +{% block page_js %} + +{% endblock page_js %} diff --git a/energymanager/configuration_site/templates/configuration_site/consumption_detail.html b/energymanager/configuration_site/templates/configuration_site/consumption_detail.html new file mode 100644 index 0000000..094dcad --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/consumption_detail.html @@ -0,0 +1,58 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} + +{% load bootstrap_tags %} +{% load utils %} + +{% block content %} +{% panel panel_title %} + + {% icon "edit" %} + +{% endpanelbuttons %} +{% trans "Unit" %}: {{ object.unit|buckingham_display }} + + +
+
+ {% bootstrap_form layout="inline" %} + {% form chart_form %} + {% form_buttons submit_label=_('Load') cancel_target=None delete_target=None %} + {% endbootstrap_form %} +
+
+

{% blocktrans with utility_unit=utility_unit|buckingham_display %}Consumption ({{ utility_unit }}){% endblocktrans %}

+
+ + +{% endpanel %} + +{% panel _("Input periods") %} + + + {% icon "plus" %} + + +{% endpanelbuttons %} + + + + + + + + + {% for inputperiod in object.period_set.all %} + + + + {% empty %} + + {% endfor %} + +
{% trans "From time" %}{% trans "To time" %}
+ {{ inputperiod.from_timestamp }} + {{ inputperiod.to_timestamp }}
{% trans "No input periods present" %}
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/consumption_form.html b/energymanager/configuration_site/templates/configuration_site/consumption_form.html new file mode 100644 index 0000000..e76ed36 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/consumption_form.html @@ -0,0 +1,12 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Consumption Data Sequence Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/consumption_list.html b/energymanager/configuration_site/templates/configuration_site/consumption_list.html new file mode 100644 index 0000000..4066343 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/consumption_list.html @@ -0,0 +1,15 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load pagination %} +{% load bootstrap_tags %} + +{% block content %} +{% panel _("Consumption Data Sequences") search=True %} + + {% icon "plus" %} + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/customer_datasource_form.html b/energymanager/configuration_site/templates/configuration_site/customer_datasource_form.html new file mode 100644 index 0000000..2d275f9 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/customer_datasource_form.html @@ -0,0 +1,12 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Customer Data Source Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/customer_datasource_list.html b/energymanager/configuration_site/templates/configuration_site/customer_datasource_list.html new file mode 100644 index 0000000..d60e962 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/customer_datasource_list.html @@ -0,0 +1,15 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load pagination %} +{% load bootstrap_tags %} + +{% block content %} +{% panel _("Customer Data Sources") search=True %} + + {% icon "plus" %} + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/meter_form.html b/energymanager/configuration_site/templates/configuration_site/meter_form.html new file mode 100644 index 0000000..92204b0 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/meter_form.html @@ -0,0 +1,12 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Meter Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/meter_list.html b/energymanager/configuration_site/templates/configuration_site/meter_list.html new file mode 100644 index 0000000..9194db0 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/meter_list.html @@ -0,0 +1,15 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load pagination %} +{% load bootstrap_tags %} + +{% block content %} +{% panel _("Meters") search=True %} + + {% icon "plus" %} + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/nonpulseperiod_form.html b/energymanager/configuration_site/templates/configuration_site/nonpulseperiod_form.html new file mode 100644 index 0000000..f16fd70 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/nonpulseperiod_form.html @@ -0,0 +1,11 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + +{% block content %} +{% panel _("Input Period Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/tariff_form.html b/energymanager/configuration_site/templates/configuration_site/tariff_form.html new file mode 100644 index 0000000..40f3344 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/tariff_form.html @@ -0,0 +1,12 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Energy Tariff Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/configuration_site/templates/configuration_site/tariff_list.html b/energymanager/configuration_site/templates/configuration_site/tariff_list.html new file mode 100644 index 0000000..4e3da16 --- /dev/null +++ b/energymanager/configuration_site/templates/configuration_site/tariff_list.html @@ -0,0 +1,15 @@ +{% extends "configuration_site/base.html" %} +{% load i18n %} +{% load pagination %} +{% load bootstrap_tags %} + +{% block content %} +{% panel _("Energy Tariffs") search=True %} + + {% icon "plus" %} + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/configuration_site/tests.py b/energymanager/configuration_site/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/energymanager/configuration_site/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/energymanager/configuration_site/urls.py b/energymanager/configuration_site/urls.py new file mode 100644 index 0000000..2af9a53 --- /dev/null +++ b/energymanager/configuration_site/urls.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.conf.urls import patterns +from django.conf.urls import url +from django.conf.urls import include + +from gridplatform.utils.urls import restricted_url + +from . import views + +urlpatterns = patterns( + 'energymanager.configuration_site_view.views', + url(r'^$', + views.HomeView.as_view(), + name='home'), + url(r'^customer/(?P\d+)/$', + views.CustomerView.as_view(), + name='customer'), + url(r'^choose-customer/$', + views.ChooseCustomer.as_view(), + name='choose-customer'), + + url(r'^customerdatasource/(?P\d+)/$', + views.CustomerDataSourceList.as_view(), + name='customer-datasource-list'), + url(r'^customerdatasource/content/(?P\d+)/$', + views.CustomerDataSourceListContentView.as_view(), + name='customer-datasource-list-content'), + url(r'^customerdatasource/create/(?P\d+)/$', + views.CustomerDataSourceCreateView.as_view(), + name='customer-datasource-create'), + url(r'^customerdatasource/update/(?P\d+)/(?P\d+)/$', + views.CustomerDataSourceUpdateView.as_view(), + name='customer-datasource-update'), + url(r'^customerdatasource/delete/(?P\d+)/(?P\d+)/$', + views.CustomerDataSourceDeleteView.as_view(), + name='customer-datasource-delete'), + + url(r'^consumption/(?P\d+)/$', + views.ConsumptionList.as_view(), + name='consumption-list'), + url(r'^consumption/content/(?P\d+)/$', + views.ConsumptionListContentView.as_view(), + name='consumption-list-content'), + url(r'^consumption/detail/(?P\d+)/' + r'(?P\d+)/$', + views.ConsumptionDetailView.as_view(), + name='consumption-detail'), + url(r'^consumption/create/(?P\d+)/$', + views.ConsumptionCreateView.as_view(), + name='consumption-create'), + url(r'^consumption/update/(?P\d+)/' + r'(?P\d+)/$', + views.ConsumptionUpdateView.as_view(), + name='consumption-update'), + url(r'^consumption/delete/(?P\d+)/' + r'(?P\d+)/$', + views.ConsumptionDeleteView.as_view(), + name='consumption-delete'), + + url(r'^consumption/(?P\d+)/' + r'(?P\d+)/nonpulseperiod/create/$', + views.ConsumptionNonpulsePeriodCreateView.as_view(), + name='consumptionnonpulseperiod-create'), + url(r'^consumption/(?P\d+)/' + r'(?P\d+)/nonpulseperiod/update/' + r'(?P\d+)/$', + views.ConsumptionNonpulsePeriodUpdateView.as_view(), + name='consumptionnonpulseperiod-update'), + url(r'^nonpulseperiod/(?P\d+)/delete/' + r'(?P\d+)/$', + views.ConsumptionNonpulsePeriodDeleteView.as_view(), + name='consumptionnonpulseperiod-delete'), + + url(r'^consumption/(?P\d+)/start/(?P\d+)/$', # noqa + views.StartWeekConsumptionUtilityBarChartView.as_view(), + name='consumption-utility-bar-chart-start'), + url(r'^consumption/(?P\d+)/finalize/$', + views.FinalizeWeekUtilityBarChartView.as_view(), + name='utility-bar-chart-finalize'), + + url(r'^tariff/(?P\d+)/$', + views.TariffList.as_view(), + name='tariff-list'), + url(r'^tariff/content/(?P\d+)/$', + views.TariffListContentView.as_view(), + name='tariff-list-content'), + url(r'^tariff/create/(?P\d+)/$', + views.TariffCreateView.as_view(), + name='tariff-create'), + url(r'^tariff/update/(?P\d+)/(?P\d+)/$', + views.TariffUpdateView.as_view(), + name='tariff-update'), + + url(r'^agent/(?P\d+)/$', + views.AgentList.as_view(), + name='agent-list'), + url(r'^agent/content/(?P\d+)/$', + views.AgentListContentView.as_view(), + name='agent-list-content'), + url(r'^agent/create/(?P\d+)/$', + views.AgentCreateView.as_view(), + name='agent-create'), + url(r'^agent/update/(?P\d+)/(?P\d+)/$', + views.AgentUpdateView.as_view(), + name='agent-update'), + + url(r'^meter/(?P\d+)/$', + views.MeterList.as_view(), + name='meter-list'), + url(r'^meter/content/(?P\d+)/$', + views.MeterListContentView.as_view(), + name='meter-list-content'), + url(r'^meter/create/(?P\d+)/$', + views.MeterCreateView.as_view(), + name='meter-create'), + url(r'^meter/update/(?P\d+)/(?P\d+)/$', + views.MeterUpdateView.as_view(), + name='meter-update'), +) diff --git a/energymanager/configuration_site/views.py b/energymanager/configuration_site/views.py new file mode 100644 index 0000000..051f84b --- /dev/null +++ b/energymanager/configuration_site/views.py @@ -0,0 +1,698 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +import operator + +from django.core.urlresolvers import reverse +from django.utils.translation import ugettext_lazy as _ +from django.utils.functional import cached_property +from django.shortcuts import get_object_or_404 +from django.utils.formats import date_format + +from gridplatform.utils import generic_views +from gridplatform.utils.breadcrumbs import Breadcrumb +from gridplatform.utils.breadcrumbs import Breadcrumbs +from gridplatform.utils.views import ChooseCustomerBase +from gridplatform.utils.views import CustomerInKwargsMixin +from gridplatform.utils.views import CustomerListMixin +from gridplatform.utils.views import CustomerViewBase +from gridplatform.utils.views import HomeViewBase +from gridplatform.consumptions.tasks import consumptions_weekly_utility_task # noqa +from gridplatform.customer_datasources.models import CustomerDataSource +from gridplatform.consumptions.models import Consumption +from gridplatform.utils.forms import HalfOpenTimePeriodModelForm +from gridplatform.consumptions.models import NonpulsePeriod +from gridplatform.utils.unitconversion import PhysicalQuantity +from gridplatform.utils.utilitytypes import ENERGY_UTILITY_TYPE_TO_DISPLAY_UNIT_MAP # noqa +from gridplatform.utils.views import StartTaskView +from gridplatform.utils.forms import YearWeekPeriodForm +from gridplatform.utils.forms import this_week_initial_values +from gridplatform.utils.views import FinalizeTaskView +from gridplatform.utils.preferredunits import PhysicalUnitConverter +from gridplatform.utils.views import JsonResponse +from gridplatform.tariffs.models import EnergyTariff +from legacy.devices.models import Agent, Meter, PhysicalInput + +from .forms import MeterModelForm + +class HomeView(HomeViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'configuration_site:customer-datasource-list', + kwargs={'customer_id': customer_id}) + + def get_choose_customer_url(self): + return reverse( + 'configuration_site:choose-customer') + + +class ChooseCustomer(ChooseCustomerBase): + template_name = 'configuration_site/choose_customer.html' + + +class CustomerView(CustomerViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'configuration_site:customer-datasource-list', + kwargs={'customer_id': customer_id}) + + +class CustomerDataSourceList( + CustomerListMixin, generic_views.TemplateView): + template_name = 'configuration_site/customer_datasource_list.html' + + @staticmethod + def build_breadcrumbs(customer_id): + return Breadcrumbs() + Breadcrumb( + _('Customer Data Sources'), + reverse( + 'configuration_site:customer-datasource-list', + kwargs={'customer_id': customer_id})) + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id) + + +class CustomerDataSourceListContentView( + CustomerListMixin, generic_views.ListView): + model = CustomerDataSource + template_name = 'configuration_site/_customer_datasource_list_content.html' + paginate_by = 40 + sort_fields = ['name_plain', 'unit', 'hardware_id', ] + search_fields = ['name_plain', 'unit', 'hardware_id', ] + + +class CustomerDataSourceCreateView( + CustomerListMixin, generic_views.CreateView): + model = CustomerDataSource + template_name = 'configuration_site/customer_datasource_form.html' + fields = ('name', 'unit', 'hardware_id') + + def form_valid(self, form): + form.instance.customer_id = self._customer.id + return super(CustomerDataSourceCreateView, self).form_valid( + form) + + def get_success_url(self): + return reverse( + 'configuration_site:customer-datasource-list', + kwargs={'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse( + 'configuration_site:customer-datasource-list', + kwargs={'customer_id': self._customer.id}) + + def get_breadcrumbs(self): + return CustomerDataSourceList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Create LED Light Project')) + + +class CustomerDataSourceUpdateView( + CustomerListMixin, generic_views.UpdateView): + model = CustomerDataSource + template_name = 'configuration_site/customer_datasource_form.html' + fields = ( + 'name', 'hardware_id', + ) + + def get_success_url(self): + return reverse( + 'configuration_site:customer-datasource-list', + kwargs={'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse( + 'configuration_site:customer-datasource-list', + kwargs={'customer_id': self._customer.id}) + + def get_delete_url(self): + if not self.object.rawdata_set.all(): + return reverse('configuration_site:customer-datasource-delete', + kwargs={'customer_id': + self._customer.id, + 'pk': + self.object.id}) + + def get_breadcrumbs(self): + return CustomerDataSourceList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(self.object) + + +class CustomerDataSourceDeleteView( + CustomerListMixin, generic_views.DeleteView): + model = CustomerDataSource + + def get_success_url(self): + return reverse( + 'configuration_site:customer-datasource-list', + kwargs={'customer_id': self._customer.id}) + + +class ConsumptionList( + CustomerListMixin, generic_views.TemplateView): + template_name = 'configuration_site/consumption_list.html' + + @staticmethod + def build_breadcrumbs(customer_id): + return Breadcrumbs() + Breadcrumb( + _('Consumptions'), + reverse( + 'configuration_site:consumption-list', + kwargs={'customer_id': customer_id})) + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id) + + +class ConsumptionListContentView( + CustomerListMixin, generic_views.ListView): + model = Consumption + template_name = \ + 'configuration_site/_consumption_list_content.html' + paginate_by = 40 + search_fields = ['name', ] + + +class ChartFormViewMixin(object): + def get_context_data(self, **kwargs): + if 'chart_form' not in kwargs: + kwargs['chart_form'] = YearWeekPeriodForm( + this_week_initial_values()) + return super(ChartFormViewMixin, self).get_context_data(**kwargs) + + +class ConsumptionDetailView( + CustomerListMixin, ChartFormViewMixin, generic_views.DetailView): + model = Consumption + template_name = \ + 'configuration_site/consumption_detail.html' + + @staticmethod + def build_breadcrumbs(customer_id, consumption_id): + return ConsumptionList.build_breadcrumbs(customer_id) + \ + Breadcrumb( + _('Consumption Detail'), + reverse( + 'configuration_site:consumption-detail', + kwargs={'customer_id': customer_id, 'pk': consumption_id})) + + def get_context_data(self, **kwargs): + context = super( + ConsumptionDetailView, + self).get_context_data(**kwargs) + context['panel_title'] = \ + _('Consumption: %(name)s' % { + 'name': self.object}) + + if 'utility_unit' not in kwargs: + context['utility_unit'] = 'watt*hours' + + return context + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id, self.object.id) + + +class PeriodForm(HalfOpenTimePeriodModelForm): + class Meta: + fields = ('datasequence',) + localized_fields = '__all__' + + +class PeriodViewMixin(object): + @cached_property + def _datasequence(self): + datasequence_model = self.model._meta.get_field('datasequence').rel.to + return get_object_or_404( + datasequence_model, id=self.kwargs['datasequence_id']) + + def get_form(self, form_class): + form = super(PeriodViewMixin, self).get_form(form_class) + form.instance.datasequence = self._datasequence + datasource_choices = [ + (ds.id, unicode(ds)) for ds in + form.fields['datasource'].queryset.all() + if PhysicalQuantity.compatible_units( + ds.unit, self._datasequence.unit) + ] + datasource_choices.sort(key=operator.itemgetter(1)) + form.fields['datasource'].choices = ((None, '---------'),) + tuple( + datasource_choices) + return form + + +class StartWeekConsumptionUtilityBarChartView( + CustomerInKwargsMixin, StartTaskView): + task = consumptions_weekly_utility_task + finalize_url_name = 'configuration_site:utility-bar-chart-finalize' + form_class = YearWeekPeriodForm + + def get_task_kwargs(self, form): + from_timestamp, to_timestamp = form.get_timestamps() + result = {} + result['consumption_ids'] = [self.kwargs['consumption_id']] + result['from_timestamp'] = from_timestamp + result['to_timestamp'] = to_timestamp + return result + + def get_finalize_url(self): + return reverse( + self.finalize_url_name, + kwargs={'customer_id': self._customer.id}) + + +class FinalizeWeekUtilityBarChartView(CustomerInKwargsMixin, FinalizeTaskView): + def finalize_task(self, task_result): + unit = ENERGY_UTILITY_TYPE_TO_DISPLAY_UNIT_MAP[ + 2000] + print unit + self.unit_converter = PhysicalUnitConverter('watt*hour') + + def format_label(timestamp): + return date_format( + timestamp.astimezone(self._customer.timezone), + 'SHORT_DATETIME_FORMAT') + + result = { + 'labels': [], + 'week_selected': [], + } + + selected_sequence = iter(task_result['week_selected']) + + selected = next(selected_sequence, None) + + while selected is not None: + + result['labels'].append(format_label(selected.from_timestamp)) + result['week_selected'].append( + float(self.unit_converter.extract_value( + selected.physical_quantity))) + selected = next(selected_sequence, None) + + return JsonResponse(result) + + +class ConsumptionNonpulsePeriodForm(PeriodForm): + class Meta(PeriodForm.Meta): + model = NonpulsePeriod + fields = ('datasource',) + + +class ConsumptionNonpulsePeriodCreateView( + CustomerListMixin, PeriodViewMixin, generic_views.CreateView): + model = NonpulsePeriod + template_name = \ + 'configuration_site/nonpulseperiod_form.html' + form_class = ConsumptionNonpulsePeriodForm + + def get_success_url(self): + return reverse( + 'configuration_site:consumption-detail', + kwargs={'pk': self.kwargs['datasequence_id'], + 'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse('configuration_site:consumption-detail', + kwargs={'pk': self.kwargs['datasequence_id'], + 'customer_id': self._customer.id}) + + def get_breadcrumbs(self): + return ConsumptionDetailView.build_breadcrumbs( + self._customer.id, self.kwargs['datasequence_id']) + \ + Breadcrumb(_('Create input period')) + + +class ConsumptionNonpulsePeriodUpdateView( + CustomerListMixin, PeriodViewMixin, generic_views.UpdateView): + model = NonpulsePeriod + template_name = \ + 'configuration_site/nonpulseperiod_form.html' + form_class = ConsumptionNonpulsePeriodForm + + def get_success_url(self): + return reverse( + 'configuration_site:consumption-detail', + kwargs={'pk': self.object.datasequence_id, + 'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse('configuration_site:consumption-detail', + kwargs={'pk': self.object.datasequence_id, + 'customer_id': self._customer.id}) + + def get_delete_url(self): + return reverse('configuration_site:consumptionnonpulseperiod-delete', + kwargs={'pk': self.object.id, + 'customer_id': self._customer.id}) + + def get_breadcrumbs(self): + return ConsumptionDetailView.build_breadcrumbs( + self._customer.id, self.kwargs['datasequence_id']) + \ + Breadcrumb(_('Edit input period')) + + +class ConsumptionNonpulsePeriodDeleteView( + CustomerListMixin, generic_views.DeleteView): + model = NonpulsePeriod + + def get_success_url(self): + return reverse( + 'configuration_site:consumption-detail', + kwargs={'pk': self.object.datasequence_id, + 'customer_id': self._customer.id}) + + +class ConsumptionCreateView( + CustomerListMixin, generic_views.CreateView): + model = Consumption + template_name = \ + 'configuration_site/consumption_form.html' + fields = ('name', 'unit',) + + def get_success_url(self): + return reverse( + 'configuration_site:consumption-detail', + kwargs={'pk': self.object.id, 'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse('configuration_site:consumption-list', + kwargs={'customer_id': self._customer.id}) + + def get_breadcrumbs(self): + return ConsumptionList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Create Consumption Datasequence')) + + +class ConsumptionUpdateView( + CustomerListMixin, generic_views.UpdateView): + model = Consumption + template_name = \ + 'configuration_site/consumption_form.html' + fields = ('name', ) + + def get_success_url(self): + return reverse( + 'configuration_site:consumption-detail', + kwargs={'pk': self.object.id, 'customer_id': self._customer.id}) + + def get_breadcrumbs(self): + return ( + (_('Data Sequences'), + reverse( + 'configuration_site:consumption-list', + kwargs={'customer_id': self._customer.id})), + (self.object, + reverse( + 'configuration_site:consumption-detail', + kwargs={'pk': self.object.id, + 'customer_id': self._customer.id})), + (_('Edit consumption data sequence'), ''), + ) + + def get_cancel_url(self): + return reverse('configuration_site:consumption-detail', + kwargs={'pk': self.object.id, + 'customer_id': self._customer.id}) + + def get_delete_url(self): + return reverse('configuration_site:consumption-delete', + kwargs={'pk': self.object.id, + 'customer_id': self._customer.id}) + + +class ConsumptionDeleteView( + CustomerListMixin, generic_views.DeleteView): + model = Consumption + + def get_success_url(self): + return reverse( + 'configuration_site:consumption-list', + kwargs={'customer_id': self._customer.id}) + + +class TariffList( + CustomerListMixin, generic_views.TemplateView): + template_name = 'configuration_site/tariff_list.html' + + @staticmethod + def build_breadcrumbs(customer_id): + return Breadcrumbs() + Breadcrumb( + _('Tariffs'), + reverse( + 'configuration_site:tariff-list', + kwargs={'customer_id': customer_id})) + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id) + + +class TariffListContentView( + CustomerListMixin, generic_views.ListView): + model = EnergyTariff + template_name = \ + 'configuration_site/_tariff_list_content.html' + paginate_by = 40 + search_fields = ['name', ] + + +class TariffCreateView( + CustomerListMixin, generic_views.CreateView): + model = EnergyTariff + template_name = \ + 'configuration_site/tariff_form.html' + fields = ('name',) + + def get_success_url(self): + return reverse( + 'configuration_site:tariff-list', + kwargs={'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse('configuration_site:tariff-list', + kwargs={'customer_id': self._customer.id}) + + def get_breadcrumbs(self): + return TariffList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Create Energy Tariff')) + + +class TariffUpdateView( + CustomerListMixin, generic_views.UpdateView): + model = EnergyTariff + template_name = \ + 'configuration_site/tariff_form.html' + fields = ('name', ) + + def get_breadcrumbs(self): + return TariffList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Update Energy Tariff')) + + def get_success_url(self): + return reverse( + 'configuration_site:tariff-list', + kwargs={'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse('configuration_site:tariff-list', + kwargs={'customer_id': self._customer.id}) + + +class AgentList( + CustomerListMixin, generic_views.TemplateView): + template_name = 'configuration_site/agent_list.html' + + @staticmethod + def build_breadcrumbs(customer_id): + return Breadcrumbs() + Breadcrumb( + _('Agents'), + reverse( + 'configuration_site:agent-list', + kwargs={'customer_id': customer_id})) + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id) + + +class AgentListContentView( + CustomerListMixin, generic_views.ListView): + model = Agent + template_name = 'configuration_site/_agent_list_content.html' + paginate_by = 40 + sort_fields = ['mac', 'location', ] + search_fields = ['mac', 'location', ] + + +class AgentCreateView( + CustomerListMixin, generic_views.CreateView): + model = Agent + template_name = \ + 'configuration_site/agent_form.html' + fields = ('mac', 'location') + + def form_valid(self, form): + form.instance.customer_id = self._customer.id + return super(AgentCreateView, self).form_valid( + form) + + def get_success_url(self): + return reverse( + 'configuration_site:agent-list', + kwargs={'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse('configuration_site:agent-list', + kwargs={'customer_id': self._customer.id}) + + def get_breadcrumbs(self): + return AgentList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Create Agent')) + + +class AgentUpdateView( + CustomerListMixin, generic_views.UpdateView): + model = Agent + template_name = \ + 'configuration_site/agent_form.html' + fields = ('location', ) + + def get_breadcrumbs(self): + return AgentList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Update Agent')) + + def get_success_url(self): + return reverse( + 'configuration_site:agent-list', + kwargs={'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse('configuration_site:agent-list', + kwargs={'customer_id': self._customer.id}) + + +class MeterList( + CustomerListMixin, generic_views.TemplateView): + template_name = 'configuration_site/meter_list.html' + + @staticmethod + def build_breadcrumbs(customer_id): + return Breadcrumbs() + Breadcrumb( + _('Meters'), + reverse( + 'configuration_site:meter-list', + kwargs={'customer_id': customer_id})) + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id) + + +class MeterListContentView( + CustomerListMixin, generic_views.ListView): + model = Meter + template_name = 'configuration_site/_meter_list_content.html' + paginate_by = 40 + sort_fields = ['name', 'connection_type', "hardware_id", "location"] + search_fields = ['name', 'connection_type', "hardware_id", "location"] + + +class MeterCreateView( + CustomerListMixin, generic_views.CreateView): + model = Meter + template_name = \ + 'configuration_site/meter_form.html' + fields = ('name', 'agent', 'connection_type', 'location', 'hardware_id') + form_class = MeterModelForm + + def form_valid(self, form): + form.instance.customer_id = self._customer.id + form.instance.agent_id = self.request.POST.get('agent') + form.instance.connection_type = Meter.WIBEEE + form.instance.manufactoring_id = 0 + + response = super(MeterCreateView, self).form_valid(form) + meter = form.instance + meter_type = int(self.request.POST.get('meter_type')) + if meter_type == MeterModelForm.WIBEEE: + PhysicalInput.objects.create( + meter=meter, + order=0, + hardware_id="e1", + name_plain="Energy Phase 1", + unit="milliwatt*hour", + type=PhysicalInput.ELECTRICITY + ) + PhysicalInput.objects.create( + meter=meter, + order=1, + hardware_id="e2", + name_plain="Energy Phase 2", + unit="milliwatt*hour", + type=PhysicalInput.ELECTRICITY + ) + PhysicalInput.objects.create( + meter=meter, + order=2, + hardware_id="e3", + name_plain="Energy Phase 3", + unit="milliwatt*hour", + type=PhysicalInput.ELECTRICITY + ) + PhysicalInput.objects.create( + meter=meter, + order=3, + hardware_id="et", + name_plain="Energy Total", + unit="milliwatt*hour", + type=PhysicalInput.ELECTRICITY + ) + elif meter_type == MeterModelForm.DATAHUB: + PhysicalInput.objects.create( + meter=meter, + order=0, + name_plain="Datahub", + unit="milliwatt*hour", + type=PhysicalInput.ELECTRICITY + ) + + return response + + def get_form_kwargs(self): + kwargs = super(MeterCreateView, self).get_form_kwargs() + kwargs.update({'customer_id': self._customer.id}) + return kwargs + + def get_success_url(self): + return reverse( + 'configuration_site:meter-list', + kwargs={'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse('configuration_site:meter-list', + kwargs={'customer_id': self._customer.id}) + + def get_breadcrumbs(self): + return MeterList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Create Meter')) + + +class MeterUpdateView( + CustomerListMixin, generic_views.UpdateView): + model = Meter + template_name = \ + 'configuration_site/meter_form.html' + fields = ('name', 'location', 'hardware_id') + + def get_breadcrumbs(self): + return MeterList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Update Meter')) + + def get_success_url(self): + return reverse( + 'configuration_site:meter-list', + kwargs={'customer_id': self._customer.id}) + + def get_cancel_url(self): + return reverse('configuration_site:meter-list', + kwargs={'customer_id': self._customer.id}) diff --git a/energymanager/datahub_site/__init__.py b/energymanager/datahub_site/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/datahub_site/admin.py b/energymanager/datahub_site/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/energymanager/datahub_site/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/energymanager/datahub_site/models.py b/energymanager/datahub_site/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/energymanager/datahub_site/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/energymanager/datahub_site/templates/datahub_site/_datahub_connection_list_content.html b/energymanager/datahub_site/templates/datahub_site/_datahub_connection_list_content.html new file mode 100644 index 0000000..b08285a --- /dev/null +++ b/energymanager/datahub_site/templates/datahub_site/_datahub_connection_list_content.html @@ -0,0 +1,27 @@ +{% load i18n %} + +{% if object_list %} + + + + + + + {% for object in object_list %} + + + + + {% endfor %} + +
{% trans "Meter number" %}
+ {{ object.customer_meter_number }} + + {% if not object.authorization_id %} + Tjek godkendelse + {% endif %} +
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No datahub connections present." %} +{% endif %} diff --git a/energymanager/datahub_site/templates/datahub_site/_menu.html b/energymanager/datahub_site/templates/datahub_site/_menu.html new file mode 100644 index 0000000..eb5cebf --- /dev/null +++ b/energymanager/datahub_site/templates/datahub_site/_menu.html @@ -0,0 +1,13 @@ +{% load i18n %} + +{% load bootstrap_tags %} + +{% if customer %} + +{% endif %} diff --git a/energymanager/datahub_site/templates/datahub_site/_navbar.html b/energymanager/datahub_site/templates/datahub_site/_navbar.html new file mode 100644 index 0000000..8da2a5a --- /dev/null +++ b/energymanager/datahub_site/templates/datahub_site/_navbar.html @@ -0,0 +1,11 @@ +{% extends "bootstrap/_navbar_base.html" %} + +{% load i18n %} +{% load bootstrap_tags %} + +{% block home_url %}{% url 'datahub_site:home' %}{% endblock home_url %} +{% block title %}{% trans 'Datahub' %}{% endblock title %} + +{% block menu_extra %} +{% include "utils/customer_selection_nav.html" %} +{% endblock menu_extra %} diff --git a/energymanager/datahub_site/templates/datahub_site/base.html b/energymanager/datahub_site/templates/datahub_site/base.html new file mode 100644 index 0000000..4596052 --- /dev/null +++ b/energymanager/datahub_site/templates/datahub_site/base.html @@ -0,0 +1,19 @@ +{% extends "bootstrap/base.html" %} + +{% load i18n %} + +{% block page_title %}{% trans 'Datahub' %}{% endblock %} + +{% block navbar %} +{% include "datahub_site/_navbar.html" %} +{% endblock %} + +{% block sidebar %} +{% include "datahub_site/_menu.html" %} +{% endblock %} + + +{% block page_bottom %} +{% include "utils/customer_selection_modal.html" with urlname='datahub_site:customer' %} +{% include "datahub_site/datahub_authorization_modal.html" %} +{% endblock page_bottom %} diff --git a/energymanager/datahub_site/templates/datahub_site/choose_customer.html b/energymanager/datahub_site/templates/datahub_site/choose_customer.html new file mode 100644 index 0000000..010f9fe --- /dev/null +++ b/energymanager/datahub_site/templates/datahub_site/choose_customer.html @@ -0,0 +1,9 @@ +{% extends "datahub_site/base.html" %} + +{% block page_js %} + +{% endblock page_js %} diff --git a/energymanager/datahub_site/templates/datahub_site/datahub_authorization_modal.html b/energymanager/datahub_site/templates/datahub_site/datahub_authorization_modal.html new file mode 100644 index 0000000..3c772a2 --- /dev/null +++ b/energymanager/datahub_site/templates/datahub_site/datahub_authorization_modal.html @@ -0,0 +1,18 @@ +{% load i18n %} + + diff --git a/energymanager/datahub_site/templates/datahub_site/datahub_connection_form.html b/energymanager/datahub_site/templates/datahub_site/datahub_connection_form.html new file mode 100644 index 0000000..43015bc --- /dev/null +++ b/energymanager/datahub_site/templates/datahub_site/datahub_connection_form.html @@ -0,0 +1,12 @@ +{% extends "datahub_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Datahub Connection Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/datahub_site/templates/datahub_site/datahub_connection_list.html b/energymanager/datahub_site/templates/datahub_site/datahub_connection_list.html new file mode 100644 index 0000000..6ef4ce2 --- /dev/null +++ b/energymanager/datahub_site/templates/datahub_site/datahub_connection_list.html @@ -0,0 +1,49 @@ +{% extends "datahub_site/base.html" %} +{% load i18n %} +{% load pagination %} +{% load bootstrap_tags %} +{% block page_js %} + +{% endblock page_js %} +{% block content %} +{% panel _("Datahub Connections") search=True %} + + {% icon "plus" %} + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} + diff --git a/energymanager/datahub_site/tests.py b/energymanager/datahub_site/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/energymanager/datahub_site/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/energymanager/datahub_site/urls.py b/energymanager/datahub_site/urls.py new file mode 100644 index 0000000..58b44a0 --- /dev/null +++ b/energymanager/datahub_site/urls.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.conf.urls import patterns +from django.conf.urls import url + +from . import views + +urlpatterns = patterns( + 'energymanager.price_relay_site.views', + url(r'^$', + views.HomeView.as_view(), + name='home'), + url(r'^customer/(?P\d+)/$', + views.CustomerView.as_view(), + name='customer'), + url(r'^choose-customer/$', + views.ChooseCustomer.as_view(), + name='choose-customer'), + url(r'^connection/(?P\d+)/$', + views.DatahubConnectionList.as_view(), + name='connection-list'), + url(r'^project/content/(?P\d+)/$', + views.DatahubConnectionListContentView.as_view(), + name='connection-list-content'), + url(r'^connection/create/(?P\d+)/$', + views.DatahubConnectionCreateView.as_view(), + name='connection-create'), + url(r'^connection/update/(?P\d+)/(?P\d+)/$', + views.DatahubConnectionUpdateView.as_view(), + name='connection-update'), + url(r'^authorizations/', + views.datahub_authorization_view, + name='authorizations-view'), +) diff --git a/energymanager/datahub_site/views.py b/energymanager/datahub_site/views.py new file mode 100644 index 0000000..aaeb536 --- /dev/null +++ b/energymanager/datahub_site/views.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +import datetime +import calendar +import pycurl +import StringIO + +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext_lazy +from django import forms +from django.core.urlresolvers import reverse +from django.db.models.fields import BLANK_CHOICE_DASH +from django.http import HttpResponse +from django.conf import settings + +from gridplatform.utils import generic_views +from gridplatform.utils import units +from gridplatform.utils.breadcrumbs import Breadcrumb +from gridplatform.utils.breadcrumbs import Breadcrumbs +from gridplatform.utils.views import ChooseCustomerBase +from gridplatform.utils.views import CustomerInKwargsMixin +from gridplatform.utils.views import CustomerListMixin +from gridplatform.utils.views import CustomerViewBase +from gridplatform.utils.views import HomeViewBase +from gridplatform.customers.models import Customer +from gridplatform.utils.forms import YearWeekPeriodForm +from gridplatform.utils.forms import this_week_initial_values +from gridplatform.datahub.models import DatahubConnection +from legacy.devices.models import PhysicalInput + + +class HomeView(HomeViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'datahub_site:connection-list', + kwargs={'customer_id': customer_id}) + + def get_choose_customer_url(self): + return reverse( + 'datahub_site:choose-customer') + + +class ChooseCustomer(ChooseCustomerBase): + template_name = 'datahub_site/choose_customer.html' + + +class CustomerView(CustomerViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'datahub_site:connection-list', + kwargs={'customer_id': customer_id}) + + +class DatahubConnectionList(CustomerListMixin, generic_views.TemplateView): + template_name = 'datahub_site/datahub_connection_list.html' + + @staticmethod + def build_breadcrumbs(customer_id): + return Breadcrumbs() + Breadcrumb( + _('Forbindelser'), + reverse( + 'datahub_site:connection-list', + kwargs={'customer_id': customer_id})) + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id) + + +class DatahubConnectionListContentView( + CustomerListMixin, + generic_views.ListView): + search_fields = ['customer_meter_number', ] + sort_fields = ['customer_meter_number', ] + model = DatahubConnection + paginate_by = 100 + template_name = 'datahub_site/_datahub_connection_list_content.html' + + +class DatahubConnectionForm(forms.ModelForm): + + class Meta: + model = DatahubConnection + fields = ( + 'customer_meter_number', 'meter' + ) + + +class DatahubConnectionCreateView(CustomerListMixin, + generic_views.CreateView): + model = DatahubConnection + template_name = 'datahub_site/datahub_connection_form.html' + form_class = DatahubConnectionForm + + def form_valid(self, form): + form.instance.customer_id = self._customer.id + meter = form.instance.meter + input = PhysicalInput.objects.create( + meter=meter, + order=0, + name_plain="Datahub", + unit="milliwatt*hour", + type=PhysicalInput.ELECTRICITY + ) + + form.instance.input = input + + response = super(DatahubConnectionCreateView, self).form_valid(form) + return response + + def get_success_url(self): + return reverse('datahub_site:connection-list', + kwargs={'customer_id': + self._customer.id}) + + def get_cancel_url(self): + return self.get_success_url() + + def get_breadcrumbs(self): + return DatahubConnectionList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Create connection')) + + +class DatahubConnectionUpdateView(CustomerListMixin, + generic_views.UpdateView): + model = DatahubConnection + template_name = 'datahub_site/datahub_connection_form.html' + fields = ( + 'customer_meter_number', + ) + + def get_success_url(self): + return reverse('datahub_site:connection-list', + kwargs={'customer_id': + self._customer.id}) + + def get_cancel_url(self): + return self.get_success_url() + + def get_breadcrumbs(self): + return DatahubConnectionList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(self.object) + + +def datahub_authorization_view(request): + b = StringIO.StringIO() + c = pycurl.Curl() + url = 'https://eloverblik.dk/api/authorizationsv2' + c.setopt(pycurl.URL, url) + c.setopt(pycurl.WRITEFUNCTION, b.write) + c.setopt(pycurl.SSLKEY, settings.NETS_KEY_DIR + "/plainkey.pem") + c.setopt(pycurl.SSLCERT, settings.NETS_KEY_DIR + "/crt.pem") + c.perform() + c.close() + response_body = b.getvalue() + return HttpResponse(response_body, content_type='application/json') diff --git a/energymanager/energy_projects/__init__.py b/energymanager/energy_projects/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/energy_projects/migrations/0001_initial.py b/energymanager/energy_projects/migrations/0001_initial.py new file mode 100644 index 0000000..6bd2bfe --- /dev/null +++ b/energymanager/energy_projects/migrations/0001_initial.py @@ -0,0 +1,276 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'LedLightProject' + db.create_table(u'energy_projects_ledlightproject', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('encryption_data_initialization_vector', self.gf('gridplatform.encryption.fields.Base64Field')()), + ('customer', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['customers.Customer'])), + ('name', self.gf('gridplatform.encryption.fields.EncryptedCharField')(max_length=50)), + ('previous_tube_count', self.gf('django.db.models.fields.IntegerField')()), + ('previous_consumption_per_tube', self.gf('django.db.models.fields.IntegerField')()), + ('led_tube_count', self.gf('django.db.models.fields.IntegerField')()), + ('led_consumption_per_tube', self.gf('django.db.models.fields.IntegerField')()), + ('price', self.gf('django.db.models.fields.FloatField')()), + ('datasource', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['consumptions.Consumption'], null=True, blank=True)), + )) + db.send_create_signal(u'energy_projects', ['LedLightProject']) + + + def backwards(self, orm): + # Deleting model 'LedLightProject' + db.delete_table(u'energy_projects_ledlightproject') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'consumptions.consumption': { + 'Meta': {'object_name': 'Consumption'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '200'}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}), + 'unit': ('gridplatform.utils.fields.BuckinghamField', [], {'max_length': '100'}), + 'volumetoenergyconversion': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['datasequences.EnergyPerVolumeDataSequence']", 'null': 'True', 'blank': 'True'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'customers.collection': { + 'Meta': {'object_name': 'Collection'}, + 'billing_installation_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), + 'billing_meter_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), + 'comment': ('gridplatform.encryption.fields.EncryptedTextField', [], {'blank': 'True'}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']", 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'gauge_colours': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'gauge_lower_threshold': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'gauge_max': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'gauge_min': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'gauge_preferred_unit': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'gauge_upper_threshold': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'hidden_on_details_page': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'hidden_on_reports_page': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('imagekit.models.fields.ProcessedImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'to': u"orm['customers.Collection']"}), + 'relay': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['devices.Meter']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'role': ('django.db.models.fields.IntegerField', [], {}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'utility_type': ('django.db.models.fields.IntegerField', [], {}) + }, + u'customers.customer': { + 'Meta': {'ordering': "[u'id']", 'object_name': 'Customer'}, + 'address': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'city': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '30', 'blank': 'True'}), + 'contact_email': ('gridplatform.encryption.fields.EncryptedEmailField', [], {'max_length': '50', 'blank': 'True'}), + 'contact_name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'contact_phone': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'country_code': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '3', 'blank': 'True'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'null': 'True', 'to': u"orm['users.User']"}), + 'currency_unit': ('gridplatform.utils.fields.BuckinghamField', [], {'default': "u'currency_dkk'", 'max_length': '100'}), + 'electricity_consumption': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt*hour'", 'max_length': '50'}), + 'electricity_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt'", 'max_length': '50'}), + 'electricity_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'electricity_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'gas_consumption': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter'", 'max_length': '50'}), + 'gas_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter*hour^-1'", 'max_length': '50'}), + 'gas_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'gas_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'heat_consumption': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt*hour'", 'max_length': '50'}), + 'heat_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt'", 'max_length': '50'}), + 'heat_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'heat_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'id': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'oil_consumption': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter'", 'max_length': '50'}), + 'oil_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter*hour^-1'", 'max_length': '50'}), + 'oil_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'oil_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'phone': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'postal_code': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '10', 'blank': 'True'}), + 'production_a_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_b_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_c_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_d_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_e_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'provider': ('django.db.models.fields.related.ForeignKey', [], {'default': '1', 'to': u"orm['providers.Provider']"}), + 'temperature': ('django.db.models.fields.CharField', [], {'default': "u'celsius'", 'max_length': '50'}), + 'timezone': ('timezones2.models.TimeZoneField', [], {'max_length': '64'}), + 'vat': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '20', 'blank': 'True'}), + 'water_consumption': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter'", 'max_length': '50'}), + 'water_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter*hour^-1'", 'max_length': '50'}), + 'water_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'water_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}) + }, + u'customers.location': { + 'Meta': {'object_name': 'Location'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']", 'blank': 'True'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['customers.Location']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + u'datasequences.energypervolumedatasequence': { + 'Meta': {'object_name': 'EnergyPerVolumeDataSequence'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '200'}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}) + }, + u'devices.agent': { + 'Meta': {'ordering': "[u'location', u'mac']", 'object_name': 'Agent'}, + 'add_mode': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Customer']", 'on_delete': 'models.PROTECT'}), + 'device_serial': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'device_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'hw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Location']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'mac': ('gridplatform.utils.fields.MacAddressField', [], {'unique': 'True'}), + 'no_longer_in_use': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'online': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'online_since': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'sw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}) + }, + u'devices.meter': { + 'Meta': {'ordering': "[u'connection_type', u'manufactoring_id', u'id']", 'object_name': 'Meter'}, + 'agent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['devices.Agent']", 'on_delete': 'models.PROTECT'}), + 'connection_type': ('django.db.models.fields.IntegerField', [], {}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Customer']", 'on_delete': 'models.PROTECT'}), + 'device_serial': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'device_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'hw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'joined': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Location']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'manual_mode': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'manufactoring_id': ('django.db.models.fields.BigIntegerField', [], {}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'online': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'online_since': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'relay_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'relay_on': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'sw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}) + }, + u'energy_projects.ledlightproject': { + 'Meta': {'object_name': 'LedLightProject'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']"}), + 'datasource': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['consumptions.Consumption']", 'null': 'True', 'blank': 'True'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'led_consumption_per_tube': ('django.db.models.fields.IntegerField', [], {}), + 'led_tube_count': ('django.db.models.fields.IntegerField', [], {}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'previous_consumption_per_tube': ('django.db.models.fields.IntegerField', [], {}), + 'previous_tube_count': ('django.db.models.fields.IntegerField', [], {}), + 'price': ('django.db.models.fields.FloatField', [], {}) + }, + u'measurementpoints.dataseries': { + 'Meta': {'ordering': "[u'role', u'id']", 'object_name': 'DataSeries'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'graph': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['measurementpoints.Graph']", 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'role': ('legacy.measurementpoints.fields.DataRoleField', [], {}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}), + 'unit': ('gridplatform.utils.fields.BuckinghamField', [], {'max_length': '100', 'blank': 'True'}), + 'utility_type': ('django.db.models.fields.IntegerField', [], {}) + }, + u'measurementpoints.graph': { + 'Meta': {'ordering': "[u'role', u'id']", 'unique_together': "((u'collection', u'role'),)", 'object_name': 'Graph'}, + 'collection': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Collection']"}), + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'role': ('legacy.measurementpoints.fields.DataRoleField', [], {}) + }, + u'providers.provider': { + 'Meta': {'object_name': 'Provider'}, + 'address': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}), + 'city': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}), + 'cvr': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'zipcode': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}) + }, + u'users.user': { + 'Meta': {'ordering': "[u'user_type', u'name', u'id']", 'object_name': 'User', '_ormbases': [u'auth.User']}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Customer']", 'null': 'True', 'blank': 'True'}), + 'e_mail': ('gridplatform.encryption.fields.EncryptedEmailField', [], {'max_length': '75'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'encryption_key_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'encryption_private_key': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'encryption_public_key': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'mobile': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '20', 'blank': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '60'}), + 'phone': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '20'}), + 'provider': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['providers.Provider']", 'null': 'True', 'blank': 'True'}), + u'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}), + 'user_type': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['energy_projects'] \ No newline at end of file diff --git a/energymanager/energy_projects/migrations/0002_auto__add_energyproject.py b/energymanager/energy_projects/migrations/0002_auto__add_energyproject.py new file mode 100644 index 0000000..0d8eeb8 --- /dev/null +++ b/energymanager/energy_projects/migrations/0002_auto__add_energyproject.py @@ -0,0 +1,289 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'EnergyProject' + db.create_table(u'energy_projects_energyproject', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('encryption_data_initialization_vector', self.gf('gridplatform.encryption.fields.Base64Field')()), + ('customer', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['customers.Customer'])), + ('name', self.gf('gridplatform.encryption.fields.EncryptedCharField')(max_length=50)), + ('baseline_from_date', self.gf('django.db.models.fields.DateField')()), + ('baseline_to_date', self.gf('django.db.models.fields.DateField')()), + ('time_datasource', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name=u'energyproject_time_set', null=True, to=orm['consumptions.Consumption'])), + ('datasource', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name=u'energyproject_set', null=True, to=orm['consumptions.Consumption'])), + ('result_from_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + ('result_to_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + )) + db.send_create_signal(u'energy_projects', ['EnergyProject']) + + + def backwards(self, orm): + # Deleting model 'EnergyProject' + db.delete_table(u'energy_projects_energyproject') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'consumptions.consumption': { + 'Meta': {'object_name': 'Consumption'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '200'}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}), + 'unit': ('gridplatform.utils.fields.BuckinghamField', [], {'max_length': '100'}), + 'volumetoenergyconversion': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['datasequences.EnergyPerVolumeDataSequence']", 'null': 'True', 'blank': 'True'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'customers.collection': { + 'Meta': {'object_name': 'Collection'}, + 'billing_installation_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), + 'billing_meter_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), + 'comment': ('gridplatform.encryption.fields.EncryptedTextField', [], {'blank': 'True'}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']", 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'gauge_colours': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'gauge_lower_threshold': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'gauge_max': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'gauge_min': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'gauge_preferred_unit': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'gauge_upper_threshold': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'hidden_on_details_page': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'hidden_on_reports_page': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('imagekit.models.fields.ProcessedImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'to': u"orm['customers.Collection']"}), + 'relay': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['devices.Meter']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'role': ('django.db.models.fields.IntegerField', [], {}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'utility_type': ('django.db.models.fields.IntegerField', [], {}) + }, + u'customers.customer': { + 'Meta': {'ordering': "[u'id']", 'object_name': 'Customer'}, + 'address': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'city': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '30', 'blank': 'True'}), + 'contact_email': ('gridplatform.encryption.fields.EncryptedEmailField', [], {'max_length': '50', 'blank': 'True'}), + 'contact_name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'contact_phone': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'country_code': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '3', 'blank': 'True'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'null': 'True', 'to': u"orm['users.User']"}), + 'currency_unit': ('gridplatform.utils.fields.BuckinghamField', [], {'default': "u'currency_dkk'", 'max_length': '100'}), + 'electricity_consumption': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt*hour'", 'max_length': '50'}), + 'electricity_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt'", 'max_length': '50'}), + 'electricity_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'electricity_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'gas_consumption': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter'", 'max_length': '50'}), + 'gas_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter*hour^-1'", 'max_length': '50'}), + 'gas_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'gas_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'heat_consumption': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt*hour'", 'max_length': '50'}), + 'heat_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt'", 'max_length': '50'}), + 'heat_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'heat_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'id': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'oil_consumption': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter'", 'max_length': '50'}), + 'oil_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter*hour^-1'", 'max_length': '50'}), + 'oil_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'oil_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'phone': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'postal_code': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '10', 'blank': 'True'}), + 'production_a_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_b_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_c_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_d_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_e_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'provider': ('django.db.models.fields.related.ForeignKey', [], {'default': '1', 'to': u"orm['providers.Provider']"}), + 'temperature': ('django.db.models.fields.CharField', [], {'default': "u'celsius'", 'max_length': '50'}), + 'timezone': ('timezones2.models.TimeZoneField', [], {'max_length': '64'}), + 'vat': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '20', 'blank': 'True'}), + 'water_consumption': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter'", 'max_length': '50'}), + 'water_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter*hour^-1'", 'max_length': '50'}), + 'water_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'water_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}) + }, + u'customers.location': { + 'Meta': {'object_name': 'Location'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']", 'blank': 'True'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['customers.Location']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + u'datasequences.energypervolumedatasequence': { + 'Meta': {'object_name': 'EnergyPerVolumeDataSequence'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '200'}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}) + }, + u'devices.agent': { + 'Meta': {'ordering': "[u'location', u'mac']", 'object_name': 'Agent'}, + 'add_mode': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Customer']", 'on_delete': 'models.PROTECT'}), + 'device_serial': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'device_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'hw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Location']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'mac': ('gridplatform.utils.fields.MacAddressField', [], {'unique': 'True'}), + 'no_longer_in_use': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'online': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'online_since': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'sw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}) + }, + u'devices.meter': { + 'Meta': {'ordering': "[u'connection_type', u'manufactoring_id', u'id']", 'object_name': 'Meter'}, + 'agent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['devices.Agent']", 'on_delete': 'models.PROTECT'}), + 'connection_type': ('django.db.models.fields.IntegerField', [], {}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Customer']", 'on_delete': 'models.PROTECT'}), + 'device_serial': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'device_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'hw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'joined': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Location']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'manual_mode': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'manufactoring_id': ('django.db.models.fields.BigIntegerField', [], {}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'online': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'online_since': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'relay_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'relay_on': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'sw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}) + }, + u'energy_projects.energyproject': { + 'Meta': {'object_name': 'EnergyProject'}, + 'baseline_from_date': ('django.db.models.fields.DateField', [], {}), + 'baseline_to_date': ('django.db.models.fields.DateField', [], {}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']"}), + 'datasource': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'energyproject_set'", 'null': 'True', 'to': u"orm['consumptions.Consumption']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'result_from_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'result_to_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'time_datasource': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'energyproject_time_set'", 'null': 'True', 'to': u"orm['consumptions.Consumption']"}) + }, + u'energy_projects.ledlightproject': { + 'Meta': {'object_name': 'LedLightProject'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']"}), + 'datasource': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['consumptions.Consumption']", 'null': 'True', 'blank': 'True'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'led_consumption_per_tube': ('django.db.models.fields.IntegerField', [], {}), + 'led_tube_count': ('django.db.models.fields.IntegerField', [], {}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'previous_consumption_per_tube': ('django.db.models.fields.IntegerField', [], {}), + 'previous_tube_count': ('django.db.models.fields.IntegerField', [], {}), + 'price': ('django.db.models.fields.FloatField', [], {}) + }, + u'measurementpoints.dataseries': { + 'Meta': {'ordering': "[u'role', u'id']", 'object_name': 'DataSeries'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'graph': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['measurementpoints.Graph']", 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'role': ('legacy.measurementpoints.fields.DataRoleField', [], {}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}), + 'unit': ('gridplatform.utils.fields.BuckinghamField', [], {'max_length': '100', 'blank': 'True'}), + 'utility_type': ('django.db.models.fields.IntegerField', [], {}) + }, + u'measurementpoints.graph': { + 'Meta': {'ordering': "[u'role', u'id']", 'unique_together': "((u'collection', u'role'),)", 'object_name': 'Graph'}, + 'collection': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Collection']"}), + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'role': ('legacy.measurementpoints.fields.DataRoleField', [], {}) + }, + u'providers.provider': { + 'Meta': {'object_name': 'Provider'}, + 'address': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}), + 'city': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}), + 'cvr': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'zipcode': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}) + }, + u'users.user': { + 'Meta': {'ordering': "[u'user_type', u'name', u'id']", 'object_name': 'User', '_ormbases': [u'auth.User']}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Customer']", 'null': 'True', 'blank': 'True'}), + 'e_mail': ('gridplatform.encryption.fields.EncryptedEmailField', [], {'max_length': '75'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'encryption_key_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'encryption_private_key': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'encryption_public_key': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'mobile': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '20', 'blank': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '60'}), + 'phone': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '20'}), + 'provider': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['providers.Provider']", 'null': 'True', 'blank': 'True'}), + u'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}), + 'user_type': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['energy_projects'] \ No newline at end of file diff --git a/energymanager/energy_projects/migrations/__init__.py b/energymanager/energy_projects/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/energy_projects/models.py b/energymanager/energy_projects/models.py new file mode 100644 index 0000000..4d620bc --- /dev/null +++ b/energymanager/energy_projects/models.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +import datetime +import pytz + +from django.core.exceptions import ValidationError +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from gridplatform.customers.mixins import EncryptionCustomerFieldMixin +from gridplatform.encryption.fields import EncryptedCharField +from gridplatform.encryption.models import EncryptedModel +from gridplatform.trackuser.managers import CustomerBoundManager +from gridplatform.consumptions.models import Consumption +from gridplatform.utils import DATETIME_MIN, PhysicalQuantity + +PHASE_ONE = 1 +PHASE_TWO = 2 +PHASE_TREE = 3 + +ENERGY_PROJECT_PHASES = { + PHASE_ONE: _('Phase 1'), + PHASE_TWO: _('Phase 2'), + PHASE_TREE: _('Phase 3'), +} + + +class EnergyProject(EncryptionCustomerFieldMixin, EncryptedModel): + name = EncryptedCharField(_('name'), max_length=50) + + baseline_from_date = models.DateField(_('Baseline start date')) + baseline_to_date = models.DateField(_('Baseline end date')) + + time_datasource = models.ForeignKey( + Consumption, + verbose_name=_('time datasource'), + null=True, blank=True, + related_name='energyproject_time_set' + ) + + datasource = models.ForeignKey( + Consumption, + verbose_name=_('datasource'), + null=True, blank=True, + related_name='energyproject_set' + ) + + result_from_date = models.DateField(_('Result start date'), blank=True, null=True) + result_to_date = models.DateField(_('Result end date'), blank=True, null=True) + + objects = CustomerBoundManager() + + class Meta: + verbose_name = _('Energy project') + verbose_name_plural = _('Energy projects') + + def __unicode__(self): + return unicode(self.name_plain) + + def clean(self): + """ + :raise ValidationError: If baseline timestamp range is empty. + """ + super(EnergyProject, self).clean() + if self.baseline_from_date and self.baseline_to_date and \ + self.baseline_from_date > self.baseline_to_date: + raise ValidationError(_('Baseline period must be non-empty.')) + + if self.datasource_id and not PhysicalQuantity.compatible_units( + self.datasource.unit, 'joule'): + raise ValidationError(_('Datasource must be an energy datasource')) + + if self.time_datasource_id and not PhysicalQuantity.compatible_units( + self.time_datasource.unit, 'second'): + raise ValidationError(_('Datasource must be a time datasource')) + + def project_phase(self): + now = datetime.date.today() + if now <= self.baseline_to_date: + return PHASE_ONE + elif now > self.baseline_to_date and now < self.result_from_date: + return PHASE_TWO + else: + return PHASE_TREE + + def baseline_timestamps(self): + return ( + datetime.datetime.combine( + self.baseline_from_date, + datetime.time(0, 0).replace(tzinfo=self.customer.timezone)), + datetime.datetime.combine( + self.baseline_to_date, + datetime.time(23, 0).replace(tzinfo=self.customer.timezone)) + ) + + def total_baseline_consumption(self): + if not self.datasource: + return None + + timestamps = self.baseline_timestamps() + return self.datasource.energy_sum(timestamps[0], timestamps[1]).convert('kilowatt*hour') + + def total_baseline_time_consumption(self): + if not self.time_datasource: + return None + + timestamps = self.baseline_timestamps() + return self.time_datasource.energy_sum(timestamps[0], timestamps[1]).convert('hour') + + +class LedLightProject( + EncryptionCustomerFieldMixin, EncryptedModel): + name = EncryptedCharField(_('name'), max_length=50) + previous_tube_count = models.IntegerField(_('previous tube count')) + previous_consumption_per_tube = models.IntegerField( + _('previous consumption per tube in W/h')) + + led_tube_count = models.IntegerField(_('LED tube count')) + led_consumption_per_tube = models.IntegerField( + _('consumption per LED tube in W/h')) + + price = models.FloatField(_('price per kw/h')) + + datasource = models.ForeignKey( + Consumption, + verbose_name=_('datasource'), + null=True, blank=True) + + objects = CustomerBoundManager() + + class Meta: + verbose_name = _('LED light project') + verbose_name_plural = _('LED light projects') + + def __unicode__(self): + return unicode(self.name_plain) + + def calculate_previous_consumption(self): + return self.previous_tube_count * self.previous_consumption_per_tube + + def measured_consumption(self, from_timestamp, to_timestamp): + if not from_timestamp: + from_timestamp = DATETIME_MIN + if not to_timestamp: + to_timestamp = datetime.datetime( + 9998, 12, 30, 23, 0, 0).replace(tzinfo=pytz.utc) + + return self.datasource.energy_sum(from_timestamp, to_timestamp) + + def calculate_previous_price_per_hour(self): + return self.calculate_previous_consumption() / 1000.0 * self.price + + def calculate_savings(self, from_time=None, to_time=None): + ''' + Returns the savings + ''' + if not self.datasource: + return None + + return self.calculated_previous_price( + from_time, to_time) - self.measured_price( + from_time, to_time) + + def calculate_burn_hours(self, from_time=None, to_time=None): + if self.datasource: + consumption = self.measured_consumption( + from_time, to_time).convert('watt*hour') + + calculated_consumption = self.led_tube_count \ + * self.led_consumption_per_tube + return consumption / calculated_consumption + else: + return None + + def calculated_previous_price( + self, from_time=None, to_time=None): + if self.datasource: + return self.calculate_burn_hours( + from_time, to_time) * self.calculate_previous_price_per_hour() + else: + return None + + def measured_price(self, from_time=None, to_time=None): + if self.datasource: + + return self.measured_consumption( + from_time, to_time).convert('kilowatt*hour') * self.price + else: + return None diff --git a/energymanager/energy_projects/tests.py b/energymanager/energy_projects/tests.py new file mode 100644 index 0000000..f294b21 --- /dev/null +++ b/energymanager/energy_projects/tests.py @@ -0,0 +1,180 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +import datetime +import pytz + +from django.test import TestCase +from django.test.utils import override_settings + +from gridplatform.customers.models import Customer +from gridplatform.providers.models import Provider +from gridplatform.trackuser import replace_customer +from gridplatform.trackuser import replace_user +from gridplatform.users.models import User +from gridplatform.customer_datasources.models import CustomerDataSource +from gridplatform.datasources.models import RawData + +from .models import LedLightProject + + +@override_settings(ENCRYPTION_TESTMODE=True) +class LedLightProjectTest(TestCase): + def setUp(self): + self.provider = Provider.objects.create() + self.user = User(provider=self.provider) + self.customer = Customer(provider=self.provider) + self.customer.save() + + def test_save_and_load(self): + with replace_user(self.user), replace_customer(self.customer): + project = LedLightProject.objects.create( + name_plain='Office', + previous_tube_count=32, + previous_consumption_per_tube=45, + led_tube_count=30, + led_consumption_per_tube=20, + price=2.4 + ) + + loaded_project = LedLightProject.objects.get( + id=project.id) + + self.assertEqual( + project.name_plain, + loaded_project.name_plain) + + def test_measured_price_without_datasource(self): + with replace_user(self.user), replace_customer(self.customer): + project = LedLightProject.objects.create( + name_plain='Office', + previous_tube_count=32, + previous_consumption_per_tube=45, + led_tube_count=30, + led_consumption_per_tube=20, + price=2.4 + ) + + self.assertEqual( + project.measured_price(), + None) + + def test_measured_price_with_datasource_without_data(self): + with replace_user(self.user), replace_customer(self.customer): + data_source = CustomerDataSource.objects.create( + name_plain='test name', + unit='watt*hour') + + project = LedLightProject.objects.create( + name_plain='Office', + previous_tube_count=32, + previous_consumption_per_tube=45, + led_tube_count=30, + led_consumption_per_tube=20, + price=2.4, + datasource=data_source + ) + + self.assertEqual( + project.measured_price(), + 0) + + def test_measured_price(self): + with replace_user(self.user), replace_customer(self.customer): + data_source = CustomerDataSource.objects.create( + name_plain='test name', + unit='watt') + + project = LedLightProject.objects.create( + name_plain='Office', + previous_tube_count=32, + previous_consumption_per_tube=45, + led_tube_count=30, + led_consumption_per_tube=20, + price=2.4, + datasource=data_source + ) + + timestamp = datetime.datetime( + 2015, 6, 2, 10, 0, 0, tzinfo=pytz.timezone('UTC')) + startvalue = 0 + for x in xrange(1, 120): + RawData.objects.create( + datasource=data_source, + value=10, + unit='milwatt*', + timestamp=timestamp + ) + startvalue += 10 + timestamp += datetime.timedelta(minutes=1) + + self.assertEqual( + project.measured_price(), + 1.44) + + def test_calculated_previous_price(self): + with replace_user(self.user), replace_customer(self.customer): + data_source = CustomerDataSource.objects.create( + name_plain='test name', + unit='watt*hour') + + project = LedLightProject.objects.create( + name_plain='Office', + previous_tube_count=32, + previous_consumption_per_tube=45, + led_tube_count=30, + led_consumption_per_tube=20, + price=2.4, + datasource=data_source + ) + + timestamp = datetime.datetime( + 2015, 6, 2, 10, 0, 0, tzinfo=pytz.timezone('UTC')) + startvalue = 0 + for x in xrange(1, 120): + RawData.objects.create( + datasource=data_source, + value=startvalue, + unit='milwatt*hour', + timestamp=timestamp + ) + startvalue += 10 + timestamp += datetime.timedelta(minutes=1) + + self.assertEqual( + project.calculated_previous_price(), + 3.456) + + def test_calculate_savings(self): + with replace_user(self.user), replace_customer(self.customer): + data_source = CustomerDataSource.objects.create( + name_plain='test name', + unit='watt*hour') + + project = LedLightProject.objects.create( + name_plain='Office', + previous_tube_count=32, + previous_consumption_per_tube=45, + led_tube_count=30, + led_consumption_per_tube=20, + price=2.4, + datasource=data_source + ) + + timestamp = datetime.datetime( + 2015, 6, 2, 10, 0, 0, tzinfo=pytz.timezone('UTC')) + startvalue = 0 + for x in xrange(1, 120): + RawData.objects.create( + datasource=data_source, + value=startvalue, + unit='milwatt*hour', + timestamp=timestamp + ) + startvalue += 10 + timestamp += datetime.timedelta(minutes=1) + + self.assertEqual( + project.calculate_savings(), + 2.016) diff --git a/energymanager/energy_projects/views.py b/energymanager/energy_projects/views.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/led_light_site/__init__.py b/energymanager/led_light_site/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/led_light_site/models.py b/energymanager/led_light_site/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/energymanager/led_light_site/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/energymanager/led_light_site/restricted_urls.py b/energymanager/led_light_site/restricted_urls.py new file mode 100644 index 0000000..51fa0b7 --- /dev/null +++ b/energymanager/led_light_site/restricted_urls.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.conf.urls import patterns +from django.conf.urls import url + +from . import views + +urlpatterns = patterns( + 'energymanager.led_light_view.views', + url(r'^project/(?P\d+)/$', + views.LedLightProjectList.as_view(), + name='led-light-project-list'), + url(r'^project/content/(?P\d+)/$', + views.LedLightProjectListContentView.as_view(), + name='led-light-project-list-content'), + url(r'^project/create/(?P\d+)/$', + views.LedLightProjectCreateView.as_view(), + name='led-light-project-create'), + url(r'^project/update/(?P\d+)/(?P\d+)/$', + views.LedLightProjectUpdateView.as_view(), + name='led-light-project-update'), + url(r'^project/delete/(?P\d+)/(?P\d+)/$', + views.LedLightProjectDeleteView.as_view(), + name='led-light-project-delete'), + url(r'^(?P\d+)/dashboard_burn/$', + views.DashboardBurnDetailView.as_view(), + name='dashboard_burn'), +) diff --git a/energymanager/led_light_site/templates/led_light_site/_led_light_project_list_content.html b/energymanager/led_light_site/templates/led_light_site/_led_light_project_list_content.html new file mode 100644 index 0000000..2c275a9 --- /dev/null +++ b/energymanager/led_light_site/templates/led_light_site/_led_light_project_list_content.html @@ -0,0 +1,21 @@ +{% load i18n %} + +{% if object_list %} + + + + + + {% for object in object_list %} + + + + {% endfor %} + +
{% trans "Name" %}
+ {{ object.name_plain }} +
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No LED light projects present." %} +{% endif %} diff --git a/energymanager/led_light_site/templates/led_light_site/_menu.html b/energymanager/led_light_site/templates/led_light_site/_menu.html new file mode 100644 index 0000000..ffc9e31 --- /dev/null +++ b/energymanager/led_light_site/templates/led_light_site/_menu.html @@ -0,0 +1,26 @@ +{% load i18n %} + +{% load bootstrap_tags %} + +{% if customer %} + +{% endif %} diff --git a/energymanager/led_light_site/templates/led_light_site/_navbar.html b/energymanager/led_light_site/templates/led_light_site/_navbar.html new file mode 100644 index 0000000..1e087ff --- /dev/null +++ b/energymanager/led_light_site/templates/led_light_site/_navbar.html @@ -0,0 +1,11 @@ +{% extends "bootstrap/_navbar_base.html" %} + +{% load i18n %} +{% load bootstrap_tags %} + +{% block home_url %}{% url 'led_light_site:home' %}{% endblock home_url %} +{% block title %}{% trans 'LED Light' %}{% endblock title %} + +{% block menu_extra %} +{% include "utils/customer_selection_nav.html" %} +{% endblock menu_extra %} diff --git a/energymanager/led_light_site/templates/led_light_site/base.html b/energymanager/led_light_site/templates/led_light_site/base.html new file mode 100644 index 0000000..803831c --- /dev/null +++ b/energymanager/led_light_site/templates/led_light_site/base.html @@ -0,0 +1,18 @@ +{% extends "bootstrap/base.html" %} + +{% load i18n %} + +{% block page_title %}{% trans 'LED Light' %}{% endblock %} + +{% block navbar %} +{% include "led_light_site/_navbar.html" %} +{% endblock %} + +{% block sidebar %} +{% include "led_light_site/_menu.html" %} +{% endblock %} + + +{% block page_bottom %} +{% include "utils/customer_selection_modal.html" with urlname='led_light_site:customer' %} +{% endblock page_bottom %} diff --git a/energymanager/led_light_site/templates/led_light_site/choose_customer.html b/energymanager/led_light_site/templates/led_light_site/choose_customer.html new file mode 100644 index 0000000..bd5ca9c --- /dev/null +++ b/energymanager/led_light_site/templates/led_light_site/choose_customer.html @@ -0,0 +1,9 @@ +{% extends "led_light_site/base.html" %} + +{% block page_js %} + +{% endblock page_js %} diff --git a/energymanager/led_light_site/templates/led_light_site/dashboard.html b/energymanager/led_light_site/templates/led_light_site/dashboard.html new file mode 100644 index 0000000..4d5367e --- /dev/null +++ b/energymanager/led_light_site/templates/led_light_site/dashboard.html @@ -0,0 +1,108 @@ +{% extends "led_light_site/base.html" %} +{% load i18n %} +{% load l10n %} + +{% load bootstrap_tags %} +{% load utils %} + +{% block content %} +
+{% panel _("Total") %} +{% comment %} + +{% endcomment %} + + +{% endpanelbuttons %} +

+
+ {% trans 'Saved' %} +
+
+ {% if total_saved %} + {{ total_saved|floatformat:2 }} + {% else %} + - + {% endif %} DKK +
+

+
+
    +
  • + {{ total_previous_price|floatformat:2 }} kr +
    {% trans 'Price with previous tubes' %}
    +
  • +
  • + {{ total_led_price|floatformat:2 }} kr +
    {% trans 'Price with LED tubes' %}
    +
  • +
+{% endpanel %} + +
+ {% for project in projects %} + +
+
+
+
+ {{ project.name }} +
+
+ {% trans 'Saved' %} + {{ project.saved|floatformat:2 }} DKK +
+
+
+
+
{{ project.previous_price|floatformat:2 }} DKK {% trans 'Previous Price' %}
+
+
+
{{ project.led_price|floatformat:2 }} DKK {% trans 'LED Price' %}
+
+
+
+
+ {% endfor %} +
+
+{% endblock %} diff --git a/energymanager/led_light_site/templates/led_light_site/dashboard_burn.html b/energymanager/led_light_site/templates/led_light_site/dashboard_burn.html new file mode 100644 index 0000000..3163aad --- /dev/null +++ b/energymanager/led_light_site/templates/led_light_site/dashboard_burn.html @@ -0,0 +1,77 @@ +{% extends "led_light_site/base.html" %} +{% load i18n %} +{% load l10n %} + +{% load bootstrap_tags %} +{% load utils %} + +{% block content %} +
+{% panel _("Total") %} + + + +{% endpanelbuttons %} +

+
+ {% trans 'Burned' %} +
+
+ {% if total_burned %} + {{ total_burned|floatformat:2 }} + {% else %} + - + {% endif %} {% trans 'Hours' %} +
+

+
+{% endpanel %} + +
+ {% for project in projects %} + +
+
+
+
+ {{ project.name }} +
+
+ {% trans 'Burned' %} + {{ project.burned|floatformat:2 }} {% trans 'Hours' %} +
+
+
+
+ {% endfor %} +
+
+{% endblock %} diff --git a/energymanager/led_light_site/templates/led_light_site/led_light_project_form.html b/energymanager/led_light_site/templates/led_light_site/led_light_project_form.html new file mode 100644 index 0000000..bbab71e --- /dev/null +++ b/energymanager/led_light_site/templates/led_light_site/led_light_project_form.html @@ -0,0 +1,12 @@ +{% extends "led_light_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("LED Light Project Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/led_light_site/templates/led_light_site/led_light_project_list.html b/energymanager/led_light_site/templates/led_light_site/led_light_project_list.html new file mode 100644 index 0000000..ad47059 --- /dev/null +++ b/energymanager/led_light_site/templates/led_light_site/led_light_project_list.html @@ -0,0 +1,15 @@ +{% extends "led_light_site/base.html" %} +{% load i18n %} +{% load pagination %} +{% load bootstrap_tags %} + +{% block content %} +{% panel _("LED Light Projects") search=True %} + + {% icon "plus" %} + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/led_light_site/tests.py b/energymanager/led_light_site/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/energymanager/led_light_site/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/energymanager/led_light_site/urls.py b/energymanager/led_light_site/urls.py new file mode 100644 index 0000000..530e4f5 --- /dev/null +++ b/energymanager/led_light_site/urls.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.conf.urls import patterns +from django.conf.urls import url +from django.conf.urls import include + +from gridplatform.utils.urls import restricted_url + +from . import views + +urlpatterns = patterns( + 'energymanager.led_light_view.views', + url(r'^$', + views.HomeView.as_view(), + name='home'), + url(r'^customer/(?P\d+)/$', + views.CustomerView.as_view(), + name='customer'), + url(r'^choose-customer/$', + views.ChooseCustomer.as_view(), + name='choose-customer'), + url(r'^(?P\d+)/dashboard/$', + views.DashboardDetailView.as_view(), + name='dashboard'), +) diff --git a/energymanager/led_light_site/views.py b/energymanager/led_light_site/views.py new file mode 100644 index 0000000..ce9ddcc --- /dev/null +++ b/energymanager/led_light_site/views.py @@ -0,0 +1,341 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +import datetime +import calendar + +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext_lazy +from django import forms +from django.core.urlresolvers import reverse +from django.db.models.fields import BLANK_CHOICE_DASH + +from gridplatform.utils import generic_views +from gridplatform.utils import units +from gridplatform.utils.breadcrumbs import Breadcrumb +from gridplatform.utils.breadcrumbs import Breadcrumbs +from gridplatform.utils.views import ChooseCustomerBase +from gridplatform.utils.views import CustomerInKwargsMixin +from gridplatform.utils.views import CustomerListMixin +from gridplatform.utils.views import CustomerViewBase +from gridplatform.utils.views import HomeViewBase +from gridplatform.customers.models import Customer +from gridplatform.utils.forms import YearWeekPeriodForm +from gridplatform.utils.forms import this_week_initial_values + + +from energymanager.energy_projects.models import LedLightProject + + +class HomeView(HomeViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'led_light_site:dashboard', + kwargs={'customer_id': customer_id}) + + def get_choose_customer_url(self): + return reverse( + 'led_light_site:choose-customer') + + +class ChooseCustomer(ChooseCustomerBase): + template_name = 'led_light_site/choose_customer.html' + + +class CustomerView(CustomerViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'led_light_site:dashboard', + kwargs={'customer_id': customer_id}) + + +class DashboardDetailView( + CustomerListMixin, generic_views.DetailView): + model = Customer + template_name = \ + 'led_light_site/dashboard.html' + + def get_breadcrumbs(self): + return ( + (_('Dashboard'), ''), + ) + + def get_object(self, queryset=None): + return self.model.objects.get(pk=self.kwargs['customer_id']) + + def get_context_data(self, **kwargs): + context = super(DashboardDetailView, self).get_context_data(**kwargs) + + projects = self.object.ledlightproject_set.all() + projects_width_savings = [] + + total_saved = None + total_previous_price = None + total_led_price = None + + year = int(self.request.GET.get( + 'year', datetime.datetime.today().year)) + month_number = int(self.request.GET.get( + 'month_number', datetime.datetime.today().month)) + + from_time = None + to_time = None + + month_options = ( + '...', + _('January'), + _('February'), + _('March'), + _('April'), + _('May'), + _('June'), + _('Juli'), + _('August'), + _('September'), + _('October'), + _('November'), + _('December'), + ) + + if month_number == 0: + from_time = datetime.datetime(year, 1, 1, 0, 0, 0).replace(tzinfo=self.object.timezone) + to_time = datetime.datetime(year + 1, 1, 1, 0, 0, 0).replace(tzinfo=self.object.timezone) + else: + from_time = datetime.datetime(year, month_number, 1, 0, 0, 0).replace(tzinfo=self.object.timezone) + to_time = datetime.datetime( + year, month_number, calendar.monthrange( + year, month_number)[1], 23, 59, 59).replace(tzinfo=self.object.timezone) + datetime.timedelta( + seconds=1) + + for project in projects: + previous_price = project.calculated_previous_price( + from_time=from_time, to_time=to_time) + + led_price = project.measured_price( + from_time=from_time, to_time=to_time) + + saved = project.calculate_savings( + from_time=from_time, to_time=to_time) + if saved: + if total_saved: + total_saved += saved + total_previous_price += previous_price + total_led_price += led_price + else: + total_previous_price = previous_price + total_led_price = led_price + total_saved = saved + + projects_width_savings.append({ + 'name': project.name_plain, + 'saved': saved, + 'previous_price': previous_price, + 'led_price': led_price + }) + else: + projects_width_savings.append({ + 'name': project.name_plain, + 'saved': '-', + 'previous_price': '-', + 'led_price': '-' + }) + + context['year'] = year + context['month_number'] = month_number + context['month'] = month_options[month_number] + context['total_saved'] = total_saved + context['total_previous_price'] = total_previous_price + context['total_led_price'] = total_led_price + context['projects'] = projects_width_savings + context['chart_form'] = YearWeekPeriodForm( + this_week_initial_values()) + return context + + +class DashboardBurnDetailView( + CustomerListMixin, generic_views.DetailView): + model = Customer + template_name = \ + 'led_light_site/dashboard_burn.html' + + def get_breadcrumbs(self): + return ( + (_('Dashboard Burn Hours'), ''), + ) + + def get_object(self, queryset=None): + return self.model.objects.get(pk=self.kwargs['customer_id']) + + def get_context_data(self, **kwargs): + context = super( + DashboardBurnDetailView, self).get_context_data(**kwargs) + + projects = self.object.ledlightproject_set.all() + projects_width_savings = [] + + total_burned = None + + year = int(self.request.GET.get( + 'year', datetime.datetime.today().year)) + month_number = int(self.request.GET.get( + 'month_number', datetime.datetime.today().month)) + + from_time = None + to_time = None + + month_options = ( + '...', + _('January'), + _('February'), + _('March'), + _('April'), + _('May'), + _('June'), + _('Juli'), + _('August'), + _('September'), + _('October'), + _('November'), + _('December'), + ) + + if month_number == 0: + from_time = datetime.datetime(year, 1, 1, 0, 0, 0).replace( + tzinfo=self.object.timezone) + to_time = datetime.datetime(year + 1, 1, 1, 0, 0, 0).replace( + tzinfo=self.object.timezone) + else: + from_time = datetime.datetime( + year, month_number, 1, 0, 0, 0).replace( + tzinfo=self.object.timezone) + to_time = datetime.datetime( + year, month_number, calendar.monthrange( + year, month_number)[1], 23, 59, 59).replace( + tzinfo=self.object.timezone) + datetime.timedelta( + seconds=1) + + for project in projects: + burned = project.calculate_burn_hours( + from_time=from_time, to_time=to_time) + + if burned: + if total_burned: + total_burned += burned + else: + total_burned = burned + + projects_width_savings.append({ + 'name': project.name_plain, + 'burned': burned, + }) + else: + projects_width_savings.append({ + 'name': project.name_plain, + 'burned': '-', + }) + + context['year'] = year + context['month_number'] = month_number + context['month'] = month_options[month_number] + context['total_burned'] = total_burned + context['projects'] = projects_width_savings + return context + + +class LedLightProjectList(CustomerListMixin, generic_views.TemplateView): + template_name = 'led_light_site/led_light_project_list.html' + + @staticmethod + def build_breadcrumbs(customer_id): + return Breadcrumbs() + Breadcrumb( + _('Led Light Projects'), + reverse( + 'led_light_site_projects:led-light-project-list', + kwargs={'customer_id': customer_id})) + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id) + + +class LedLightProjectListContentView( + CustomerListMixin, + generic_views.ListView): + search_fields = ['name_plain', ] + sort_fields = ['name_plain', ] + model = LedLightProject + paginate_by = 100 + template_name = 'led_light_site/_led_light_project_list_content.html' + + +class LedLightProjectForm(forms.ModelForm): + + class Meta: + model = LedLightProject + fields = ( + 'name', 'previous_tube_count', 'previous_consumption_per_tube', + 'led_tube_count', 'led_consumption_per_tube', 'price', + 'datasource', + ) + + +class LedLightProjectCreateView(CustomerListMixin, + generic_views.CreateView): + model = LedLightProject + template_name = 'led_light_site/led_light_project_form.html' + form_class = LedLightProjectForm + + def form_valid(self, form): + form.instance.customer_id = self._customer.id + result = super(LedLightProjectCreateView, self).form_valid(form) + assert self.object.id + self._customer.ledlightproject_set.add(self.object) + return result + + def get_success_url(self): + return reverse('led_light_site_projects:led-light-project-list', + kwargs={'customer_id': + self._customer.id}) + + def get_cancel_url(self): + return self.get_success_url() + + def get_breadcrumbs(self): + return LedLightProjectList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Create LED Light Project')) + + +class LedLightProjectUpdateView(CustomerListMixin, + generic_views.UpdateView): + model = LedLightProject + template_name = 'led_light_site/led_light_project_form.html' + form_class = LedLightProjectForm + + def get_success_url(self): + return reverse('led_light_site_projects:led-light-project-list', + kwargs={'customer_id': + self._customer.id}) + + def get_cancel_url(self): + return self.get_success_url() + + def get_delete_url(self): + return reverse('led_light_site_projects:led-light-project-delete', + kwargs={'customer_id': + self._customer.id, + 'pk': + self.object.id}) + + def get_breadcrumbs(self): + return LedLightProjectList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(self.object) + + +class LedLightProjectDeleteView( + CustomerListMixin, generic_views.DeleteView): + model = LedLightProject + + def get_success_url(self): + return reverse('led_light_site_projects:led-light-project-list', + kwargs={'customer_id': + self._customer.id}) diff --git a/energymanager/price_relay_site/__init__.py b/energymanager/price_relay_site/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/price_relay_site/migrations/0001_initial.py b/energymanager/price_relay_site/migrations/0001_initial.py new file mode 100644 index 0000000..c8c1f6a --- /dev/null +++ b/energymanager/price_relay_site/migrations/0001_initial.py @@ -0,0 +1,278 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'PriceRelayProject' + db.create_table(u'price_relay_site_pricerelayproject', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('encryption_data_initialization_vector', self.gf('gridplatform.encryption.fields.Base64Field')()), + ('customer', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['customers.Customer'])), + ('name', self.gf('gridplatform.encryption.fields.EncryptedCharField')(max_length=50)), + ('look_ahead', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('relay_one_on_at', self.gf('django.db.models.fields.FloatField')()), + ('relay_two_on_at', self.gf('django.db.models.fields.FloatField')()), + ('relay_tree_on_at', self.gf('django.db.models.fields.FloatField')()), + ('relay_four_on_at', self.gf('django.db.models.fields.FloatField')()), + ('relay_five_on_at', self.gf('django.db.models.fields.FloatField')()), + ('relay_six_on_at', self.gf('django.db.models.fields.FloatField')()), + ('relay_seven_on_at', self.gf('django.db.models.fields.FloatField')()), + ('relay_eight_on_at', self.gf('django.db.models.fields.FloatField')()), + ('tariff', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['tariffs.EnergyTariff'])), + )) + db.send_create_signal(u'price_relay_site', ['PriceRelayProject']) + + + def backwards(self, orm): + # Deleting model 'PriceRelayProject' + db.delete_table(u'price_relay_site_pricerelayproject') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'customers.collection': { + 'Meta': {'object_name': 'Collection'}, + 'billing_installation_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), + 'billing_meter_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), + 'comment': ('gridplatform.encryption.fields.EncryptedTextField', [], {'blank': 'True'}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']", 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'gauge_colours': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'gauge_lower_threshold': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'gauge_max': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'gauge_min': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'gauge_preferred_unit': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'gauge_upper_threshold': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'hidden_on_details_page': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'hidden_on_reports_page': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('imagekit.models.fields.ProcessedImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'to': u"orm['customers.Collection']"}), + 'relay': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['devices.Meter']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'role': ('django.db.models.fields.IntegerField', [], {}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'utility_type': ('django.db.models.fields.IntegerField', [], {}) + }, + u'customers.customer': { + 'Meta': {'ordering': "[u'id']", 'object_name': 'Customer'}, + 'address': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'city': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '30', 'blank': 'True'}), + 'contact_email': ('gridplatform.encryption.fields.EncryptedEmailField', [], {'max_length': '50', 'blank': 'True'}), + 'contact_name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'contact_phone': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'country_code': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '3', 'blank': 'True'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'null': 'True', 'to': u"orm['users.User']"}), + 'currency_unit': ('gridplatform.utils.fields.BuckinghamField', [], {'default': "u'currency_dkk'", 'max_length': '100'}), + 'electricity_consumption': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt*hour'", 'max_length': '50'}), + 'electricity_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt'", 'max_length': '50'}), + 'electricity_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'electricity_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'gas_consumption': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter'", 'max_length': '50'}), + 'gas_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter*hour^-1'", 'max_length': '50'}), + 'gas_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'gas_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'heat_consumption': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt*hour'", 'max_length': '50'}), + 'heat_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'kilowatt'", 'max_length': '50'}), + 'heat_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'heat_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'id': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'oil_consumption': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter'", 'max_length': '50'}), + 'oil_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter*hour^-1'", 'max_length': '50'}), + 'oil_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'oil_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}), + 'phone': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'postal_code': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '10', 'blank': 'True'}), + 'production_a_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_b_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_c_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_d_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'production_e_unit': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'provider': ('django.db.models.fields.related.ForeignKey', [], {'default': '1', 'to': u"orm['providers.Provider']"}), + 'temperature': ('django.db.models.fields.CharField', [], {'default': "u'celsius'", 'max_length': '50'}), + 'timezone': ('timezones2.models.TimeZoneField', [], {'max_length': '64'}), + 'vat': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '20', 'blank': 'True'}), + 'water_consumption': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter'", 'max_length': '50'}), + 'water_instantaneous': ('django.db.models.fields.CharField', [], {'default': "u'meter*meter*meter*hour^-1'", 'max_length': '50'}), + 'water_tariff': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'water_tariff_set'", 'null': 'True', 'to': u"orm['measurementpoints.DataSeries']"}) + }, + u'customers.location': { + 'Meta': {'object_name': 'Location'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']", 'blank': 'True'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['customers.Location']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + u'devices.agent': { + 'Meta': {'ordering': "[u'location', u'mac']", 'object_name': 'Agent'}, + 'add_mode': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Customer']", 'on_delete': 'models.PROTECT'}), + 'device_serial': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'device_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'hw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Location']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'mac': ('gridplatform.utils.fields.MacAddressField', [], {'unique': 'True'}), + 'no_longer_in_use': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'online': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'online_since': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'sw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}) + }, + u'devices.meter': { + 'Meta': {'ordering': "[u'connection_type', u'manufactoring_id', u'id']", 'object_name': 'Meter'}, + 'agent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['devices.Agent']", 'on_delete': 'models.PROTECT'}), + 'connection_type': ('django.db.models.fields.IntegerField', [], {}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Customer']", 'on_delete': 'models.PROTECT'}), + 'device_serial': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'device_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'hw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'hw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'joined': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Location']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'manual_mode': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'manufactoring_id': ('django.db.models.fields.BigIntegerField', [], {}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50', 'blank': 'True'}), + 'online': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'online_since': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'relay_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'relay_on': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'sw_major': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_minor': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_revision': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'sw_subrevision': ('django.db.models.fields.CharField', [], {'max_length': '12'}) + }, + u'measurementpoints.dataseries': { + 'Meta': {'ordering': "[u'role', u'id']", 'object_name': 'DataSeries'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}), + 'graph': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['measurementpoints.Graph']", 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'role': ('legacy.measurementpoints.fields.DataRoleField', [], {}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}), + 'unit': ('gridplatform.utils.fields.BuckinghamField', [], {'max_length': '100', 'blank': 'True'}), + 'utility_type': ('django.db.models.fields.IntegerField', [], {}) + }, + u'measurementpoints.graph': { + 'Meta': {'ordering': "[u'role', u'id']", 'unique_together': "((u'collection', u'role'),)", 'object_name': 'Graph'}, + 'collection': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Collection']"}), + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'role': ('legacy.measurementpoints.fields.DataRoleField', [], {}) + }, + u'price_relay_site.pricerelayproject': { + 'Meta': {'object_name': 'PriceRelayProject'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'look_ahead': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'relay_eight_on_at': ('django.db.models.fields.FloatField', [], {}), + 'relay_five_on_at': ('django.db.models.fields.FloatField', [], {}), + 'relay_four_on_at': ('django.db.models.fields.FloatField', [], {}), + 'relay_one_on_at': ('django.db.models.fields.FloatField', [], {}), + 'relay_seven_on_at': ('django.db.models.fields.FloatField', [], {}), + 'relay_six_on_at': ('django.db.models.fields.FloatField', [], {}), + 'relay_tree_on_at': ('django.db.models.fields.FloatField', [], {}), + 'relay_two_on_at': ('django.db.models.fields.FloatField', [], {}), + 'tariff': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['tariffs.EnergyTariff']"}) + }, + u'providers.provider': { + 'Meta': {'object_name': 'Provider'}, + 'address': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}), + 'city': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}), + 'cvr': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '50'}), + 'zipcode': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '100'}) + }, + u'tariffs.energytariff': { + 'Meta': {'object_name': 'EnergyTariff', '_ormbases': [u'tariffs.Tariff']}, + u'tariff_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['tariffs.Tariff']", 'unique': 'True', 'primary_key': 'True'}) + }, + u'tariffs.tariff': { + 'Meta': {'object_name': 'Tariff'}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['customers.Customer']"}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '200'}), + 'subclass': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.PROTECT', 'to': u"orm['contenttypes.ContentType']"}) + }, + u'users.user': { + 'Meta': {'ordering': "[u'user_type', u'name', u'id']", 'object_name': 'User', '_ormbases': [u'auth.User']}, + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['customers.Customer']", 'null': 'True', 'blank': 'True'}), + 'e_mail': ('gridplatform.encryption.fields.EncryptedEmailField', [], {'max_length': '75'}), + 'encryption_data_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'encryption_key_initialization_vector': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'encryption_private_key': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'encryption_public_key': ('gridplatform.encryption.fields.Base64Field', [], {}), + 'mobile': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '20', 'blank': 'True'}), + 'name': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '60'}), + 'phone': ('gridplatform.encryption.fields.EncryptedCharField', [], {'max_length': '20'}), + 'provider': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['providers.Provider']", 'null': 'True', 'blank': 'True'}), + u'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}), + 'user_type': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['price_relay_site'] \ No newline at end of file diff --git a/energymanager/price_relay_site/migrations/__init__.py b/energymanager/price_relay_site/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/price_relay_site/models.py b/energymanager/price_relay_site/models.py new file mode 100644 index 0000000..6d1de9e --- /dev/null +++ b/energymanager/price_relay_site/models.py @@ -0,0 +1,162 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +import datetime + +import pytz +from django.core.exceptions import ValidationError +from django.db import models +from django.utils.translation import ugettext_lazy as _, ugettext + +from gridplatform.customers.mixins import EncryptionCustomerFieldMixin +from gridplatform.encryption.fields import EncryptedCharField +from gridplatform.encryption.models import EncryptedModel +from gridplatform.tariffs.models import EnergyTariff +from gridplatform.trackuser.managers import CustomerBoundManager +from gridplatform.utils import PhysicalQuantity +from gridplatform.utils.preferredunits import PhysicalUnitConverter + + +class PriceRelayProject( + EncryptionCustomerFieldMixin, EncryptedModel): + name = EncryptedCharField(_('name'), max_length=50) + look_ahead = models.PositiveIntegerField( + _('Look ahead'), help_text=_('in hours')) + relay_one_on_at = models.FloatField( + _('Relay one on at'), help_text=_('kr')) + relay_two_on_at = models.FloatField( + _('Relay two on at'), help_text=_('kr')) + relay_tree_on_at = models.FloatField( + _('Relay tree on at'), help_text=_('kr')) + relay_four_on_at = models.FloatField( + _('Relay four on at'), help_text=_('kr')) + relay_five_on_at = models.FloatField( + _('Relay five on at'), help_text=_('kr')) + relay_six_on_at = models.FloatField( + _('Relay six on at'), help_text=_('kr')) + relay_seven_on_at = models.FloatField( + _('Relay seven on at'), help_text=_('kr')) + relay_eight_on_at = models.FloatField( + _('Relay eight on at'), help_text=_('kr')) + tariff = models.ForeignKey( + EnergyTariff, + verbose_name=_('tariff')) + + objects = CustomerBoundManager() + + class Meta: + verbose_name = _('Price relay project') + verbose_name_plural = _('Price relay projects') + + def __unicode__(self): + return unicode(self.name_plain) + + def clean(self): + """ + :raises ValidationError: if ``self.relay_one_at`` value is gte ``self.relay_two_at`` + :raises ValidationError: if ``self.relay_two_at`` value is gte ``self.relay_tree_at`` + :raises ValidationError: if ``self.relay_tree_at`` value is gte ``self.relay_four_at`` + :raises ValidationError: if ``self.relay_four_at`` value is gte ``self.relay_five_at`` + :raises ValidationError: if ``self.relay_five_at`` value is gte ``self.relay_six_at`` + :raises ValidationError: if ``self.relay_six_at`` value is gte ``self.relay_seven_at`` + :raises ValidationError: if ``self.relay_seven_at`` value is gte ``self.relay_eight_at`` + + """ + super(PriceRelayProject, self).clean() + + if self.relay_one_on_at >= self.relay_two_on_at: + raise ValidationError( + { + 'relay_one_on_at': [ + ugettext( + 'Value must be lesser than Relay two value at')]}) + + if self.relay_two_on_at >= self.relay_tree_on_at: + raise ValidationError( + { + 'relay_two_on_at': [ + ugettext( + 'Value must be lesser than Relay tree value at')]}) + + if self.relay_tree_on_at >= self.relay_four_on_at: + raise ValidationError( + { + 'relay_tree_on_at': [ + ugettext( + 'Value must be lesser than Relay four value at')]}) + + if self.relay_four_on_at >= self.relay_five_on_at: + raise ValidationError( + { + 'relay_four_on_at': [ + ugettext( + 'Value must be lesser than Relay five value at')]}) + + if self.relay_five_on_at >= self.relay_six_on_at: + raise ValidationError( + { + 'relay_five_on_at': [ + ugettext( + 'Value must be lesser than Relay six value at')]}) + + if self.relay_six_on_at >= self.relay_seven_on_at: + raise ValidationError( + { + 'relay_six_on_at': [ + ugettext( + 'Value must be lesser than Relay seven value at')]}) + + if self.relay_seven_on_at >= self.relay_eight_on_at: + raise ValidationError( + { + 'relay_seven_on_at': [ + ugettext( + 'Value must be lesser than Relay eight value at')]}) + + def _get_relay_number(self, price): + if price < self.relay_one_on_at: + return 0 + if self.relay_one_on_at <= price < self.relay_two_on_at: + return 1 + elif self.relay_two_on_at <= price < self.relay_tree_on_at: + return 2 + elif self.relay_tree_on_at <= price < self.relay_four_on_at: + return 3 + elif self.relay_four_on_at <= price < self.relay_five_on_at: + return 4 + elif self.relay_five_on_at <= price < self.relay_six_on_at: + return 5 + elif self.relay_six_on_at <= price < self.relay_seven_on_at: + return 6 + elif self.relay_seven_on_at <= price < self.relay_eight_on_at: + return 7 + elif self.relay_eight_on_at <= price: + return 8 + + def calculate_relay_settings(self): + settings = [] + now = datetime.datetime.now().replace(tzinfo=self.customer.timezone) - datetime.timedelta(hours=2) + + prices = list(self.tariff.period_set.value_sequence(now, now + datetime.timedelta(hours=24))) + #print prices + unit_converter = PhysicalUnitConverter(self.tariff.unit) + print self.tariff.unit, self.tariff.pk + for i in range(0, len(prices)): + sample = prices[i] + look_ahead_sample = None + try: + look_ahead_sample = prices[i+self.look_ahead] + except IndexError: + pass + if look_ahead_sample: + change = PhysicalQuantity(100) - (sample.physical_quantity / look_ahead_sample.physical_quantity * 100) + relay_number = self._get_relay_number(float(unit_converter.extract_value( + look_ahead_sample.physical_quantity))) + + # todo fix pris delta + + settings.append( + {'sample': sample, 'look_ahead_sample': look_ahead_sample, 'change': change, 'relay': relay_number}) + + return settings diff --git a/energymanager/price_relay_site/serializers.py b/energymanager/price_relay_site/serializers.py new file mode 100644 index 0000000..796c75a --- /dev/null +++ b/energymanager/price_relay_site/serializers.py @@ -0,0 +1,25 @@ +import json + +from gridplatform.rest import serializers + +from energymanager.price_relay_site.models import PriceRelayProject + + +class PriceRelayProjectSerializer(serializers.DefaultSerializer): + name = serializers.CharField(source='name_plain') + + class Meta: + model = PriceRelayProject + fields = ('name', ) + read_only = True + + def to_native(self, obj): + native = super(PriceRelayProjectSerializer, self).to_native(obj) + if obj: + settings = [] + for setting in obj.calculate_relay_settings(): + settings.append({'timestamp': setting['sample'].from_timestamp.isoformat(), 'relay': setting['relay']}) + + native['relay_settings'] = settings + + return native diff --git a/energymanager/price_relay_site/tasks.py b/energymanager/price_relay_site/tasks.py new file mode 100644 index 0000000..5dc920d --- /dev/null +++ b/energymanager/price_relay_site/tasks.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from gridplatform.tariffs.models import EnergyTariff +from gridplatform.trackuser.tasks import task + + +@task(bind=True) +def price_relay_tariff_hourly_task( + task, tariff_id, project_id, from_timestamp, to_timestamp): + tariff = EnergyTariff.objects.get(pk=tariff_id) + + task.set_progress(0, 1) + + data = list(tariff.period_set.value_sequence(from_timestamp, to_timestamp)) + + result = {} + result['tariff_id'] = tariff_id + result['project_id'] = project_id + result['data'] = list(tariff.period_set.value_sequence(from_timestamp, to_timestamp)) + task.set_progress(1, 1) + + return result diff --git a/energymanager/price_relay_site/templates/price_relay_site/_menu.html b/energymanager/price_relay_site/templates/price_relay_site/_menu.html new file mode 100644 index 0000000..a6568b5 --- /dev/null +++ b/energymanager/price_relay_site/templates/price_relay_site/_menu.html @@ -0,0 +1,19 @@ +{% load i18n %} + +{% load bootstrap_tags %} + +{% if customer %} + +{% endif %} diff --git a/energymanager/price_relay_site/templates/price_relay_site/_navbar.html b/energymanager/price_relay_site/templates/price_relay_site/_navbar.html new file mode 100644 index 0000000..6064324 --- /dev/null +++ b/energymanager/price_relay_site/templates/price_relay_site/_navbar.html @@ -0,0 +1,11 @@ +{% extends "bootstrap/_navbar_base.html" %} + +{% load i18n %} +{% load bootstrap_tags %} + +{% block home_url %}{% url 'price_relay_site:home' %}{% endblock home_url %} +{% block title %}{% trans 'Price Relay' %}{% endblock title %} + +{% block menu_extra %} +{% include "utils/customer_selection_nav.html" %} +{% endblock menu_extra %} diff --git a/energymanager/price_relay_site/templates/price_relay_site/_price_relay_project_list_content.html b/energymanager/price_relay_site/templates/price_relay_site/_price_relay_project_list_content.html new file mode 100644 index 0000000..b470b0c --- /dev/null +++ b/energymanager/price_relay_site/templates/price_relay_site/_price_relay_project_list_content.html @@ -0,0 +1,21 @@ +{% load i18n %} + +{% if object_list %} + + + + + + {% for object in object_list %} + + + + {% endfor %} + +
{% trans "Name" %}
+ {{ object.name_plain }} +
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No price relay projects present." %} +{% endif %} diff --git a/energymanager/price_relay_site/templates/price_relay_site/base.html b/energymanager/price_relay_site/templates/price_relay_site/base.html new file mode 100644 index 0000000..9b0eaec --- /dev/null +++ b/energymanager/price_relay_site/templates/price_relay_site/base.html @@ -0,0 +1,18 @@ +{% extends "bootstrap/base.html" %} + +{% load i18n %} + +{% block page_title %}{% trans 'Price Relay' %}{% endblock %} + +{% block navbar %} +{% include "price_relay_site/_navbar.html" %} +{% endblock %} + +{% block sidebar %} +{% include "price_relay_site/_menu.html" %} +{% endblock %} + + +{% block page_bottom %} +{% include "utils/customer_selection_modal.html" with urlname='price_relay_site:customer' %} +{% endblock page_bottom %} diff --git a/energymanager/price_relay_site/templates/price_relay_site/choose_customer.html b/energymanager/price_relay_site/templates/price_relay_site/choose_customer.html new file mode 100644 index 0000000..d4be32c --- /dev/null +++ b/energymanager/price_relay_site/templates/price_relay_site/choose_customer.html @@ -0,0 +1,9 @@ +{% extends "price_relay_site/base.html" %} + +{% block page_js %} + +{% endblock page_js %} diff --git a/energymanager/price_relay_site/templates/price_relay_site/dashboard.html b/energymanager/price_relay_site/templates/price_relay_site/dashboard.html new file mode 100644 index 0000000..f9c5471 --- /dev/null +++ b/energymanager/price_relay_site/templates/price_relay_site/dashboard.html @@ -0,0 +1,39 @@ +{% extends "price_relay_site/base.html" %} +{% load i18n %} +{% load l10n %} + +{% load bootstrap_tags %} +{% load utils %} + +{% block content %} +
+{% panel object.name_plain %} +{% endpanelbuttons %} +

{% trans "Price Forecast" %}

+
+

{% trans "Relay Settings" %}

+ + + + + + + + + + + + {% for setting in object.calculate_relay_settings %} + + + + + + + + {% endfor %} + +
{% trans "Time" %}{% trans "Look Ahead Time" %}{% trans "Procent Change" %}{% trans "Relay" %}
{{ setting.sample.from_timestamp }}{{ setting.look_ahead_sample.from_timestamp }}{{ setting.change.value|floatformat:2 }}{{ setting.relay }}
+{% endpanel %} +
+{% endblock %} diff --git a/energymanager/price_relay_site/templates/price_relay_site/price_relay_project_form.html b/energymanager/price_relay_site/templates/price_relay_site/price_relay_project_form.html new file mode 100644 index 0000000..a96b8b9 --- /dev/null +++ b/energymanager/price_relay_site/templates/price_relay_site/price_relay_project_form.html @@ -0,0 +1,12 @@ +{% extends "price_relay_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Price Relay Project Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/price_relay_site/templates/price_relay_site/price_relay_project_list.html b/energymanager/price_relay_site/templates/price_relay_site/price_relay_project_list.html new file mode 100644 index 0000000..a54e583 --- /dev/null +++ b/energymanager/price_relay_site/templates/price_relay_site/price_relay_project_list.html @@ -0,0 +1,15 @@ +{% extends "price_relay_site/base.html" %} +{% load i18n %} +{% load pagination %} +{% load bootstrap_tags %} + +{% block content %} +{% panel _("Price Relay Projects") search=True %} + + {% icon "plus" %} + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/price_relay_site/tests.py b/energymanager/price_relay_site/tests.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/price_relay_site/urls.py b/energymanager/price_relay_site/urls.py new file mode 100644 index 0000000..5246268 --- /dev/null +++ b/energymanager/price_relay_site/urls.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.conf.urls import patterns +from django.conf.urls import url + +from . import views + +urlpatterns = patterns( + 'energymanager.price_relay_site.views', + url(r'^$', + views.HomeView.as_view(), + name='home'), + url(r'^customer/(?P\d+)/$', + views.CustomerView.as_view(), + name='customer'), + url(r'^choose-customer/$', + views.ChooseCustomer.as_view(), + name='choose-customer'), + url(r'^project/(?P\d+)/$', + views.PriceRelayProjectList.as_view(), + name='price-relay-project-list'), + url(r'^project/content/(?P\d+)/$', + views.PriceRelayProjectListContentView.as_view(), + name='price-relay-project-list-content'), + url(r'^project/create/(?P\d+)/$', + views.PriceRelayProjectCreateView.as_view(), + name='price-relay-project-create'), + url(r'^project/update/(?P\d+)/(?P\d+)/$', + views.PriceRelayProjectUpdateView.as_view(), + name='price-relay-project-update'), + url(r'^(?P\d+)/dashboard/$', + views.PriceRelayProjectDashboardCustomerDetailView.as_view(), + name='dashboard'), + + url(r'^project/(?P\d+)/start/(?P\d+)/$', # noqa + views.StartTariffHourlyLineChartView.as_view(), + name='forecast-chart-start'), + url(r'^project/(?P\d+)/finalize/$', + views.FinalizeTariffHourlyLineChartView.as_view(), + name='forecast-chart-finalize'), +) diff --git a/energymanager/price_relay_site/views.py b/energymanager/price_relay_site/views.py new file mode 100644 index 0000000..b97a6c1 --- /dev/null +++ b/energymanager/price_relay_site/views.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +import datetime + +from django.utils.formats import date_format +from django.utils.translation import ugettext_lazy as _ +from django import forms +from django.core.urlresolvers import reverse +from rest_framework.generics import RetrieveAPIView + +from energymanager.price_relay_site.tasks import price_relay_tariff_hourly_task +from gridplatform.customers.models import Customer +from gridplatform.tariffs.models import EnergyTariff +from gridplatform.tariffs.tasks import tariff_hourly_task +from gridplatform.utils import generic_views +from gridplatform.utils.breadcrumbs import Breadcrumb +from gridplatform.utils.breadcrumbs import Breadcrumbs +from gridplatform.utils.forms import YearWeekPeriodForm +from gridplatform.utils.preferredunits import PhysicalUnitConverter +from gridplatform.utils.views import ChooseCustomerBase, CustomerInKwargsMixin, StartTaskView, JsonResponse, \ + FinalizeTaskView +from gridplatform.utils.views import CustomerListMixin +from gridplatform.utils.views import CustomerViewBase +from gridplatform.utils.views import HomeViewBase + +from .models import PriceRelayProject + + +class HomeView(HomeViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'price_relay_site:dashboard', + kwargs={'customer_id': customer_id}) + + def get_choose_customer_url(self): + return reverse( + 'price_relay_site:choose-customer') + + +class ChooseCustomer(ChooseCustomerBase): + template_name = 'price_relay_site/choose_customer.html' + + +class CustomerView(CustomerViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'price_relay_site:dashboard', + kwargs={'customer_id': customer_id}) + + +class PriceRelayProjectList(CustomerListMixin, generic_views.TemplateView): + template_name = 'price_relay_site/price_relay_project_list.html' + + @staticmethod + def build_breadcrumbs(customer_id): + return Breadcrumbs() + Breadcrumb( + _('Price Relay Projects'), + reverse( + 'price_relay_site:price-relay-project-list', + kwargs={'customer_id': customer_id})) + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id) + + +class PriceRelayProjectListContentView( + CustomerListMixin, generic_views.ListView): + search_fields = ['name_plain', ] + sort_fields = ['name_plain', ] + model = PriceRelayProject + paginate_by = 100 + template_name = 'price_relay_site/_price_relay_project_list_content.html' + + +class PriceRelayProjectForm(forms.ModelForm): + class Meta: + model = PriceRelayProject + fields = ( + 'name', 'look_ahead', 'tariff', 'relay_one_on_at', 'relay_two_on_at', 'relay_tree_on_at', + 'relay_four_on_at', 'relay_five_on_at', 'relay_six_on_at', 'relay_seven_on_at', + 'relay_eight_on_at') + + +class PriceRelayProjectCreateView(CustomerListMixin, + generic_views.CreateView): + model = PriceRelayProject + template_name = 'price_relay_site/price_relay_project_form.html' + form_class = PriceRelayProjectForm + + def form_valid(self, form): + form.instance.customer_id = self._customer.id + result = super(PriceRelayProjectCreateView, self).form_valid(form) + assert self.object.id + self._customer.pricerelayproject_set.add(self.object) + return result + + def get_success_url(self): + return reverse('price_relay_site:price-relay-project-list', + kwargs={'customer_id': + self._customer.id}) + + def get_cancel_url(self): + return self.get_success_url() + + def get_breadcrumbs(self): + return PriceRelayProjectList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Create LED Light Project')) + + +class PriceRelayProjectUpdateView(CustomerListMixin, + generic_views.UpdateView): + model = PriceRelayProject + template_name = 'price_relay_site/price_relay_project_form.html' + form_class = PriceRelayProjectForm + + def get_success_url(self): + return reverse('price_relay_site:price-relay-project-list', + kwargs={'customer_id': + self._customer.id}) + + def get_cancel_url(self): + return self.get_success_url() + + def get_breadcrumbs(self): + return PriceRelayProjectList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(self.object) + + +class PriceRelayProjectDashboardCustomerDetailView( + CustomerListMixin, generic_views.DetailView): + model = Customer + template_name = \ + 'price_relay_site/dashboard.html' + + def get_breadcrumbs(self): + return ( + (_('Price Relay Dashboard'), ''), + ) + + def get_object(self, queryset=None): + projects = self.model.objects.get(pk=self.kwargs['customer_id']).pricerelayproject_set.all() + + if len(projects) > 0: + return projects[0] + + return None + + def get_context_data(self, **kwargs): + context = super( + PriceRelayProjectDashboardCustomerDetailView, self).get_context_data(**kwargs) + + return context + + +class StartTariffHourlyLineChartView( + CustomerInKwargsMixin, StartTaskView): + task = price_relay_tariff_hourly_task + finalize_url_name = 'price_relay_site:forecast-chart-finalize' + form_class = YearWeekPeriodForm + + def get_task_kwargs(self, form): + from_timestamp = datetime.datetime.now().replace(tzinfo=self._customer.timezone) - datetime.timedelta(hours=3) + to_timestamp = from_timestamp + datetime.timedelta(hours=24) + + project = PriceRelayProject.objects.get(pk=self.kwargs['project_id']) + + + result = {} + result['tariff_id'] = project.tariff_id + result['project_id'] = project.id + result['from_timestamp'] = from_timestamp + result['to_timestamp'] = to_timestamp + return result + + def get_finalize_url(self): + return reverse( + self.finalize_url_name, + kwargs={'customer_id': self._customer.id}) + + +class FinalizeTariffHourlyLineChartView(CustomerInKwargsMixin, FinalizeTaskView): + def finalize_task(self, task_result): + tariff = EnergyTariff.objects.get(pk=task_result['tariff_id']) + + self.unit_converter = PhysicalUnitConverter(tariff.unit) + + def format_label(timestamp): + return timestamp.astimezone(self._customer.timezone).isoformat() + + result = { + 'labels': [], + 'data': [], + } + + selected_sequence = iter(task_result['data']) + + selected = next(selected_sequence, None) + + while selected is not None: + + result['labels'].append(format_label(selected.from_timestamp)) + result['labels'].append(format_label(selected.to_timestamp)) + result['data'].append( + float(self.unit_converter.extract_value( + selected.physical_quantity))) + result['data'].append( + float(self.unit_converter.extract_value( + selected.physical_quantity))) + selected = next(selected_sequence, None) + + project = PriceRelayProject.objects.get(pk=task_result['project_id']) + + result['set_points'] = { + '1': project.relay_one_on_at, + '2': project.relay_two_on_at, + '3': project.relay_tree_on_at, + '4': project.relay_four_on_at, + '5': project.relay_five_on_at, + '6': project.relay_six_on_at, + '7': project.relay_seven_on_at, + '8': project.relay_eight_on_at + } + + + return JsonResponse(result) \ No newline at end of file diff --git a/energymanager/price_relay_site/viewsets.py b/energymanager/price_relay_site/viewsets.py new file mode 100644 index 0000000..ae3b15e --- /dev/null +++ b/energymanager/price_relay_site/viewsets.py @@ -0,0 +1,10 @@ +from rest_framework.response import Response +from rest_framework import viewsets + +from energymanager.price_relay_site import serializers +from .models import PriceRelayProject + + +class RelaySettingsViewSet(viewsets.ReadOnlyModelViewSet): + model = PriceRelayProject + serializer_class = serializers.PriceRelayProjectSerializer diff --git a/energymanager/project_site/__init__.py b/energymanager/project_site/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/project_site/models.py b/energymanager/project_site/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/energymanager/project_site/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/energymanager/project_site/templates/project_site/_menu.html b/energymanager/project_site/templates/project_site/_menu.html new file mode 100644 index 0000000..9b59162 --- /dev/null +++ b/energymanager/project_site/templates/project_site/_menu.html @@ -0,0 +1,13 @@ +{% load i18n %} + +{% load bootstrap_tags %} + +{% if customer %} + +{% endif %} diff --git a/energymanager/project_site/templates/project_site/_navbar.html b/energymanager/project_site/templates/project_site/_navbar.html new file mode 100644 index 0000000..d5d10e4 --- /dev/null +++ b/energymanager/project_site/templates/project_site/_navbar.html @@ -0,0 +1,11 @@ +{% extends "bootstrap/_navbar_base.html" %} + +{% load i18n %} +{% load bootstrap_tags %} + +{% block home_url %}{% url 'project_site:home' %}{% endblock home_url %} +{% block title %}{% trans 'ESCo Lite' %}{% endblock title %} + +{% block menu_extra %} +{% include "utils/customer_selection_nav.html" %} +{% endblock menu_extra %} diff --git a/energymanager/project_site/templates/project_site/_project_list_content.html b/energymanager/project_site/templates/project_site/_project_list_content.html new file mode 100644 index 0000000..4cff566 --- /dev/null +++ b/energymanager/project_site/templates/project_site/_project_list_content.html @@ -0,0 +1,27 @@ +{% load i18n %} + +{% load bootstrap_tags %} + +{% if object_list %} + + + + + + + {% for object in object_list %} + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Overview" %}
+ {{ object.name_plain }} + + {% icon "arrow-right" %} +
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No projects present." %} +{% endif %} diff --git a/energymanager/project_site/templates/project_site/base.html b/energymanager/project_site/templates/project_site/base.html new file mode 100644 index 0000000..e269323 --- /dev/null +++ b/energymanager/project_site/templates/project_site/base.html @@ -0,0 +1,18 @@ +{% extends "bootstrap/base.html" %} + +{% load i18n %} + +{% block page_title %}{% trans 'ESCo Lite' %}{% endblock %} + +{% block navbar %} +{% include "project_site/_navbar.html" %} +{% endblock %} + +{% block sidebar %} +{% include "project_site/_menu.html" %} +{% endblock %} + + +{% block page_bottom %} +{% include "utils/customer_selection_modal.html" with urlname='project_site:customer' %} +{% endblock page_bottom %} diff --git a/energymanager/project_site/templates/project_site/choose_customer.html b/energymanager/project_site/templates/project_site/choose_customer.html new file mode 100644 index 0000000..c69c3da --- /dev/null +++ b/energymanager/project_site/templates/project_site/choose_customer.html @@ -0,0 +1,9 @@ +{% extends "project_site/base.html" %} + +{% block page_js %} + +{% endblock page_js %} diff --git a/energymanager/project_site/templates/project_site/overview.html b/energymanager/project_site/templates/project_site/overview.html new file mode 100644 index 0000000..48cb7e3 --- /dev/null +++ b/energymanager/project_site/templates/project_site/overview.html @@ -0,0 +1,26 @@ +{% extends "project_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + +{% block content %} +{% panel object %} +

{% trans 'Status' %}:{{ phase }}

+
+
{% trans 'Baseline' %}: {{ object.baseline_from_date }} - {{ object.baseline_to_date }}
+
+
{% trans 'Baseline Energy Consumption' %}: {{ baseline_sum|floatformat:2 }} {% trans 'KW/h' %}
+
{% trans 'Baseline Time Consumption' %}: {{ baseline_time_sum|floatformat:2 }} {% trans 'hours' %}
+ + {% if object.datasource %} +

{% trans 'Baseline Energy Consumption' %}

+
+ {% endif %} + + {% if object.time_datasource %} +

{% trans 'Baseline Time Consumption' %}

+
+ {% endif %} + +{% endpanel %} + +{% endblock %} diff --git a/energymanager/project_site/templates/project_site/project_form.html b/energymanager/project_site/templates/project_site/project_form.html new file mode 100644 index 0000000..56efe2e --- /dev/null +++ b/energymanager/project_site/templates/project_site/project_form.html @@ -0,0 +1,12 @@ +{% extends "project_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Project Details") %} +{% bootstrap_form %} +{% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock %} diff --git a/energymanager/project_site/templates/project_site/project_list.html b/energymanager/project_site/templates/project_site/project_list.html new file mode 100644 index 0000000..4272171 --- /dev/null +++ b/energymanager/project_site/templates/project_site/project_list.html @@ -0,0 +1,15 @@ +{% extends "project_site/base.html" %} +{% load i18n %} +{% load pagination %} +{% load bootstrap_tags %} + +{% block content %} +{% panel _("ESCo Projects") search=True %} + + {% icon "plus" %} + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/project_site/tests.py b/energymanager/project_site/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/energymanager/project_site/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/energymanager/project_site/urls.py b/energymanager/project_site/urls.py new file mode 100644 index 0000000..968c9fb --- /dev/null +++ b/energymanager/project_site/urls.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.conf.urls import patterns +from django.conf.urls import url + +from . import views + +urlpatterns = patterns( + 'energymanager.project_site.views', + url(r'^$', + views.HomeView.as_view(), + name='home'), + url(r'^customer/(?P\d+)/$', + views.CustomerView.as_view(), + name='customer'), + url(r'^choose-customer/$', + views.ChooseCustomer.as_view(), + name='choose-customer'), + url(r'^project/(?P\d+)/$', + views.EnergyProjectList.as_view(), + name='project-list'), + url(r'^project/content/(?P\d+)/$', + views.EnergyProjectListContentView.as_view(), + name='project-list-content'), + url(r'^project/create/(?P\d+)/$', + views.EnergyProjectCreateView.as_view(), + name='project-create'), + url(r'^project/update/(?P\d+)/(?P\d+)/$', + views.EnergyProjectUpdateView.as_view(), + name='project-update'), + url(r'^project/delete/(?P\d+)/(?P\d+)/$', + views.EnergyProjectDeleteView.as_view(), + name='project-delete'), + url(r'^project/overview/(?P\d+)/(?P\d+)/$', + views.EnergyProjectDetailView.as_view(), + name='project-detail'), + + url(r'^project/(?P\d+)/start_power/(?P\d+)/$', # noqa + views.StartBaselineHourConsumptionUtilityBarChartView.as_view(), + name='consumption-utility-bar-chart-start'), + url(r'^project/(?P\d+)/start_time/(?P\d+)/$', # noqa + views.StartBaselineDayliConsumptionUtilityBarChartView.as_view(), + name='time-consumption-utility-bar-chart-start'), + url(r'^project/(?P\d+)/finalize/$', + views.FinalizeWeekUtilityBarChartView.as_view(), + name='utility-bar-chart-finalize'), +) diff --git a/energymanager/project_site/views.py b/energymanager/project_site/views.py new file mode 100644 index 0000000..6e48902 --- /dev/null +++ b/energymanager/project_site/views.py @@ -0,0 +1,239 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.utils.formats import date_format +from django.utils.translation import ugettext_lazy as _ +from django import forms +from django.core.urlresolvers import reverse + +from gridplatform.consumptions.models import Consumption +from gridplatform.consumptions.tasks import consumptions_weekly_utility_task, consumptions_weekly_time_task +from gridplatform.utils.forms import YearWeekPeriodForm +from gridplatform.utils.preferredunits import PhysicalUnitConverter +from gridplatform.utils.utilitytypes import ENERGY_UTILITY_TYPE_TO_DISPLAY_UNIT_MAP +from gridplatform.utils.views import CustomerInKwargsMixin, FinalizeTaskView, JsonResponse +from gridplatform.utils.views import StartTaskView +from gridplatform.utils import generic_views, PhysicalQuantity +from gridplatform.utils.breadcrumbs import Breadcrumb +from gridplatform.utils.breadcrumbs import Breadcrumbs +from gridplatform.utils.views import ChooseCustomerBase +from gridplatform.utils.views import CustomerListMixin +from gridplatform.utils.views import CustomerViewBase +from gridplatform.utils.views import HomeViewBase + +from energymanager.energy_projects.models import EnergyProject, ENERGY_PROJECT_PHASES + + +class HomeView(HomeViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'project_site:project-list', + kwargs={'customer_id': customer_id}) + + def get_choose_customer_url(self): + return reverse( + 'project_site:choose-customer') + + +class ChooseCustomer(ChooseCustomerBase): + template_name = 'project_site/choose_customer.html' + + +class CustomerView(CustomerViewBase): + def get_redirect_with_customer_url(self, customer_id): + return reverse( + 'project_site:project-list', + kwargs={'customer_id': customer_id}) + + +class EnergyProjectList(CustomerListMixin, generic_views.TemplateView): + template_name = 'project_site/project_list.html' + + @staticmethod + def build_breadcrumbs(customer_id): + return Breadcrumbs() + Breadcrumb( + _('Projects'), + reverse( + 'project_site:project-list', + kwargs={'customer_id': customer_id})) + + def get_breadcrumbs(self): + return self.build_breadcrumbs(self._customer.id) + + +class EnergyProjectListContentView( + CustomerListMixin, + generic_views.ListView): + search_fields = ['name_plain', ] + sort_fields = ['name_plain', ] + model = EnergyProject + paginate_by = 100 + template_name = 'project_site/_project_list_content.html' + + +class EnergyProjectForm(forms.ModelForm): + + class Meta: + model = EnergyProject + fields = ( + 'name', 'baseline_from_date', 'baseline_to_date', + 'datasource', 'time_datasource', + 'result_from_date', 'result_to_date' + ) + + +class EnergyProjectCreateView(CustomerListMixin, + generic_views.CreateView): + model = EnergyProject + template_name = 'project_site/project_form.html' + form_class = EnergyProjectForm + + def form_valid(self, form): + form.instance.customer_id = self._customer.id + result = super(EnergyProjectCreateView, self).form_valid(form) + assert self.object.id + self._customer.energyproject_set.add(self.object) + return result + + def get_success_url(self): + return reverse('project_site:project-list', + kwargs={'customer_id': + self._customer.id}) + + def get_cancel_url(self): + return self.get_success_url() + + def get_breadcrumbs(self): + return EnergyProjectList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(_('Create Project')) + + +class EnergyProjectUpdateView(CustomerListMixin, + generic_views.UpdateView): + model = EnergyProject + template_name = 'project_site/project_form.html' + form_class = EnergyProjectForm + + def get_success_url(self): + return reverse('project_site:project-list', + kwargs={'customer_id': + self._customer.id}) + + def get_cancel_url(self): + return self.get_success_url() + + def get_delete_url(self): + return reverse('project_site:project-delete', + kwargs={'customer_id': + self._customer.id, + 'pk': + self.object.id}) + + def get_breadcrumbs(self): + return EnergyProjectList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(self.object) + + +class EnergyProjectDeleteView( + CustomerListMixin, generic_views.DeleteView): + model = EnergyProject + + def get_success_url(self): + return reverse('project_site:project-list', + kwargs={'customer_id': + self._customer.id}) + + +class EnergyProjectDetailView( + CustomerListMixin, generic_views.DetailView): + model = EnergyProject + template_name = \ + 'project_site/overview.html' + + def get_breadcrumbs(self): + return EnergyProjectList.build_breadcrumbs(self._customer.id) + \ + Breadcrumb(self.object) + + def get_context_data(self, **kwargs): + context = super(EnergyProjectDetailView, self).get_context_data(**kwargs) + + context['phase'] = ENERGY_PROJECT_PHASES[self.object.project_phase()] + context['baseline_sum'] = self.object.total_baseline_consumption() + context['baseline_time_sum'] = self.object.total_baseline_time_consumption() + return context + + +class StartHourConsumptionUtilityBarChartViewBase( + CustomerInKwargsMixin, StartTaskView): + task = consumptions_weekly_time_task + finalize_url_name = 'project_site:utility-bar-chart-finalize' + form_class = YearWeekPeriodForm + + def get_consumption_id(self, project): + raise NotImplementedError() + + def get_task_kwargs(self, form): + project = EnergyProject.objects.get(pk=self.kwargs['project_id']) + from_timestamp, to_timestamp = project.baseline_timestamps() + result = {} + result['consumption_ids'] = [self.get_consumption_id(project)] + result['from_timestamp'] = from_timestamp + result['to_timestamp'] = to_timestamp + return result + + def get_finalize_url(self): + return reverse( + self.finalize_url_name, + kwargs={'customer_id': self._customer.id}) + + +class StartBaselineHourConsumptionUtilityBarChartView( + StartHourConsumptionUtilityBarChartViewBase): + task = consumptions_weekly_utility_task + + def get_consumption_id(self, project): + return project.datasource_id + + +class StartBaselineDayliConsumptionUtilityBarChartView( + StartHourConsumptionUtilityBarChartViewBase): + + def get_consumption_id(self, project): + return project.time_datasource_id + + +class FinalizeWeekUtilityBarChartView(CustomerInKwargsMixin, FinalizeTaskView): + def finalize_task(self, task_result): + consumption = Consumption.objects.get(pk=task_result['consumption_id']) + + unit = 'watt*hour' + if PhysicalQuantity.compatible_units( + consumption.unit, 'second'): + unit = 'hour' + + self.unit_converter = PhysicalUnitConverter(unit) + + def format_label(timestamp): + return date_format( + timestamp.astimezone(self._customer.timezone), + 'SHORT_DATETIME_FORMAT') + + result = { + 'labels': [], + 'week_selected': [], + } + + selected_sequence = iter(task_result['week_selected']) + + selected = next(selected_sequence, None) + + while selected is not None: + + result['labels'].append(format_label(selected.from_timestamp)) + result['week_selected'].append( + float(self.unit_converter.extract_value( + selected.physical_quantity))) + selected = next(selected_sequence, None) + + return JsonResponse(result) \ No newline at end of file diff --git a/energymanager/provider_site/__init__.py b/energymanager/provider_site/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/provider_site/locale/da/LC_MESSAGES/django.mo b/energymanager/provider_site/locale/da/LC_MESSAGES/django.mo new file mode 100644 index 0000000..7eed554 Binary files /dev/null and b/energymanager/provider_site/locale/da/LC_MESSAGES/django.mo differ diff --git a/energymanager/provider_site/locale/da/LC_MESSAGES/django.po b/energymanager/provider_site/locale/da/LC_MESSAGES/django.po new file mode 100644 index 0000000..e885ac1 --- /dev/null +++ b/energymanager/provider_site/locale/da/LC_MESSAGES/django.po @@ -0,0 +1,148 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-10-23 14:38+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: views.py:31 views.py:74 views.py:103 templates/provider_site/_menu.html:8 +#: templates/provider_site/customer_list.html:8 +msgid "Customers" +msgstr "Kunder" + +#: views.py:76 views.py:105 templates/provider_site/customer_form.html:7 +msgid "Customer Details" +msgstr "Kundedetaljer" + +#: views.py:135 +msgid "A user with that e-mail already exists" +msgstr "En bruger med denne e-mail-adresse eksisterer allerede" + +#: views.py:157 views.py:288 +#: templates/provider_site/_api_user_list_content.html:9 +#: templates/provider_site/_user_list_content.html:10 +msgid "Customer" +msgstr "Kunde" + +#: views.py:254 views.py:329 views.py:359 +#: templates/provider_site/_menu.html:18 +#: templates/provider_site/api_user_list.html:24 +#: templates/provider_site/show_token.html:8 +msgid "API Users" +msgstr "API-brugere" + +#: views.py:330 +msgid "API User Create" +msgstr "Opret API-bruger" + +#: templates/provider_site/_api_user_list_content.html:7 +#: templates/provider_site/_user_list_content.html:7 +msgid "Username" +msgstr "Brugernavn" + +#: templates/provider_site/_api_user_list_content.html:8 +#: templates/provider_site/_user_list_content.html:9 +msgid "Groups" +msgstr "Grupper" + +#: templates/provider_site/_api_user_list_content.html:10 +#: templates/provider_site/_customer_list_content.html:7 +#: templates/provider_site/_user_list_content.html:11 +msgid "Active" +msgstr "Aktiv" + +#: templates/provider_site/_api_user_list_content.html:25 +msgid "No API users present." +msgstr "Ingen API-brugere tilgængelige." + +#: templates/provider_site/_customer_list_content.html:6 +#: templates/provider_site/_user_list_content.html:8 +msgid "Name" +msgstr "Navn" + +#: templates/provider_site/_customer_list_content.html:20 +msgid "No customers present." +msgstr "Ingen kunder tilgængelige." + +#: templates/provider_site/_menu.html:13 +#: templates/provider_site/user_form.html:29 +#: templates/provider_site/user_list.html:7 +#: templates/provider_site/user_list.html:10 +msgid "Users" +msgstr "Brugere" + +#: templates/provider_site/_navbar.html:5 templates/provider_site/base.html:6 +msgid "Administration" +msgstr "Administration" + +#: templates/provider_site/_user_list_content.html:27 +msgid "No users present." +msgstr "Ingen brugere tilgængelige." + +#: templates/provider_site/api_user_form.html:7 +#: templates/provider_site/user_form.html:33 +msgid "Create User" +msgstr "Opret bruger" + +#: templates/provider_site/api_user_list.html:25 +#: templates/provider_site/customer_list.html:9 +#: templates/provider_site/user_list.html:11 +msgid "Add" +msgstr "Tilføj" + +#: templates/provider_site/api_user_list.html:38 +msgid "Confirm" +msgstr "Bekræft" + +#: templates/provider_site/api_user_list.html:41 +msgid "Are you sure you want to delete this user?" +msgstr "Er du sikker på at du ønsker at slette denne bruger?" + +#: templates/provider_site/api_user_list.html:46 +msgid "Cancel" +msgstr "Annullér" + +#: templates/provider_site/api_user_list.html:47 +msgid "Delete" +msgstr "Slet" + +#: templates/provider_site/api_user_update_form.html:7 +msgid "Update User" +msgstr "Opdatér Bruger" + +#: templates/provider_site/show_token.html:9 +msgid "User Created" +msgstr "Bruger Oprettet" + +#: templates/provider_site/show_token.html:12 +msgid "User created" +msgstr "Bruger oprettet" + +#: templates/provider_site/show_token.html:13 +msgid "Username:" +msgstr "Brugernavn:" + +#: templates/provider_site/show_token.html:15 +msgid "Token:" +msgstr "Token:" + +#: templates/provider_site/user_form.html:37 +msgid "User Details" +msgstr "Brugerdetaljer" + +#: templates/provider_site/user_form.html:50 +msgid "Generate" +msgstr "Generér" diff --git a/energymanager/provider_site/locale/es/LC_MESSAGES/django.mo b/energymanager/provider_site/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000..ce692f0 Binary files /dev/null and b/energymanager/provider_site/locale/es/LC_MESSAGES/django.mo differ diff --git a/energymanager/provider_site/locale/es/LC_MESSAGES/django.po b/energymanager/provider_site/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000..1a0c64b --- /dev/null +++ b/energymanager/provider_site/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,148 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-09-15 13:43+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: views.py:30 views.py:73 views.py:102 templates/provider_site/_menu.html:8 +#: templates/provider_site/customer_list.html:8 +msgid "Customers" +msgstr "" + +#: views.py:75 views.py:104 templates/provider_site/customer_form.html:7 +msgid "Customer Details" +msgstr "" + +#: views.py:134 +msgid "A user with that e-mail already exists" +msgstr "" + +#: views.py:155 views.py:279 +#: templates/provider_site/_api_user_list_content.html:9 +#: templates/provider_site/_user_list_content.html:10 +msgid "Customer" +msgstr "" + +#: views.py:246 views.py:320 views.py:350 +#: templates/provider_site/_menu.html:18 +#: templates/provider_site/api_user_list.html:24 +#: templates/provider_site/show_token.html:8 +msgid "API Users" +msgstr "" + +#: views.py:321 +msgid "API User Create" +msgstr "" + +#: templates/provider_site/_api_user_list_content.html:7 +#: templates/provider_site/_user_list_content.html:7 +msgid "Username" +msgstr "" + +#: templates/provider_site/_api_user_list_content.html:8 +#: templates/provider_site/_user_list_content.html:9 +msgid "Groups" +msgstr "" + +#: templates/provider_site/_api_user_list_content.html:10 +#: templates/provider_site/_customer_list_content.html:7 +#: templates/provider_site/_user_list_content.html:11 +msgid "Active" +msgstr "" + +#: templates/provider_site/_api_user_list_content.html:25 +msgid "No API users present." +msgstr "" + +#: templates/provider_site/_customer_list_content.html:6 +#: templates/provider_site/_user_list_content.html:8 +msgid "Name" +msgstr "" + +#: templates/provider_site/_customer_list_content.html:20 +msgid "No customers present." +msgstr "" + +#: templates/provider_site/_menu.html:13 +#: templates/provider_site/user_form.html:29 +#: templates/provider_site/user_list.html:7 +#: templates/provider_site/user_list.html:10 +msgid "Users" +msgstr "" + +#: templates/provider_site/_navbar.html:5 templates/provider_site/base.html:6 +msgid "Administration" +msgstr "" + +#: templates/provider_site/_user_list_content.html:27 +msgid "No users present." +msgstr "" + +#: templates/provider_site/api_user_form.html:7 +#: templates/provider_site/user_form.html:33 +msgid "Create User" +msgstr "" + +#: templates/provider_site/api_user_list.html:25 +#: templates/provider_site/customer_list.html:9 +#: templates/provider_site/user_list.html:11 +msgid "Add" +msgstr "" + +#: templates/provider_site/api_user_list.html:38 +msgid "Confirm" +msgstr "" + +#: templates/provider_site/api_user_list.html:41 +msgid "Are you sure you want to delete this user?" +msgstr "" + +#: templates/provider_site/api_user_list.html:46 +msgid "Cancel" +msgstr "" + +#: templates/provider_site/api_user_list.html:47 +msgid "Delete" +msgstr "" + +#: templates/provider_site/api_user_update_form.html:7 +msgid "Update User" +msgstr "" + +#: templates/provider_site/show_token.html:9 +msgid "User Created" +msgstr "" + +#: templates/provider_site/show_token.html:12 +msgid "User created" +msgstr "" + +#: templates/provider_site/show_token.html:13 +msgid "Username:" +msgstr "" + +#: templates/provider_site/show_token.html:15 +msgid "Token:" +msgstr "" + +#: templates/provider_site/user_form.html:37 +msgid "User Details" +msgstr "" + +#: templates/provider_site/user_form.html:50 +msgid "Generate" +msgstr "" diff --git a/energymanager/provider_site/locale/es/LC_MESSAGES/djangojs.po b/energymanager/provider_site/locale/es/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/provider_site/models.py b/energymanager/provider_site/models.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/provider_site/templates/provider_site/_api_user_list_content.html b/energymanager/provider_site/templates/provider_site/_api_user_list_content.html new file mode 100644 index 0000000..ed36230 --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/_api_user_list_content.html @@ -0,0 +1,26 @@ +{% load i18n %} +{% load bootstrap_tags %} + +{% if object_list %} + + + + + + + + + {% for object in object_list %} + + + + + + + {% endfor %} + +
{% trans "Username" %}{% trans "Groups" %}{% trans "Customer" %}{% trans "Active" %}
{{ object.e_mail_plain }}{% for group in object.groups.all %}{{ group }}{% if not forloop.last %}, {% endif %}{% endfor %}{% if object.customer %}{{ object.customer }}{% endif %}{% if object.is_active %}{% icon 'check-square-o' %}{% else %}{% icon 'square-o' %}{% endif %}
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No API users present." %} +{% endif %} diff --git a/energymanager/provider_site/templates/provider_site/_customer_list_content.html b/energymanager/provider_site/templates/provider_site/_customer_list_content.html new file mode 100644 index 0000000..504c60b --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/_customer_list_content.html @@ -0,0 +1,21 @@ +{% load i18n %} +{% load bootstrap_tags %} +{% if object_list %} + + + + + + + {% for object in object_list %} + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Active" %}
{{ object.name_plain }}{% if object.is_active %}{% icon 'check-square-o' %}{% else %}{% icon 'square-o' %}{% endif %}
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No customers present." %} +{% endif %} diff --git a/energymanager/provider_site/templates/provider_site/_menu.html b/energymanager/provider_site/templates/provider_site/_menu.html new file mode 100644 index 0000000..35eadbf --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/_menu.html @@ -0,0 +1,22 @@ +{% load i18n %} +{% load static from staticfiles %} +{% load bootstrap_tags %} + + diff --git a/energymanager/provider_site/templates/provider_site/_navbar.html b/energymanager/provider_site/templates/provider_site/_navbar.html new file mode 100644 index 0000000..1898c4b --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/_navbar.html @@ -0,0 +1,5 @@ +{% extends "bootstrap/_navbar_base.html" %} +{% load i18n %} + +{% block home_url %}{% url 'provider_site:home' %}{% endblock %} +{% block title %}{% trans "Administration" %}{% endblock %} diff --git a/energymanager/provider_site/templates/provider_site/_user_list_content.html b/energymanager/provider_site/templates/provider_site/_user_list_content.html new file mode 100644 index 0000000..dce138c --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/_user_list_content.html @@ -0,0 +1,28 @@ +{% load i18n %} +{% load bootstrap_tags %} + +{% if object_list %} + + + + + + + + + + {% for object in object_list %} + + + + + + + + {% endfor %} + +
{% trans "Username" %}{% trans "Name" %}{% trans "Groups" %}{% trans "Customer" %}{% trans "Active" %}
{{ object.e_mail_plain }}{{ object.name_plain }}{% for group in object.groups.all %}{{ group }}{% if not forloop.last %}, {% endif %}{% endfor %}{{ object.customer|default:"" }}{% if object.is_active %}{% icon 'check-square-o' %}{% else %}{% icon 'square-o' %}{% endif %}
+{% include "bootstrap/_pagination.html" %} +{% else %} +{% trans "No users present." %} +{% endif %} diff --git a/energymanager/provider_site/templates/provider_site/api_user_form.html b/energymanager/provider_site/templates/provider_site/api_user_form.html new file mode 100644 index 0000000..fea879e --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/api_user_form.html @@ -0,0 +1,12 @@ +{% extends "provider_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Create User") %} + {% bootstrap_form %} + {% form form %} + {% endbootstrap_form %} +{% endpanel %} +{% endblock content %} diff --git a/energymanager/provider_site/templates/provider_site/api_user_list.html b/energymanager/provider_site/templates/provider_site/api_user_list.html new file mode 100644 index 0000000..c7b6094 --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/api_user_list.html @@ -0,0 +1,53 @@ +{% extends "provider_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + +{% block page_js %} + +{% endblock page_js %} + +{% block content %} +{% panel _("API Users") search=True %} + + + +{% endpanelbuttons %} +
+{% endpanel %} +{% endblock content %} + +{% block page_bottom %} + +{% endblock %} diff --git a/energymanager/provider_site/templates/provider_site/api_user_update_form.html b/energymanager/provider_site/templates/provider_site/api_user_update_form.html new file mode 100644 index 0000000..945c9de --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/api_user_update_form.html @@ -0,0 +1,12 @@ +{% extends "provider_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} +{% panel _("Update User") %} + {% bootstrap_form %} + {% form form %} + {% endbootstrap_form %} +{% endpanel %} +{% endblock content %} diff --git a/energymanager/provider_site/templates/provider_site/base.html b/energymanager/provider_site/templates/provider_site/base.html new file mode 100644 index 0000000..f7eb6a7 --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/base.html @@ -0,0 +1,15 @@ +{% extends "bootstrap/base.html" %} + +{% load static from staticfiles %} +{% load i18n %} + +{% block page_title %}{% trans "Administration" %}{% endblock %} + +{% block navbar %} +{% include "provider_site/_navbar.html" %} +{% endblock %} + +{% block sidebar %} +{% include "provider_site/_menu.html" %} +{% endblock %} + diff --git a/energymanager/provider_site/templates/provider_site/customer_form.html b/energymanager/provider_site/templates/provider_site/customer_form.html new file mode 100644 index 0000000..a3765a7 --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/customer_form.html @@ -0,0 +1,12 @@ +{% extends "provider_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + +{% block content %} + +{% panel _("Customer Details") %} +{% bootstrap_form %} + {% form form %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock content %} diff --git a/energymanager/provider_site/templates/provider_site/customer_list.html b/energymanager/provider_site/templates/provider_site/customer_list.html new file mode 100644 index 0000000..bacb1e0 --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/customer_list.html @@ -0,0 +1,15 @@ +{% extends "provider_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} + +{% panel _("Customers") search=True %} + + + +{% endpanelbuttons %} +
+{% endpanel %} +{% endblock content %} diff --git a/energymanager/provider_site/templates/provider_site/show_token.html b/energymanager/provider_site/templates/provider_site/show_token.html new file mode 100644 index 0000000..1f57d4f --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/show_token.html @@ -0,0 +1,19 @@ +{% extends "provider_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + + +{% block content %} + + +{% panel _("User created") %} +

{% trans "Username:" %}

+{{ username }} +

{% trans "Token:" %}

+{{ token }} + +{% endpanel %} +{% endblock content %} diff --git a/energymanager/provider_site/templates/provider_site/user_form.html b/energymanager/provider_site/templates/provider_site/user_form.html new file mode 100644 index 0000000..27feaff --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/user_form.html @@ -0,0 +1,57 @@ +{% extends "provider_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + +{% block page_js %} + +{% endblock %} + +{% block content %} + + +{% panel _("User Details") %} +{% bootstrap_form %} + {% non_field_errors form %} + {% csrf_token %} + {% for hidden in form.hidden_fields %} + {{ hidden }} + {% endfor %} + {% for field in form.visible_fields %} + {% field field %} + {% endfor %} + {% if form.instance.id %} +
+
+ +
+
+ {% endif %} + {% form_buttons %} +{% endbootstrap_form %} +{% endpanel %} +{% endblock content %} diff --git a/energymanager/provider_site/templates/provider_site/user_list.html b/energymanager/provider_site/templates/provider_site/user_list.html new file mode 100644 index 0000000..0dc1e9e --- /dev/null +++ b/energymanager/provider_site/templates/provider_site/user_list.html @@ -0,0 +1,18 @@ +{% extends "provider_site/base.html" %} +{% load i18n %} +{% load bootstrap_tags %} + +{% block content %} + + +{% panel _("Users") search=False %} + + + +{% endpanelbuttons %} +
+{% endpanel %} + +{% endblock %} diff --git a/energymanager/provider_site/tests.py b/energymanager/provider_site/tests.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/provider_site/urls.py b/energymanager/provider_site/urls.py new file mode 100644 index 0000000..443ad95 --- /dev/null +++ b/energymanager/provider_site/urls.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.conf.urls import patterns, url +from django.core.urlresolvers import reverse_lazy +from django.views.generic import RedirectView + +from . import views + +urlpatterns = patterns( + '', + url(r'^$', + RedirectView.as_view( + url=reverse_lazy('provider_site:customer-list')), + name='home'), + url(r'^customers/$', + views.CustomerListView.as_view(), + name='customer-list'), + url(r'^customers/content$', + views.CustomerListContentView.as_view(), + name='customer-list-content'), + url(r'^customers/create$', + views.CustomerCreateView.as_view(), + name='customer-create'), + url(r'^customers/update/(?P\d+)/$', + views.CustomerUpdateView.as_view(), + name='customer-update'), + + url(r'^users/$', + views.UserListView.as_view(), + name='user-list'), + url(r'^users/content$', + views.UserListContentView.as_view(), + name='user-list-content'), + url(r'^users/create$', + views.UserCreateView.as_view(), + name='user-create'), + url(r'^users/update/(?P\d+)/$', + views.UserUpdateView.as_view(), + name='user-update'), + + url(r'^api_users/$', + views.APIUserListView.as_view(), + name='apiuser-list'), + url(r'^api_users/content$', + views.APIUserListContentView.as_view(), + name='apiuser-list-content'), + url(r'^api_users/create$', + views.APIUserCreateView.as_view(), + name='apiuser-create'), + url(r'^api_users/update/(?P\d+)/$', + views.APIUserUpdateView.as_view(), + name='apiuser-update'), +) diff --git a/energymanager/provider_site/views.py b/energymanager/provider_site/views.py new file mode 100644 index 0000000..d5a23a1 --- /dev/null +++ b/energymanager/provider_site/views.py @@ -0,0 +1,360 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django import forms +from django.conf import settings +from django.contrib.auth import logout +from django.contrib.auth.models import Group +from django.contrib.auth.models import Permission +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect +from django.shortcuts import render +from django.utils.translation import ugettext as _ + +from gridplatform.customers.models import Customer +from gridplatform.token_auth.models import create_token +from gridplatform.trackuser import get_provider +from gridplatform.trackuser import _get_user_customer +from gridplatform.users.managers import hash_username +from gridplatform.users.models import User +from gridplatform.utils import generic_views +from gridplatform.utils.views import NoCustomerMixin + + +class CustomerListView(NoCustomerMixin, generic_views.ListView): + model = Customer + template_name = 'provider_site/customer_list.html' + + def get_breadcrumbs(self): + return ( + (_('Customers'), ''), + ) + + +class CustomerListContentView( + NoCustomerMixin, generic_views.ListView): + sort_fields = ['name_plain', 'is_active'] + search_fields = ['name_plain'] + model = Customer + paginate_by = 100 + template_name = 'provider_site/_customer_list_content.html' + + +class CustomerCreateView( + NoCustomerMixin, generic_views.CreateView): + model = Customer + template_name = 'provider_site/customer_form.html' + fields = ( + 'name', 'vat', 'address', 'postal_code', 'city', 'phone', + 'country_code', 'timezone', 'contact_name', 'contact_email', + 'contact_phone', 'electricity_instantaneous', + 'electricity_consumption', 'gas_instantaneous', 'gas_consumption', + 'water_instantaneous', 'water_consumption', + 'heat_instantaneous', 'heat_consumption', + 'oil_instantaneous', 'oil_consumption', + 'temperature', 'currency_unit', + ) + + def get_success_url(self): + return reverse('provider_site:customer-list') + + def get_cancel_url(self): + return self.get_success_url() + + def form_valid(self, form): + self.object = form.save(commit=False) + self.object.provider = get_provider() + self.object.save() + + return HttpResponseRedirect(self.get_success_url()) + + def get_breadcrumbs(self): + return ( + (_('Customers'), + reverse('provider_site:customer-list')), + (_('Customer Details'), ''), + ) + + +class CustomerUpdateView( + NoCustomerMixin, generic_views.UpdateView): + model = Customer + template_name = 'provider_site/customer_form.html' + fields = ( + 'name', 'vat', 'address', 'postal_code', 'city', 'phone', + 'country_code', 'timezone', 'contact_name', 'contact_email', + 'contact_phone', 'electricity_instantaneous', + 'electricity_consumption', 'gas_instantaneous', 'gas_consumption', + 'water_instantaneous', 'water_consumption', + 'heat_instantaneous', 'heat_consumption', + 'oil_instantaneous', 'oil_consumption', + 'temperature', 'currency_unit', 'is_active' + ) + + def get_success_url(self): + return reverse('provider_site:customer-list') + + def get_cancel_url(self): + return self.get_success_url() + + def get_breadcrumbs(self): + return ( + (_('Customers'), + reverse('provider_site:customer-list')), + (_('Customer Details'), ''), + ) + + +class UserListView( + NoCustomerMixin, generic_views.TemplateView): + template_name = 'provider_site/user_list.html' + + +class UserListContentView( + NoCustomerMixin, generic_views.ListView): + sort_fields = ['e_mail_plain', 'name_plain'] + search_fields = ['e_mail_plain', 'name_plain'] + model = User + paginate_by = 100 + template_name = 'provider_site/_user_list_content.html' + + def get_queryset(self): + qs = super(UserListContentView, self).get_queryset() + return qs.exclude(user_type=User.API_USER) + + +class UserFormBase(forms.ModelForm): + class Meta: + model = User + + def clean_e_mail(self): + e_mail = self.cleaned_data['e_mail'] + if User.objects.filter(username=hash_username(e_mail)).exists(): + raise forms.ValidationError( + _("A user with that e-mail already exists")) + return e_mail + + +class UserForm(UserFormBase): + class Meta(UserFormBase.Meta): + fields = ('groups', 'e_mail', + 'phone', 'mobile', 'password', + 'name') + + def __init__(self, *args, **kwargs): + super(UserForm, self).__init__(*args, **kwargs) + self.fields['password'].initial = User.objects.make_random_password() + + group_perm = Permission.objects.get(codename='provider_admin_group') + groups = Group.objects.filter(permissions__id__exact=group_perm.id) + self.fields['groups'].choices = [(g.id, g.name) for g in groups] + + +class UserCreateForm(UserForm): + # customer field is editable=False on User model. + customer = forms.ModelChoiceField( + label=_('Customer'), queryset=Customer.objects.none()) + + def __init__(self, *args, **kwargs): + super(UserCreateForm, self).__init__(*args, **kwargs) + self.fields['customer'].queryset = Customer.objects.all() + + def save(self, commit=True): + self.instance.customer = self.cleaned_data['customer'] + return super(UserCreateForm, self).save(commit=commit) + + +class UserCreateView( + NoCustomerMixin, generic_views.CreateView): + model = User + template_name = 'provider_site/user_form.html' + form_class = UserCreateForm + + def get_success_url(self): + return reverse('provider_site:user-list') + + def get_cancel_url(self): + return self.get_success_url() + + def form_valid(self, form): + self.object = form.save(commit=False) + + if self.object.customer: + user = User.objects.create_user( + self.object.e_mail_plain, self.object.password, + user_type=User.ADMIN, + customer=self.object.customer, + groups=form.cleaned_data.get('groups', None)) + else: + user = User.objects.create_user( + self.object.e_mail_plain, self.object.password, + user_type=User.ADMIN, + provider=get_provider(), + groups=form.cleaned_data.get('groups', None)) + + user.e_mail_plain = self.object.e_mail_plain + user.name_plain = self.object.name_plain + user.phone_plain = self.object.phone_plain + user.mobile_plain = self.object.mobile_plain + user.save() + + return HttpResponseRedirect(self.get_success_url()) + + +class UserUpdateForm(forms.ModelForm): + new_password = forms.CharField(required=False, min_length=8) + + class Meta: + model = User + fields = ('groups', 'e_mail', + 'name', 'phone', 'mobile', 'is_active') + + def __init__(self, *args, **kwargs): + super(UserUpdateForm, self).__init__(*args, **kwargs) + group_perm = Permission.objects.get(codename='provider_admin_group') + groups = Group.objects.filter(permissions__id__exact=group_perm.id) + self.fields['groups'].choices = [(g.id, g.name) for g in groups] + + def save(self, commit=True): + assert commit + user = super(UserUpdateForm, self).save(commit=False) + if self.cleaned_data.get('new_password'): + user.reset_password( + self.request, self.cleaned_data.get('new_password')) + if user.id == self.request.user.id: + logout(self.request) + user.save() + self.save_m2m() + return user + + +class UserUpdateView( + NoCustomerMixin, generic_views.UpdateView): + model = User + template_name = 'provider_site/user_form.html' + form_class = UserUpdateForm + + def get_success_url(self): + return reverse('provider_site:user-list') + + def get_cancel_url(self): + return self.get_success_url() + + def form_valid(self, form): + form.request = self.request + form.save() + return HttpResponseRedirect(self.get_success_url()) + + +class APIUserListView(NoCustomerMixin, generic_views.TemplateView): + template_name = 'provider_site/api_user_list.html' + + def get_breadcrumbs(self): + return ((_('API Users'), ''), ) + + +class APIUserListContentView(NoCustomerMixin, generic_views.ListView): + sort_fields = [ + 'provider__name_plain', 'customer__name_plain', 'e_mail_plain', + ] + search_fields = [ + 'provider__name_plain', 'customer__name_plain', 'e_mail_plain', + ] + model = User + paginate_by = 100 + template_name = 'provider_site/_api_user_list_content.html' + + def get_queryset(self): + qs = super(APIUserListContentView, self).get_queryset() + return qs.filter(user_type=User.API_USER) + + +class APIUserForm(UserFormBase): + class Meta(UserFormBase.Meta): + fields = ('e_mail', 'groups') + + +class APIUserCreateForm(APIUserForm): + def __init__(self, *args, **kwargs): + super(APIUserCreateForm, self).__init__(*args, **kwargs) + if _get_user_customer() is None: + self.fields['customer'].required = False + self.fields['customer'].widget.is_required = False + self.fields['customer'].empty_label = \ + 'All customers --- Provider API User' + + customer = forms.ModelChoiceField( + label=_('Customer'), + queryset=Customer.objects.all(), empty_label=None) + + def save(self, commit=True): + self.instance.customer = self.cleaned_data['customer'] + if _get_user_customer() is None and not self.instance.customer: + self.instance.provider = get_provider() + return super(APIUserCreateForm, self).save(commit=commit) + + +class APIUserCreateView(NoCustomerMixin, generic_views.CreateView): + model = User + template_name = 'provider_site/api_user_form.html' + form_class = APIUserCreateForm + + def get_success_url(self): + return reverse('provider_site:apiuser-list') + + def form_valid(self, form): + self.object = form.save(commit=False) + + password = User.objects.make_random_password( + length=settings.TOKEN_AUTH_USER_PASSWORD_LENGTH) + + user = User.objects.create_user( + self.object.e_mail_plain, password, user_type=User.API_USER, + customer=self.object.customer, provider=self.object.provider, + groups=form.cleaned_data.get('groups', None)) + + user.name_plain = 'API User' + user.save() + token = create_token(user, password) + + context = { + 'username': user.e_mail_plain, + 'token': token, + } + return render(self.request, 'provider_site/show_token.html', context) + + def get_breadcrumbs(self): + return ( + (_('API Users'), reverse('provider_site:apiuser-list')), + (_('API User Create'), ''), ) + + def get_cancel_url(self): + return reverse('provider_site:apiuser-list') + + +class APIUserUpdateForm(UserFormBase): + class Meta(UserFormBase.Meta): + fields = ('groups', 'is_active') + + +class APIUserUpdateView(NoCustomerMixin, generic_views.UpdateView): + model = User + template_name = 'provider_site/api_user_update_form.html' + form_class = APIUserUpdateForm + + def get_success_url(self): + return reverse('provider_site:apiuser-list') + + def get_cancel_url(self): + return reverse('provider_site:apiuser-list') + + def form_valid(self, form): + form.request = self.request + form.save() + return HttpResponseRedirect(self.get_success_url()) + + def get_breadcrumbs(self): + return ( + (_('API Users'), reverse('provider_site:apiuser-list')), + (self.object, ''), ) diff --git a/energymanager/start_site/__init__.py b/energymanager/start_site/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/start_site/context_processors.py b/energymanager/start_site/context_processors.py new file mode 100644 index 0000000..53d0f8a --- /dev/null +++ b/energymanager/start_site/context_processors.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from gridplatform.trackuser import get_user + +from .views import applist + + +def app_selection(request): + """ + Provide template context variable app_selection to make the list of apps + that the current user has access to avaiable in all templates. + """ + return { + 'app_selection': applist(request, get_user()), + } diff --git a/energymanager/start_site/locale/da/LC_MESSAGES/django.mo b/energymanager/start_site/locale/da/LC_MESSAGES/django.mo new file mode 100644 index 0000000..6628140 Binary files /dev/null and b/energymanager/start_site/locale/da/LC_MESSAGES/django.mo differ diff --git a/energymanager/start_site/locale/da/LC_MESSAGES/django.po b/energymanager/start_site/locale/da/LC_MESSAGES/django.po new file mode 100644 index 0000000..8bd70b2 --- /dev/null +++ b/energymanager/start_site/locale/da/LC_MESSAGES/django.po @@ -0,0 +1,122 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-10-23 14:38+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: views.py:33 templates/start_site/navbar.html:8 +msgid "SmartFlex" +msgstr "SmartFlex" + +#: views.py:37 templates/start_site/navbar.html:10 +msgid "Endesa Energy Portal" +msgstr "Endesa Energy Portal" + +#: views.py:41 +msgid "GridPortal 2.0" +msgstr "GridPortal 2.0" + +#: views.py:49 +msgid "Sales" +msgstr "Salg" + +#: views.py:54 +msgid "Configuration" +msgstr "Konfiguration" + +#: views.py:61 +msgid "Product List" +msgstr "Produktliste" + +#: views.py:67 +msgid "System Health" +msgstr "System Status" + +#: views.py:73 +msgid "Administration" +msgstr "Administration" + +#: views.py:79 +msgid "Energy Manager" +msgstr "Energy Manager" + +#: views.py:85 +msgid "Survey" +msgstr "Teknisk Opmåling" + +#: views.py:91 +msgid "Reporting" +msgstr "Indrapportering" + +#: views.py:97 +msgid "Tariff and Compensation" +msgstr "Tariffer og Afgiftsgodtgørelse" + +#: views.py:104 +msgid "Graphs" +msgstr "Grafer" + +#: templates/start_site/apps.html:15 +msgid "Welcome to SmartFlex, choose an app" +msgstr "Velkommen til SmartFlex, vælg en app" + +#: templates/start_site/apps.html:17 +msgid "Welcome to the Endesa Energy Portal, choose an app" +msgstr "Velkommen til Endesa Energy Portal, vælg en app" + +#: templates/start_site/apps.html:19 +msgid "Welcome to GridPortal, choose an app" +msgstr "Velkommen til GridPortalen, vælg en app" + +#: templates/start_site/apps.html:34 +msgid "or" +msgstr "eller" + +#: templates/start_site/apps.html:36 +msgid "Logout" +msgstr "Log ud" + +#: templates/start_site/base.html:13 +msgid "SmartFlex: Login" +msgstr "SmartFlex: Login" + +#: templates/start_site/base.html:15 +msgid "Endesa Energy Portal: Login" +msgstr "Endesa Energy Portal: Login" + +#: templates/start_site/base.html:17 +msgid "GridPortal: Login" +msgstr "GridPortal: Login" + +#: templates/start_site/login.html:16 +msgid "Login to SmartFlex" +msgstr "Log in på SmartFlex" + +#: templates/start_site/login.html:18 +msgid "Login to Endesa Energy Manager" +msgstr "Login til Endesa Energy Manager" + +#: templates/start_site/login.html:20 +msgid "Login to GridPortal" +msgstr "Log in på GridPortalen" + +#: templates/start_site/navbar.html:12 +msgid "GridPortal" +msgstr "GridPortal" + +#~ msgid "Admin" +#~ msgstr "Admin" diff --git a/energymanager/start_site/locale/es/LC_MESSAGES/django.mo b/energymanager/start_site/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000..ce692f0 Binary files /dev/null and b/energymanager/start_site/locale/es/LC_MESSAGES/django.mo differ diff --git a/energymanager/start_site/locale/es/LC_MESSAGES/django.po b/energymanager/start_site/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000..45d2336 --- /dev/null +++ b/energymanager/start_site/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,103 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-09-15 13:43+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: views.py:33 templates/start_site/navbar.html:8 +msgid "SmartFlex" +msgstr "" + +#: views.py:37 +msgid "GridPortal 2.0" +msgstr "" + +#: views.py:45 +msgid "Sales" +msgstr "" + +#: views.py:50 +msgid "Configuration" +msgstr "" + +#: views.py:57 +msgid "Product List" +msgstr "" + +#: views.py:63 +msgid "System Health" +msgstr "" + +#: views.py:69 +msgid "Administration" +msgstr "" + +#: views.py:75 +msgid "Energy Manager" +msgstr "" + +#: views.py:81 +msgid "Survey" +msgstr "" + +#: views.py:87 +msgid "Reporting" +msgstr "" + +#: views.py:93 +msgid "Tariff and Compensation" +msgstr "" + +#: views.py:100 +msgid "Graphs" +msgstr "" + +#: templates/start_site/apps.html:15 +msgid "Welcome to SmartFlex, choose an app" +msgstr "" + +#: templates/start_site/apps.html:17 +msgid "Welcome to GridPortal, choose an app" +msgstr "" + +#: templates/start_site/apps.html:32 +msgid "or" +msgstr "" + +#: templates/start_site/apps.html:34 +msgid "Logout" +msgstr "" + +#: templates/start_site/base.html:13 +msgid "SmartFlex: Login" +msgstr "" + +#: templates/start_site/base.html:15 +msgid "GridPortal: Login" +msgstr "" + +#: templates/start_site/login.html:16 +msgid "Login to SmartFlex" +msgstr "" + +#: templates/start_site/login.html:18 +msgid "Login to GridPortal" +msgstr "" + +#: templates/start_site/navbar.html:10 +msgid "GridPortal" +msgstr "" diff --git a/energymanager/start_site/locale/es/LC_MESSAGES/djangojs.po b/energymanager/start_site/locale/es/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/start_site/models.py b/energymanager/start_site/models.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/start_site/static/start_site/images/administration_icon.png b/energymanager/start_site/static/start_site/images/administration_icon.png new file mode 100644 index 0000000..89645d7 Binary files /dev/null and b/energymanager/start_site/static/start_site/images/administration_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/configuration_icon.png b/energymanager/start_site/static/start_site/images/configuration_icon.png new file mode 100644 index 0000000..74b6cbd Binary files /dev/null and b/energymanager/start_site/static/start_site/images/configuration_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/energy_manager_icon.png b/energymanager/start_site/static/start_site/images/energy_manager_icon.png new file mode 100644 index 0000000..0065cc5 Binary files /dev/null and b/energymanager/start_site/static/start_site/images/energy_manager_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/graph_icon.png b/energymanager/start_site/static/start_site/images/graph_icon.png new file mode 100644 index 0000000..a52b67b Binary files /dev/null and b/energymanager/start_site/static/start_site/images/graph_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/led_light_icon.png b/energymanager/start_site/static/start_site/images/led_light_icon.png new file mode 100644 index 0000000..ca7d7e4 Binary files /dev/null and b/energymanager/start_site/static/start_site/images/led_light_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/portal2_icon.png b/energymanager/start_site/static/start_site/images/portal2_icon.png new file mode 100644 index 0000000..a6924ac Binary files /dev/null and b/energymanager/start_site/static/start_site/images/portal2_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/product_list_icon.png b/energymanager/start_site/static/start_site/images/product_list_icon.png new file mode 100644 index 0000000..d5fb437 Binary files /dev/null and b/energymanager/start_site/static/start_site/images/product_list_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/reporting_icon.png b/energymanager/start_site/static/start_site/images/reporting_icon.png new file mode 100644 index 0000000..100780c Binary files /dev/null and b/energymanager/start_site/static/start_site/images/reporting_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/sales_icon.png b/energymanager/start_site/static/start_site/images/sales_icon.png new file mode 100644 index 0000000..28610b9 Binary files /dev/null and b/energymanager/start_site/static/start_site/images/sales_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/survey_icon.png b/energymanager/start_site/static/start_site/images/survey_icon.png new file mode 100644 index 0000000..7661ed2 Binary files /dev/null and b/energymanager/start_site/static/start_site/images/survey_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/system_health_icon.png b/energymanager/start_site/static/start_site/images/system_health_icon.png new file mode 100644 index 0000000..27aa270 Binary files /dev/null and b/energymanager/start_site/static/start_site/images/system_health_icon.png differ diff --git a/energymanager/start_site/static/start_site/images/tariff_and_compensation_icon.png b/energymanager/start_site/static/start_site/images/tariff_and_compensation_icon.png new file mode 100644 index 0000000..9bf2863 Binary files /dev/null and b/energymanager/start_site/static/start_site/images/tariff_and_compensation_icon.png differ diff --git a/energymanager/start_site/templates/start_site/apps.html b/energymanager/start_site/templates/start_site/apps.html new file mode 100644 index 0000000..d50580e --- /dev/null +++ b/energymanager/start_site/templates/start_site/apps.html @@ -0,0 +1,43 @@ +{% extends "start_site/base.html"%} +{% load i18n %} +{% load bootstrap_tags %} +{% load widget_tweaks %} + +{% block content %} +{% include "start_site/navbar.html" %} +
+
+
+
+ +
+
+
+
+{% endblock content %} diff --git a/energymanager/start_site/templates/start_site/base.html b/energymanager/start_site/templates/start_site/base.html new file mode 100644 index 0000000..248c8db --- /dev/null +++ b/energymanager/start_site/templates/start_site/base.html @@ -0,0 +1,75 @@ +{% spaceless %} +{% load i18n %} +{% load version %} +{% load static from staticfiles %} +{% load compress %} + + + + + + {% block page_title %} + {% if request.get_host == "portal.smartflex.dk" %} + {% trans "SmartFlex: Login" %} + {% elif request.get_host == "endesa.grid-manager.com" %} + {% trans "Endesa Energy Portal: Login" %} + {% else %} + {% trans "SC-Portal: Login" %} + {% endif %} + {% endblock %} + + + {% if bootstrap_theme == 'genius' %} + {% compress css %} + + + + + + + + + {% endcompress %} + {% endif %} + {% compress css %} + + + + {% endcompress %} + {# custom css #} + {% block site_css %}{% endblock site_css %} + {% block page_css %}{% endblock page_css %} + {% compress js %} + {# js... #} + + + + + + + + + {% endcompress %} + {% if bootstrap_theme == 'genius' %} + {% compress js %} + + + + + + + {% endcompress %} + {% endif %} + + {% compress js %} + + {% endcompress %} + {% block site_js %}{% endblock site_js %} + {% block page_js %}{% endblock page_js %} + + + {% block content %}{% endblock content %} + {% include "users/_user_profile_modal.html" %} + + +{% endspaceless %} diff --git a/energymanager/start_site/templates/start_site/login.html b/energymanager/start_site/templates/start_site/login.html new file mode 100644 index 0000000..c9acb04 --- /dev/null +++ b/energymanager/start_site/templates/start_site/login.html @@ -0,0 +1,58 @@ +{% extends "start_site/base.html"%} +{% load i18n %} +{% load bootstrap_tags %} +{% load widget_tweaks %} +{% load version %} + +{% block content %} +
+
+
+
+ +
+
+
+
+{% endblock content %} diff --git a/energymanager/start_site/templates/start_site/navbar.html b/energymanager/start_site/templates/start_site/navbar.html new file mode 100644 index 0000000..ba2a1d2 --- /dev/null +++ b/energymanager/start_site/templates/start_site/navbar.html @@ -0,0 +1,14 @@ +{% extends "bootstrap/_navbar_base.html" %} +{% load i18n %} + +{% block menu_button %}{% endblock %} +{% block home_url %}{% url 'start_site:apps' %}{% endblock %} +{% block title %} +{% if request.get_host == "portal.smartflex.dk" %} + {% trans "SmartFlex" %} +{% elif request.get_host == "endesa.grid-manager.com" %} + {% trans "Endesa Energy Portal" %} +{% else %} + {% trans "SC-Portal" %} +{% endif %} +{% endblock %} diff --git a/energymanager/start_site/tests.py b/energymanager/start_site/tests.py new file mode 100644 index 0000000..e69de29 diff --git a/energymanager/start_site/urls.py b/energymanager/start_site/urls.py new file mode 100644 index 0000000..037194e --- /dev/null +++ b/energymanager/start_site/urls.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.conf.urls import patterns, url + +from energymanager.start_site import views + +urlpatterns = patterns( + 'legacy.website.views', + url(r'^login/$', views.LoginView.as_view(), name='login'), + url(r'^apps/$', views.AppsView.as_view(), name='apps'), +) diff --git a/energymanager/start_site/views.py b/energymanager/start_site/views.py new file mode 100644 index 0000000..07b83fc --- /dev/null +++ b/energymanager/start_site/views.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +import urlparse + +from django.conf import settings +from django.http import HttpResponseRedirect +from django.contrib.auth.forms import AuthenticationForm +from django.contrib.auth import REDIRECT_FIELD_NAME +from django.contrib.auth import login as auth_login +from django.contrib.sites.models import get_current_site +from django.views.generic import FormView +from django.views.generic import TemplateView +from django.utils.translation import ugettext as _ +from django.core.urlresolvers import reverse +from django.contrib.staticfiles.templatetags.staticfiles import static + +from gridplatform.trackuser import get_provider_id +from gridplatform.trackuser import replace_selected_customer + + +def applist(request, user): + """ + Returns a list off apps that the loggedin user has access to + """ + + with replace_selected_customer(None): + app_selection = [] + + app_selection.append( + {'name': _('SC-Portal 2.0'), 'url': reverse('website-home'), + 'icon': static('start_site/images/portal2_icon.png')}) + + if user is None: + return app_selection + + if user.has_perm('users.access_provider_site') and get_provider_id(): + app_selection.append( + {'name': _('Administration'), + 'url': reverse('provider_site:home'), + 'icon': static('start_site/images/administration_icon.png')}) + + app_selection.append( + {'name': _('Configuration'), + 'url': reverse('configuration_site:home'), + 'icon': static('start_site/images/administration_icon.png')}) + + if user.has_perm('users.access_led_light_site'): + app_selection.append( + {'name': _('LED Light'), + 'url': reverse('led_light_site:home'), + 'icon': static('start_site/images/led_light_icon.png')}) + + if user.has_perm('users.access_project_site'): + app_selection.append( + {'name': _('ESCo Lite'), + 'url': reverse('project_site:home'), + 'icon': static('start_site/images/energy_manager_icon.png')}) + + if user.has_perm('users.access_price_relay_site'): + app_selection.append( + {'name': _('Price Relay'), + 'url': reverse('price_relay_site:home'), + 'icon': static('start_site/images/energy_manager_icon.png')}) + + if user.has_perm('users.access_datahub_site'): + app_selection.append( + {'name': _('Datahub'), + 'url': reverse('datahub_site:home'), + 'icon': static('start_site/images/energy_manager_icon.png')}) + + return app_selection + + +class LoginView(FormView): + template_name = "start_site/login.html" + form_class = AuthenticationForm + + def dispatch(self, request, *args, **kwargs): + self.redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '') + request.session.set_test_cookie() + self.current_site = get_current_site(request) + + return super( + LoginView, self).dispatch(request, *args, **kwargs) + + def form_valid(self, form): + # login user + user = form.get_user() + auth_login(self.request, user) + + netloc = urlparse.urlparse(self.redirect_to)[1] + + # Use applist or default setting if self.redirect_to is empty + if not self.redirect_to: + app_selection = applist(self.request, user) + if len(app_selection) == 1: + self.redirect_to = app_selection[0]['url'] + else: + self.redirect_to = settings.LOGIN_REDIRECT_URL + + # Heavier security check -- don't allow redirection to a different + # host. + elif netloc and netloc != self.request.get_host(): + self.redirect_to = settings.LOGIN_REDIRECT_URL + + if self.request.session.test_cookie_worked(): + self.request.session.delete_test_cookie() + + return HttpResponseRedirect(self.redirect_to) + + def render_to_response(self, context, **response_kwargs): + context.update( + {'REDIRECT_FIELD_NAME': self.redirect_to, + 'site': self.current_site, + 'site_name': self.current_site.name, }) + + return super( + LoginView, self).render_to_response(context, **response_kwargs) + + +class AppsView(TemplateView): + template_name = "start_site/apps.html" diff --git a/fabfile.py b/fabfile.py new file mode 100644 index 0000000..591fa97 --- /dev/null +++ b/fabfile.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +from cStringIO import StringIO + +from fabric.api import cd +from fabric.api import env +from fabric.api import execute +from fabric.api import get +from fabric.api import local +from fabric.api import parallel +from fabric.api import put +from fabric.api import roles +from fabric.api import run +from fabric.api import runs_once +from fabric.api import serial +from fabric.api import task + + +env.user = 'portal' + +env.roledefs['web'] = [ + '{}.grid-manager.com'.format(name) + for name in ('web1', 'web2', 'web3', 'web4', 'web5') +] +env.roledefs['gas'] = ['gas.grid-manager.com'] +env.roledefs['engine'] = ['engine.grid-manager.com'] + +env.roledefs['staging'] = ['192.168.0.150'] +env.roledefs['experimental'] = ['experimental.grid-manager.com'] +#env.roledefs['production'] = ['portal@185.121.173.146'] +env.roledefs['production'] = ['portal@smarterconsumers.dk'] + +SCRIPT_DIR = 'gridplatform/scripts/production_nordic' + + +@runs_once +def get_version(): + return local('git describe --always', capture=True) + + +@runs_once +def get_distfilename(): + return 'gridplatform-{}.tar.gz'.format(get_version()) + + +@runs_once +def build_distfile(distfilename): + local('make {}'.format(distfilename)) + + +@parallel +@roles('web', 'gas', 'engine') +def upload(distfilename): + put(distfilename, distfilename) + + +def unpack(distfilename): + run('rm -rf gridplatform.old') + run('mv gridplatform gridplatform.old') + run('tar xzf {}'.format(distfilename)) + + +def pip_setup(): + run('source $HOME/ve/bin/activate && ' + + 'pip install -r gridplatform/requirements/production.txt') + + +@parallel +@roles('web') +def stop_web(): + with cd(SCRIPT_DIR): + run('./stop_celery.sh') + run('./stop_uwsgi.sh') + + +@parallel +@roles('web') +def unpack_web(distfilename): + execute(unpack, distfilename) + + +@parallel +@roles('web') +def setup_web(): + execute(pip_setup) + with cd(SCRIPT_DIR): + run('./manage.sh collectstatic --noinput') + run('./manage.sh compress') + + +@parallel +@roles('web') +def start_web(): + with cd(SCRIPT_DIR): + run('./start_celery.sh') + run('./start_uwsgi.sh') + + +@roles('engine') +def stop_engine(): + with cd(SCRIPT_DIR): + run('./stop_reports.sh') + run('killall python') + + +@roles('engine') +def unpack_engine(distfilename): + execute(unpack, distfilename) + + +@roles('engine') +def setup_engine(): + execute(pip_setup) + + +@roles('engine') +def start_engine(): + with cd(SCRIPT_DIR): + run('./start_reports.sh') + run('./manage.sh ruleengine') + + +@roles('gas') +def stop_gas(): + run('gridplatform/gridagentserver/stop.sh') + + +@roles('gas') +def unpack_gas(distfilename): + execute(unpack, distfilename) + + +@roles('gas') +def setup_gas(): + execute(pip_setup) + run('source $HOME/ve/bin/activate && ' + + 'pip install -r gridplatform/gridagentserver/requirements.txt') + with cd(SCRIPT_DIR): + run('./manage.sh syncdb --migrate') + run('./manage.sh fix_contenttypes_and_permissions') + + +@roles('gas') +def start_gas(): + run('export DJANGO_CONFIGURATION=Prod && ' + + 'source $HOME/ve/bin/activate && ' + + '$HOME/gridplatform/gridagentserver/start.sh') + + +@task +@serial +def deploy_nordic(): + """ + Deploy to the GridManager Nordic cloud. + """ + distfilename = get_distfilename() + execute(build_distfile, distfilename) + execute(upload, distfilename) + + execute(stop_engine) + execute(unpack_engine, distfilename) + + execute(stop_gas) + execute(unpack_gas, distfilename) + execute(setup_gas) + execute(start_gas) + + execute(setup_engine) + execute(start_engine) + + execute(stop_web) + execute(unpack_web, distfilename) + execute(setup_web) + execute(start_web) + + +def deploy_singleserver(): + distfilename = get_distfilename() + execute(build_distfile, distfilename) + put(distfilename, distfilename) + # stop + with cd('gridplatform/scripts/production'): + run('./stop_celery.sh', warn_only=True) + run('./stop_uwsgi.sh', warn_only=True) + run('./stop_reports.sh', warn_only=True) + run('gridplatform/gridagentserver/stop.sh', warn_only=True) + run('killall python', warn_only=True) + # unpack + execute(unpack, distfilename) + # setup + execute(pip_setup) + run('source $HOME/ve/bin/activate && ' + + 'pip install -r gridplatform/gridagentserver/requirements.txt') + with cd('gridplatform/scripts/production'): + run('./manage.sh syncdb --migrate') + run('./manage.sh fix_contenttypes_and_permissions') + run('./manage.sh collectstatic --noinput') + run('./manage.sh compress') + # start + with cd('gridplatform/scripts/production'): + run('./start_celery.sh') + run('./start_uwsgi.sh') + run('./start_reports.sh') + run('./manage.sh ruleengine') + run('export DJANGO_CONFIGURATION=Local && ' + + 'source $HOME/ve/bin/activate && ' + + '$HOME/gridplatform/gridagentserver/start.sh') + + +@task +@roles('staging') +def deploy_staging(): + execute(deploy_singleserver) + + +@task +@roles('experimental') +def deploy_experimental(): + execute(deploy_singleserver) + + +@task +@roles('production') +def deploy_production(): + execute(deploy_singleserver) + + +@parallel +@roles('web', 'gas', 'engine', 'staging', 'experimental', 'iberia') +def deployed_versions(): + data = StringIO() + get('gridplatform/gridplatform/__init__.py', data) + for line in data.getvalue().split('\n'): + if line.startswith('__version__'): + version = line.split()[-1] + return version + return None + + +@task +def check_versions(): + """ + Check software versions currently deployed. + """ + versions = execute(deployed_versions) + for host, version in sorted(versions.items()): + print '{}: {}'.format(host, version) diff --git a/fixture_hack.py b/fixture_hack.py new file mode 100644 index 0000000..5e94102 --- /dev/null +++ b/fixture_hack.py @@ -0,0 +1,450 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +# +# ./manage.py syncdb --noinput +# ./manage.py create_encrypted_user root feet +# ./manage.py create_encrypted_user super 123 +# ./manage.py create_encrypted_user test 123 +# +# python fixture_hack.py + +import datetime +from decimal import Decimal +import math +import os +import pytz + + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gridplatform.settings.local") + +from legacy.measurementpoints.models import Collection +from gridplatform.customers.models import Customer +from legacy.measurementpoints.models import Location +from legacy.measurementpoints.proxies import ConsumptionMeasurementPoint +from legacy.measurementpoints.proxies import TemperatureMeasurementPoint +from gridplatform.encryption.testutils import encryption_context +from gridplatform.providers.models import Provider +from gridplatform.users.models import User +from gridplatform.utils import utilitytypes +from legacy.devices.models import Agent +from legacy.devices.models import Meter +from legacy.devices.models import PhysicalInput +from legacy.devices.models import RawData +from legacy.devices.models import SoftwareImage +from legacy.indexes.models import Index +from legacy.measurementpoints.fields import DataRoleField +from legacy.measurementpoints.models import CostCalculation +from legacy.measurementpoints.models import DataSeries + + +def create_customer(): + customer = Customer() + customer.provider_id = 1 + customer.name_plain = 'test customer' + customer.vat_plain = '4242' + customer.address_plain = 'address' + customer.postal_code_plain = '1234' + customer.city_plain = 'city' + customer.phone_plain = '12341234' + customer.country_code_plain = 'dnk' + customer.timezone = pytz.timezone('Europe/Copenhagen') + customer.contact_name_plain = '' + customer.contact_email_plain = '' + customer.contact_phone_plain = '' + customer.created_by = User.objects.get(id=1) + customer.save() + return customer + + +def setup_users(customer): + superuser = User.objects.create_user( + 'super', '123', + user_type=User.CUSTOMER_SUPERUSER, + customer=customer) + testuser = User.objects.create_user( + 'test', '123', + user_type=User.CUSTOMER_USER, + customer=customer) + + superuser.is_staff = False + superuser.is_superuser = True + superuser.save() + + testuser.is_staff = False + testuser.is_superuser = False + testuser.save() + + +def create_location(customer): + location = Location(customer=customer, name_plain='test location') + location.save() + return location + + +def create_agent(customer, location): + agent = Agent( + customer=customer, location=location, mac='08:00:27:03:fe:c7', + device_type=1, hw_major=5, hw_minor=0, hw_revision=0, + sw_major=2, sw_minor=2, sw_revision=1, sw_subrevision='fixture', + online=True) + agent.save() + return agent + + +def create_meter(agent, manufactoring_id, connection_type, name): + customer = agent.customer + location = agent.location + meter = Meter( + customer=customer, + agent=agent, + manufactoring_id=manufactoring_id, + connection_type=connection_type, + location=location, + name_plain=name, + relay_enabled=True, + online=True) + meter.save() + return meter + + +def create_meters(agent): + kamstrup_meter = create_meter( + agent, 155173425101, Meter.GRIDLINK, + 'Kamstrup meter') + mbus_meter = create_meter( + agent, 1980720117449728, Meter.GRIDLINK, + 'Mbus meter') + meter = create_meter( + agent, 456789, Meter.GRIDLINK, + 'ZigBee elec. test meter') + gas = create_meter( + agent, 456790, Meter.GRIDLINK, + 'ZigBee gas meter') + heat = create_meter( + agent, 456791, Meter.GRIDLINK, + 'ZigBee heat meter') + water = create_meter( + agent, 456792, Meter.GRIDLINK, + 'ZigBee water meter') + gridlink = create_meter( + agent, 456793, Meter.GRIDLINK, + 'GridLink') + return kamstrup_meter, mbus_meter, meter, gas, heat, water, gridlink + + +def create_physicalinputs(kamstrup_meter, mbus_meter, meter, gas, heat, + water, gridlink): + accum = PhysicalInput( + customer=mbus_meter.customer, + unit='milliwatt*hour', type=1, + meter=mbus_meter, order=0, + name_plain='M-Bus consumption') + accum.save() + power = PhysicalInput( + customer=mbus_meter.customer, + unit='milliwatt', type=1, + meter=mbus_meter, order=0, name_plain='M-Bus power') + power.save() + current = PhysicalInput( + customer=mbus_meter.customer, + unit='milliampere', type=1, + meter=mbus_meter, order=0, + name_plain='M-Bus current') + current.save() + voltage = PhysicalInput( + customer=mbus_meter.customer, + unit='millivolt', type=1, + meter=mbus_meter, order=0, + name_plain='M-Bus voltage') + voltage.save() + physicalinput = PhysicalInput( + customer=meter.customer, + unit='impulse', + type=PhysicalInput.UNKNOWN_ORIGIN, + meter=meter, order=2, + name_plain='Pulse meter') + physicalinput.save() + + gas = PhysicalInput( + customer=gas.customer, + unit='milliliter', + type=PhysicalInput.UNKNOWN_ORIGIN, meter=gas, order=0, + name_plain="Gas consumption") + gas.save() + + heat = PhysicalInput( + customer=heat.customer, + unit='milliwatt*hour', + type=PhysicalInput.DISTRICT_HEATING, meter=heat, order=0, + name_plain="Heat consumption") + heat.save() + + water = PhysicalInput( + customer=water.customer, + unit='milliliter', + type=PhysicalInput.WATER, meter=water, + order=0, name_plain="Water consumption") + water.save() + + gl1 = PhysicalInput( + customer=gridlink.customer, + unit='impulse', + type=PhysicalInput.UNKNOWN_ORIGIN, meter=gridlink, + order=0, name_plain="GridLink input 1") + gl2 = PhysicalInput( + customer=gridlink.customer, + unit='impulse', + type=PhysicalInput.UNKNOWN_ORIGIN, meter=gridlink, + order=1, name_plain="GridLink input 2") + gl3 = PhysicalInput( + customer=gridlink.customer, + unit='impulse', + type=PhysicalInput.UNKNOWN_ORIGIN, meter=gridlink, + order=2, name_plain="GridLink input 3") + gl1.save() + gl2.save() + gl3.save() + + powerfactor = PhysicalInput( + customer=mbus_meter.customer, + unit='millinone', type=1, + meter=mbus_meter, order=0, + name_plain='M-Bus Power Factor') + powerfactor.save() + + return accum, power, physicalinput, heat + + +def create_groups(customer): + collection = Collection( + customer=customer, + name_plain='Hal A', + role=Collection.GROUP, + utility_type=utilitytypes.OPTIONAL_METER_CHOICES.unknown) + collection.save() + + collection = Collection( + customer=customer, + name_plain='Hal B', + role=Collection.GROUP, + utility_type=utilitytypes.OPTIONAL_METER_CHOICES.unknown) + collection.save() + + collection = Collection( + customer=customer, + parent=collection, + name_plain='Hal C', + role=Collection.GROUP, + utility_type=utilitytypes.OPTIONAL_METER_CHOICES.unknown) + collection.save() + + collection = Collection.objects.get(id=1) + + return collection + + +def create_indexes(): + timezone = pytz.timezone("Europe/Copenhagen") + + elindex = Index( + unit="currency_dkk*kilowatt^-1*hour^-1", + role=DataRoleField.ELECTRICITY_TARIFF, + utility_type=utilitytypes.OPTIONAL_METER_CHOICES.electricity, + data_format=Index.SPOT, + name_plain="Random el", + timezone=timezone) + elindex.save() + + start_time = timezone.localize(datetime.datetime.now()).replace( + hour=0, minute=0, second=0, microsecond=0) + current_time = start_time + for i in range(24 * 7): + elindex.entry_set.create( + from_timestamp=current_time, + to_timestamp=current_time + datetime.timedelta(hours=1), + value=Decimal(0.3 * math.sin(i * 7.0 / 24.0) + 0.3)) + current_time += datetime.timedelta(hours=1) + + gasindex = Index( + unit="currency_dkk*liter^-1", + role=DataRoleField.GAS_TARIFF, + utility_type=utilitytypes.OPTIONAL_METER_CHOICES.gas, + data_format=Index.SPOT, + name_plain="Random Gas", + timezone=timezone) + gasindex.save() + + start_time = timezone.localize(datetime.datetime.now()).replace( + hour=0, minute=0, second=0, microsecond=0) + current_time = start_time + for i in range(24 * 7): + gasindex.entry_set.create( + from_timestamp=current_time, + to_timestamp=current_time + datetime.timedelta(hours=1), + value=Decimal(0.1 * math.sin(i * 3.0 / 24.0) + 0.15)) + current_time += datetime.timedelta(hours=1) + + return elindex, gasindex + + +def create_swimage(): + swimage = SoftwareImage(device_type=1, + hw_major=5, hw_minor=0, hw_revision=0, + sw_major=2, sw_minor=2, sw_revision=1) + swimage.save() + return swimage + + +def main(): + root = User.objects.create_user( + 'root', 'feet', + user_type=User.ADMIN) + root.is_staff = True + root.is_superuser = True + root.save() + + Provider.objects.create(name_plain='GridManager Energy Service') + + customer = create_customer() + setup_users(customer) + from gridplatform.trackuser import _set_customer + _set_customer(customer) + location = create_location(customer) + agent = create_agent(customer, location) + kamstrup_meter, mbus_meter, meter, gas, heat, water, gridlink = \ + create_meters(agent) + accum, power, physicalinput, heat_accum = create_physicalinputs( + kamstrup_meter, mbus_meter, meter, gas, heat, water, gridlink) + + ph_production = meter.physicalinput_set.create( + customer=meter.customer, + unit='milliwatt*hour', + type=PhysicalInput.ELECTRICITY, + order=10, + name_plain='Production data') + from productiondata import MEASUREMENTS + RawData.objects.bulk_create( + [ + RawData( + datasource=ph_production, + value=value, + timestamp=timestamp) + for timestamp, value in MEASUREMENTS]) + + collection = create_groups(customer) + + mpa = ConsumptionMeasurementPoint( + customer=customer, parent=collection, + name_plain='Lighting', + role=Collection.CONSUMPTION_MEASUREMENT_POINT, + utility_type=utilitytypes.OPTIONAL_METER_CHOICES.electricity) + + from gridplatform.consumptions.models import NonpulsePeriod + from legacy.datasequence_adapters.models import ConsumptionAccumulationAdapter # noqa + period = NonpulsePeriod.objects.get(datasource=accum) + ds = ConsumptionAccumulationAdapter.objects.get( + datasequence__period=period) + mpa.consumption_input = ds + mpa.consumption.customer = customer + mpa.save() + mpa.enable_rate = True + + meter = Meter.objects.get(manufactoring_id=456789) + mpa.relay = meter + mpa.save() + + mpb = ConsumptionMeasurementPoint( + customer=customer, parent=collection, name_plain='Production', + role=Collection.CONSUMPTION_MEASUREMENT_POINT, + utility_type=utilitytypes.OPTIONAL_METER_CHOICES.electricity) + + mpb.consumption_input = ds + mpb.consumption.customer = customer + mpb.save() + + mpc = ConsumptionMeasurementPoint( + customer=customer, parent=collection, + name_plain='Heating (total)', + role=Collection.CONSUMPTION_MEASUREMENT_POINT, + utility_type=utilitytypes.OPTIONAL_METER_CHOICES.district_heating) + period = NonpulsePeriod.objects.get(datasource=heat_accum) + ds = ConsumptionAccumulationAdapter.objects.get( + datasequence__period=period) + mpc.consumption_input = ds + mpc.consumption.customer = customer + mpc.save() + mpc.enable_rate = True + + create_indexes() + + tariff = DataSeries.objects.filter( + role=DataRoleField.ELECTRICITY_TARIFF)[0] + + cost_graph = mpa.graph_set.create( + role=DataRoleField.COST) + + CostCalculation.objects.create( + graph=cost_graph, + role=DataRoleField.COST, + utility_type=utilitytypes.OPTIONAL_METER_CHOICES.electricity, + unit="millicurrency_dkk", + customer=customer, + tariff=tariff, + consumption=mpa.consumption) + + create_swimage() + + temperature = PhysicalInput( + customer=meter.customer, + unit='millikelvin', + type=PhysicalInput.TEMPERATURE, + meter=meter, + order=3, + name_plain='Temperature input') + temperature.save() + + temperature_measurement_point = TemperatureMeasurementPoint( + name_plain='Outdoor temperature', + customer=customer, + parent=collection) + + assert customer + + from gridplatform.datasequences.models import NonaccumulationPeriod + from legacy.datasequence_adapters.models import NonaccumulationAdapter # noqa + period = NonaccumulationPeriod.objects.get(datasource=temperature) + ds = NonaccumulationAdapter.objects.get( + datasequence__period_set=period) + + temperature_measurement_point.input_configuration = ds + temperature_measurement_point.save() + + # The automatically created input periods will be have their from_timestamp + # initialized to creation time, which is naturally in real life, bug + # useless in this fixture setup: + import gridplatform.consumptions.models + gridplatform.consumptions.models.Period.objects.all().update( + from_timestamp=datetime.datetime(2000, 1, 1, tzinfo=pytz.utc)) + NonaccumulationPeriod.objects.all().update( + from_timestamp=datetime.datetime(2000, 1, 1, tzinfo=pytz.utc)) + + from django.contrib.auth.models import Group, Permission + all_permission_group = Group.objects.create(name='All permissions') + all_permissions = Permission.objects.all() + all_permission_group.permissions.add(*all_permissions) + + from gridplatform.customer_datasources.models import CustomerDataSource + from gridplatform.utils.units import ENERGY_PER_VOLUME_BASE_UNITS + conversion_rate = CustomerDataSource( + name_plain='conversion rate', + customer=customer, + unit=ENERGY_PER_VOLUME_BASE_UNITS[0]) + conversion_rate.save() + + +if __name__ == "__main__": + with encryption_context(): + main() diff --git a/fixture_hack.sh b/fixture_hack.sh new file mode 100755 index 0000000..3936eff --- /dev/null +++ b/fixture_hack.sh @@ -0,0 +1,52 @@ +#!/bin/bash +if [ -z "$VIRTUAL_ENV" ] +then + echo "ERROR: virtualenv not active" + exit -1 +fi + +# sudo -u postgres dropdb portal +if [ "$(uname)" == "Darwin" ] +then + dropdb -h localhost portal +else + dropdb portal +fi + +if [ $? -ne 0 ] +then + echo "ERROR: failed to drop database" + exit -1 +fi + +# sudo -u postgres createdb -O $USER portal +if [ "$(uname)" == "Darwin" ] +then + createdb -h localhost -E utf8 portal +else + createdb -E utf8 portal +fi +if [ $? -ne 0 ] +then + echo "ERROR: failed to recreate database" + exit -1 +fi + +echo 'Clearing memcached (old sessions...)' +echo 'flush_all' | telnet localhost 11211 + +set -e + +echo 'Clearing pyc-files' +find . -name '*.pyc' -delete + +echo 'Setting up tables' +gunzip -c initial.sql.gz | psql portal > /dev/null +./manage.py migrate --all --noinput --traceback +./manage.py fix_contenttypes_and_permissions + +echo 'Adding "fixture" data' +python fixture_hack.py +#python measurement_fixture.hack.py +#./manage.py loaddata salestool_data +echo 'done' diff --git a/forecast-daemon/__init__.py b/forecast-daemon/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/forecast-daemon/forecast b/forecast-daemon/forecast new file mode 100644 index 0000000..1803cc0 --- /dev/null +++ b/forecast-daemon/forecast @@ -0,0 +1,229 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: forecast +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start/stop forecast +### END INIT INFO + +NAME=forecast +DAEMONUSER="pi" +SYSCONF_PATH=/etc/default/ + +# If there's no configuration file, die!! +#[ ! -f $SYSCONF_PATH$NAME ] && echo "Fatal: cannot find $SYSCONF_FILE$NAME config file!" && exit 1 + +# Pull in the config settings and echo them out for easy troubleshooting. +#. $SYSCONF_PATH$NAME + +#[ ! -f $EMONHUB_CONFIG ] && echo "Fatal: cannot find $EMONHUB_CONFIG" && exit 1 +#[ ! -f $EMONHUB_PATH$NAME.py ] && echo "Fatal: cannot find $EMONHUB_PATH$NAME.py" && exit 1 +#[ ! -f $EMONHUB_LOG ] && sudo mkdir -p "$(dirname "$EMONHUB_LOG")" && sudo touch "$EMONHUB_LOG" && sudo chown -R $DAEMONUSER "$(dirname "$EMONHUB_LOG")" +#sudo chown -R $DAEMONUSER "$(dirname "$EMONHUB_LOG")" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="SCNordic Forecast" +# Enter your installation path here +DAEMON=/home/pi/ve/bin/python + +# Specify command line arguments here +DAEMON_ARGS="/home/pi/forecast/forecast.py --config-file /home/pi/forecast/forecast.conf" + +PIDFILE=/var/run/$NAME.pid +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || echo "Not starting - cannot find $DAEMON" || exit 1 + +# Exit if not run as root +case `id -u` in + 0) ;; + *) echo "This script must be run as root" >&2; exit 1 ;; +esac + +# Load the VERBOSE setting and other rcS variables +#. /lib/init/vars.sh +# Override VERBOSE setting +VERBOSE=yes + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() { + do_status + case "$?" in + 0) return 1 ;; + 1) rm -f $PIDFILE;; + 3) ;; + 4) PID=`ps -ef | grep '[p]ython '$DAEMON | awk '{ print $2 }'` + echo "$PID" > $PIDFILE;; + *) return "$?" ;; + esac + start-stop-daemon --start --quiet --background --make-pidfile --chuid=$DAEMONUSER --pidfile $PIDFILE --startas $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --background --no-close --make-pidfile --chuid=$DAEMONUSER --pidfile $PIDFILE --startas $DAEMON -- \ + $DAEMON_ARGS \ + || return 2 + # Add code here, if necessary, that waits for the process to be ready + # to handle requests from services started subsequently which depend + # on this one. As a last resort, sleep for some time. +} + +# +# Function that stops the daemon/service +# +do_stop() { + do_status + case "$?" in + 0) ;; + 1) rm -f $PIDFILE;; + 3) return 1 ;; + 4) PID=`ps -ef | grep '[p]ython '$DAEMON | awk '{ print $2 }'` + echo "$PID" > $PIDFILE;; + *) return "$?" ;; + esac + start-stop-daemon --stop --quiet --retry=INT/30/KILL/5 --pidfile $PIDFILE >/dev/null || RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + rm -f $PIDFILE + return "$?" +} + +# +# Function that restarts the daemon/service +# +do_restart() { + do_stop + case "$?" in + 0|1) ;; + *) return 2;; + esac + do_start + [ "$?" = 0 ] && return 0 + return 2 +} + +# +# Function that status checks the daemon/service +# +do_status() { + status="0" + pidofproc -p $PIDFILE $DAEMON >/dev/null || status="$?" + if [ "$status" = 3 ]; then + pid=`ps -ef | grep '[p]ython '$DAEMON | awk '{ print $2 }'` + [ "$pid" != "" ] && return 4 + fi + return $status +} + +# +# Function that sends a SIGHUP to the daemon/service +# +#do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # +# start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME +# return 0 +#} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0) [ "$VERBOSE" != no ] && log_progress_msg "has been started ok" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 1) [ "$VERBOSE" != no ] && log_progress_msg "is already running" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_progress_msg "start attempt" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + *) [ "$VERBOSE" != no ] && log_progress_msg "error: $?" + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0) [ "$VERBOSE" != no ] && log_progress_msg "has been stopped ok" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 1) [ "$VERBOSE" != no ] && log_progress_msg "had already stopped" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_progress_msg "stop attempt" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + *) [ "$VERBOSE" != no ] && log_progress_msg "error: $?" + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + [ "$VERBOSE" != no ] && log_daemon_msg "Checking $DESC" "$NAME" + do_status + case "$?" in + 0) [ "$VERBOSE" != no ] && log_progress_msg "process is running" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 1) [ "$VERBOSE" != no ] && log_progress_msg "process has" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + 3) [ "$VERBOSE" != no ] && log_progress_msg "process not running" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 4) [ "$VERBOSE" != no ] && log_progress_msg "running but PID file has" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + *) [ "$VERBOSE" != no ] && log_progress_msg "status unknown as checks" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + [ "$VERBOSE" != no ] && log_daemon_msg "Restarting $DESC" "$NAME" + do_restart + case "$?" in + 0) [ "$VERBOSE" != no ] && log_progress_msg "has been restarted ok" + [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_progress_msg "restart attempt has" #failed + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + *) [ "$VERBOSE" != no ] && log_progress_msg "error: $?" + [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + killp) + # use only for crash testing - kills process without removing the pid file + # also used to "tidy up" a process that's missing it's pid file (eg if rmpid used) + # can be commented out or deleted, (not included in "Usage" help list). + pid=`ps -ef | grep '[p]ython '$DAEMON | awk '{ print $2 }'` + [ "$pid" != "" ] && kill -9 "${pid:-}" + ;; + rmpid) + # use only for crash testing - removes the pid file without killing process + # also used to "tidy up" a crashed process's redundant pid file (eg if killp used) + # can be commented out or deleted, (not included in "Usage" help list). + [ -e $PIDFILE ] && rm $PIDFILE + ;; + *) + #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: \ No newline at end of file diff --git a/forecast-daemon/forecast.conf b/forecast-daemon/forecast.conf new file mode 100644 index 0000000..e85c9c2 --- /dev/null +++ b/forecast-daemon/forecast.conf @@ -0,0 +1,2 @@ +url=http://192.168.1.69:8000/api/v3/pricerelays/ +api_key=6a091cd98ce0946f8b7c013aafa1565a038ce34b1779a7cecdf47128bcd403818416dc1bbf1330cd6198eee6891c95d3e68d3c9d \ No newline at end of file diff --git a/forecast-daemon/forecast.py b/forecast-daemon/forecast.py new file mode 100644 index 0000000..906c84e --- /dev/null +++ b/forecast-daemon/forecast.py @@ -0,0 +1,75 @@ +import argparse +import sys +import signal +import time + +import datetime +from RPi import GPIO + +from forecast_configuration import ForecastConfiguration +from relay_handler import RelayHandler +from request_handler import RequestHandler + + +class Forecast: + __version__ = "Forecast v0.1" + + def __init__(self, configuration): + self._exit = False + self.configuration = configuration + self.last_request_time = None + + def run(self): + signal.signal(signal.SIGINT, self._sigint_handler) + request = RequestHandler(self.configuration) + relay = RelayHandler(self.configuration) + forecast_data = None + + while not self._exit: + if not self.last_request_time or \ + datetime.datetime.now() >= self.last_request_time + datetime.timedelta(seconds=10): + new_data = request.fetch_forecast() + print new_data + if new_data: + forecast_data = new_data + self.last_request_time = datetime.datetime.now() + + relay.update_ports(forecast_data) + + time.sleep(0.2) + + def _sigint_handler(self, signal, frame): + self._exit = True + GPIO.cleanup() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="SC Nordic Forecast Relay") + + parser.add_argument("--config-file", action="store", help="Path to configuration file", default="forecast.conf") + + parser.add_argument("--version", action="store_true", help="Display version number") + + args = parser.parse_args() + + if args.version: + print Forecast.__version__ + sys.exit() + + configuration = None + try: + configuration = ForecastConfiguration(args.config_file) + + except Exception as e: + print e.message + sys.exit() + + try: + forecast = Forecast(configuration.configuration) + + except Exception as e: + print e.message + sys.exit("Could not start Forecast daemon") + else: + forecast.run() + diff --git a/forecast-daemon/forecast_configuration.py b/forecast-daemon/forecast_configuration.py new file mode 100644 index 0000000..a477f53 --- /dev/null +++ b/forecast-daemon/forecast_configuration.py @@ -0,0 +1,14 @@ +from configobj import ConfigObj + + +class ForecastConfiguration: + def __init__(self, config_path): + configuration = ConfigObj(config_path) + + self.validate_config(configuration) + + self.configuration = configuration + + def validate_config(self, configuration): + if "url" not in configuration or "api_key" not in configuration: + raise Exception("url or key not found in configuration file") diff --git a/forecast-daemon/relay_handler.py b/forecast-daemon/relay_handler.py new file mode 100644 index 0000000..a678248 --- /dev/null +++ b/forecast-daemon/relay_handler.py @@ -0,0 +1,59 @@ +from random import randint + +import datetime +import pytz +from RPi import GPIO + + +class RelayHandler: + + def __init__(self, configuration): + self.configuration = configuration + self.prev_port_setting = -1 + self.pins = [2, 3, 4, 17, 27, 22, 10, 9] + + GPIO.setmode(GPIO.BCM) + + for i in self.pins: + GPIO.setup(i, GPIO.OUT) + GPIO.output(i, GPIO.HIGH) + + def update_ports(self, forecast_data): + now = datetime.datetime.now().replace(tzinfo=pytz.utc) # + datetime.timedelta(hours=2) + port_setting = 0 + + if not forecast_data: + port_setting = 9 + else: + for setting in forecast_data: + print setting['timestamp'], now + if setting['timestamp'] < now < setting['timestamp'] + datetime.timedelta(hours=1): + print setting['timestamp'], setting['relay'] + port_setting = setting['relay'] + + if self.prev_port_setting != port_setting: + for i in self.pins: + GPIO.output(i, GPIO.HIGH) + + self.open_port(port_setting) + self.prev_port_setting = port_setting + + def open_port(self, port_number): + + if port_number == 0: + for i in self.pins: + GPIO.output(i, GPIO.LOW) + else: + self.set_port_state(port_number, GPIO.LOW) + + def close_port(self, port_number): + + self.set_port_state(port_number, GPIO.HIGH) + + def set_port_state(self, port_number, state): + if 0 < port_number < 9: + GPIO.output(self.pins[port_number - 1], state) + + + + diff --git a/forecast-daemon/request_handler.py b/forecast-daemon/request_handler.py new file mode 100644 index 0000000..f35dad2 --- /dev/null +++ b/forecast-daemon/request_handler.py @@ -0,0 +1,44 @@ +import requests +import dateutil.parser +from requests.auth import AuthBase + + +class TokenAuth(AuthBase): + """Attaches HTTP Token Authentication to the given Request object.""" + + def __init__(self, token): + # setup any auth-related data here + self.token = token + + def __call__(self, r): + # modify and return the request + r.headers['Authorization'] = "token %s" % self.token + return r + + +class RequestHandler: + def __init__(self, configuration): + self.configuration = configuration + self.auth = TokenAuth(self.configuration['api_key']) + + def fetch_forecast(self): + + try: + r = requests.get(self.configuration['url'], auth=self.auth, timeout=1) + except Exception as e: + print e.message + return None + + if r.status_code == requests.codes.ok: + response = r.json() + + if response['count'] == 1: + settings = [] + for setting in response['results'][0]['relaySettings']: + settings.append( + {'timestamp': dateutil.parser.parse(setting['timestamp']), 'relay': setting['relay']}) + return settings + else: + return None + else: + return None diff --git a/gridagentserver-protocol/.gitignore b/gridagentserver-protocol/.gitignore new file mode 100644 index 0000000..f50f8c8 --- /dev/null +++ b/gridagentserver-protocol/.gitignore @@ -0,0 +1,4 @@ +*~ +*.pyc +GridAgentServerProtocol.egg-info +_trial_temp/ diff --git a/gridagentserver-protocol/README b/gridagentserver-protocol/README new file mode 100644 index 0000000..15166e5 --- /dev/null +++ b/gridagentserver-protocol/README @@ -0,0 +1,11 @@ +This is the GridAgent Server communication protocol. + +Communication is message-based. +Messages have a common header with type, length and a field for Boolean where this may simplify the payload. +Apart from the initial handshake, communication is encrypted. +We use a pre-shared key, merged with a nonce from the agent to protect against playback attacks (and with the MAC address from the agent for slightly improved obscurity). +Currently, the set of messages sent by a server is disjoint from the set of messages sent by a client --- though the header is the same, and the type identifiers are global, so this may be changed later. + +The protocol has a version number, sent by both sides as part of the handshake. +At present, the server must handle version discrepencies, i.e. communication takes place with the protocol version specified by the client. + diff --git a/gridagentserver-protocol/gridagentserver_protocol/__init__.py b/gridagentserver-protocol/gridagentserver_protocol/__init__.py new file mode 100644 index 0000000..518f00c --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/__init__.py @@ -0,0 +1,5 @@ +# Protocol and library version will differ; protocol version is always an +# integer without any concept of major/minor versions... + +PROTOCOL_VERSION = 5 +SECRET = "jicWehirnEn2" diff --git a/gridagentserver-protocol/gridagentserver_protocol/client_messages.py b/gridagentserver-protocol/gridagentserver_protocol/client_messages.py new file mode 100644 index 0000000..1e0e8d8 --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/client_messages.py @@ -0,0 +1,350 @@ +"""Messages to be sent from the (virtual) agent to the GridAgent server.""" + +from struct import Struct +import logging + +from messages import Message, timestamp_to_datetime, datetime_to_timestamp +from datatypes import Meter, MeterData, MeasurementSet, Measurement, Version + + +logger = logging.getLogger(__name__) + +int32 = Struct('!i') +uint32 = Struct('!I') +int16 = Struct('!h') +uint16 = Struct('!H') +uint8 = Struct('!B') + + +# ZigBee timestamp, i.e. seconds since 2000-01-01 +timestamp_struct = Struct('!I') + +# major, minor, revision, extra string +version_struct = Struct('!BBB12s') + + +def normalise_version(version): + """ + Replace the received fixed-length "extra" string with its prefix before the + first \0 character. + """ + major, minor, revision, extra_bytes = version + extra_bytes = extra_bytes.split('\0', 1)[0] + extra = extra_bytes.decode('iso8859-1') + return (major, minor, revision, extra) + + +class BulkMeasurements(Message): + # ID, timestamp, value + measurement1_struct = Struct('!qIq') + # type, unit, input_number, value + measurement2_struct = Struct('!bbbq') + # connection_type, ID + meter2_struct = Struct('!bq') + + def __init__(self, meter_data): + self.meter_data = meter_data + + def __cmp__(self, other): + return cmp(self.meter_data, other.meter_data) + + def __hash__(self): + return hash(self.meter_data) + + @classmethod + def unpack(cls, header, read, version): + if version == 1: + return cls.unpack_1(read) + else: + return cls.unpack_2(read) + + # meter id, connection_type --- ver1 only id... + @classmethod + def unpack_1(cls, read): + def group_ids(acc, elem): + id, timestamp, value = elem + if not acc: + acc = [(id, [(timestamp, value)])] + else: + old_id = acc[-1][0] + if id == old_id: + acc[-1][1].append((timestamp, value)) + else: + acc.append((id, [(timestamp, value)])) + return acc + count, = read(uint32) + # [(id, timestamp, value), ...] + raw_list = read(cls.measurement1_struct, count) + raw_list.sort() + # to [(id, [(timestamp, value), ...]), ...] + data = reduce(group_ids, raw_list, []) + meter_data = [] + for meter_id, measurements in data: + meter = Meter(0, meter_id) + measurement_sets = [ + MeasurementSet(timestamp_to_datetime(timestamp), + [Measurement(0, 0, 0, value)]) + for timestamp, value in measurements] + meter_data.append(MeterData(meter, measurement_sets)) + return cls(meter_data) + + @classmethod + def unpack_2(cls, read): + meter_data_count, = read(uint16) + meter_data = [] + for n in range(meter_data_count): + meter = Meter(*read(cls.meter2_struct)) + measurement_set_count, = read(uint16) + measurement_sets = [] + for m in range(measurement_set_count): + timestamp, = read(timestamp_struct) + measurement_count, = read(uint16) + measurements = [] + for l in range(measurement_count): + measurements.append( + Measurement(*read(cls.measurement2_struct))) + measurement_sets.append( + MeasurementSet(timestamp_to_datetime(timestamp), + measurements)) + meter_data.append(MeterData(meter, measurement_sets)) + return cls(meter_data) + + def pack(self, version): + if version < 2: + raise Exception("Not implemented for version {}".format(version)) + data = [] + data.append(uint16.pack(len(self.meter_data))) + for meter, measurement_sets in self.meter_data: + data.append(self.meter2_struct.pack(*meter)) + data.append(uint16.pack(len(measurement_sets))) + for timestamp, measurements in measurement_sets: + data.append(timestamp_struct.pack( + datetime_to_timestamp(timestamp))) + data.append(uint16.pack(len(measurements))) + data.extend([self.measurement2_struct.pack(*measurement) + for measurement in measurements]) + return self._pack(data, version) + + +class NotificationGaAddMode(Message): + def __init__(self, timestamp, in_add_mode): + self.timestamp = timestamp + self.in_add_mode = in_add_mode + + def __cmp__(self, other): + return cmp((self.timestamp, self.in_add_mode), + (other.timestamp, other.in_add_mode)) + + def __hash__(self): + return hash((self.timestamp, self.in_add_mode)) + + @classmethod + def unpack(cls, header, read, version): + timestamp = timestamp_to_datetime(*read(timestamp_struct)) + in_add_mode = bool(header.flags & 1) + return cls(timestamp, in_add_mode) + + def pack(self, version): + data = timestamp_struct.pack(datetime_to_timestamp(self.timestamp)) + return self._pack([data], version, int(self.in_add_mode)) + + +class NotificationGaTime(Message): + def __init__(self, timestamp): + self.timestamp = timestamp + + def __cmp__(self, other): + return cmp(self.timestamp, other.timestamp) + + def __hash__(self): + return hash(self.timestamp) + + @classmethod + def unpack(cls, header, read, version): + timestamp = timestamp_to_datetime(*read(timestamp_struct)) + return cls(timestamp) + + def pack(self, version): + data = timestamp_struct.pack(datetime_to_timestamp(self.timestamp)) + return self._pack([data], version) + + +class NotificationGaConnectedSet(Message): + # ID + meter1_struct = Struct('!q') + # connection_type, ID + meter2_struct = Struct('!bq') + # connection_type, ID, device type, device option, + # hw major, hw minor, hw revision, hw revisionstring + # sw major, sw minor, sw revision, sw revisionstring + meter4_struct = Struct('!BqBB' + 'BBB12s' + 'BBB12s') + + def __init__(self, meters, device_opts=None, versions=None): + self.meters = meters + self.device_opts = device_opts + self.versions = versions + + def __cmp__(self, other): + return cmp(self.meters, other.meters) + + def __hash__(self): + return hash(self.meters) + + @classmethod + def unpack(cls, header, read, version): + count, = read(uint32) + if version == 1: + meters = [Meter(0, id) for id, in read(cls.meter1_struct, count)] + return cls(meters) + elif version < 4: + meters = [Meter(*data) for data in read(cls.meter2_struct, count)] + return cls(meters) + else: + data = read(cls.meter4_struct, count) + meters = [Meter(elem[0], elem[1]) for elem in data] + device_opts = [(elem[2], elem[3]) for elem in data] + versions = [(Version(*elem[4:8]), Version(*elem[8:12])) + for elem in data] + return cls(meters, device_opts, versions) + + def pack(self, version): + if version < 2: + raise Exception("Not implemented for version {}".format(version)) + data = [uint32.pack(len(self.meters))] + data.extend([self.meter2_struct.pack(*meter) for meter in self.meters]) + return self._pack(data, version) + + +class NotificationGpState(Message): + # ID + meter1_struct = Struct('!q') + # connection_type, ID + meter2_struct = Struct('!bq') + + def __init__(self, meter, online, control_manual, relay_on, timestamp): + self.meter = meter + self.online = online + self.control_manual = control_manual + self.relay_on = relay_on + self.timestamp = timestamp + + def __cmp__(self, other): + return cmp((self.meter, self.timestamp, + self.online, self.control_manual, self.relay_on), + (other.meter, other.timestamp, + other.online, other.control_manual, other.relay_on)) + + def __hash__(self): + return hash((self.meter, self.timestamp, + self.online, self.control_manual, self.relay_on)) + + @classmethod + def unpack(cls, header, read, version): + online = bool(header.flags & 1) + control_manual = bool(header.flags & 2) + relay_on = bool(header.flags & 4) + timestamp = timestamp_to_datetime(*read(timestamp_struct)) + if version == 1: + id, = read(cls.meter1_struct) + meter = Meter(0, id) + else: + meter = Meter(*read(cls.meter2_struct)) + return cls(meter, online, control_manual, relay_on, timestamp) + + def pack(self, version): + if version < 2: + raise Exception("Not implemented for version {}".format(version)) + flags = self.online * 1 + self.control_manual * 2 + self.relay_on * 4 + data = [timestamp_struct.pack(datetime_to_timestamp(self.timestamp)), + self.meter2_struct.pack(*self.meter)] + return self._pack(data, version, flags) + + +class AcknowledgementGpSoftware(Message): + # no members... + @classmethod + def unpack(cls, header, read, version): + return cls() + + def pack(self, version): + return self._pack([], version) + + +class AcknowledgementGaSoftware(Message): + # no members... + @classmethod + def unpack(cls, header, read, version): + return cls() + + def pack(self, version): + return self._pack([], version) + + +class ErrorGpSoftware(Message): + # no members... + @classmethod + def unpack(cls, header, read, version): + return cls() + + def pack(self, version): + return self._pack([], version) + + +class ErrorGaSoftware(Message): + # no members... + @classmethod + def unpack(cls, header, read, version): + return cls() + + def pack(self, version): + return self._pack([], version) + + +class InfoAgentVersions(Message): + def __init__(self, sw_version, device_type, hw_revision, serial): + self.sw_version = sw_version + self.device_type = device_type + self.hw_revision = hw_revision + self.serial = serial + + @classmethod + def unpack(cls, header, read, version): + assert version >= 3 + sw_version = normalise_version(read(version_struct)) + device_type, = read(uint8) + hw_revision = normalise_version(read(version_struct)) + serial, = read(int32) + return cls(sw_version, device_type, hw_revision, serial) + + def pack(self, version): + assert version >= 3 + data = [version_struct.pack(*self.sw_version), + uint8.pack(self.device_type), + version_struct.pack(*self.hw_revision), + uint32.pack(self.serial)] + return self._pack(data, version) + + +class InfoEventLog(Message): + eventtext_struct = Struct('!128s') + + def __init__(self, timestamp, code, text): + self.timestamp = timestamp + self.code = code + self.text = text + + @classmethod + def unpack(cls, header, read, version): + timestamp_raw, = read(timestamp_struct) + timestamp = timestamp_to_datetime(timestamp_raw) + code, = read(int16) + text_raw, = read(cls.eventtext_struct) + text = text_raw.split('\0', 1)[0] + return cls(timestamp, code, text) + + def pack(self, version): + assert version >= 5 + data = [timestamp_struct.pack(datetime_to_timestamp(self.timestamp)), + int16.pack(self.code), + self.eventtext_struct.pack(self.text)] + return self._pack(data, version) diff --git a/gridagentserver-protocol/gridagentserver_protocol/client_messages_test.py b/gridagentserver-protocol/gridagentserver_protocol/client_messages_test.py new file mode 100644 index 0000000..f2e3154 --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/client_messages_test.py @@ -0,0 +1,226 @@ +import unittest +import datetime +import ctypes +from collections import namedtuple +from StringIO import StringIO +import random + +from messages import parse +from datatypes import MeterData, Meter, MeasurementSet, Measurement +import messages + +from client_messages import ( + BulkMeasurements, + NotificationGaAddMode, + NotificationGaTime, + NotificationGaConnectedSet, + NotificationGpState, +) + + +def parse_message(data, version): + stream = StringIO(data) + return parse(stream, version) + +ConnectionMock = namedtuple('ConnectionMock', ['agent_mac']) + +# NOTE: checking class names is perhaps silly, when what actually matters is +# the behaviour on message.process() --- but we really want to test parsing by +# itself, and checking the behaviour of process() requires a more complex test +# setup in that it may lead to more messages being sent, interaction with the +# database, interaction with the portal... + + +def cast_signed(val): + return ctypes.c_longlong(val).value + + +class TestParsingVersion1(unittest.TestCase): + def test_bulk_measurements(self): + data = str(bytearray([ + 0x00, 0x00, 0x00, 0x48, # length + 0x00, 0x00, # padding + 0, # type + 0x01, # flags (is last) + 0x00, 0x00, # padding + 0x00, 0x03, # count + 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB, # id + 0xAB, 0xCD, 0xAB, 0xCD, # timestamp + 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, # value + 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB, # id + 0xAB, 0xCD, 0xAB, 0xEF, # timestamp + 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, # value + 0xCC, 0xCC, 0xCC, 0xCC, 0xDD, 0xDD, 0xDD, 0xDD, # id + 0x12, 0x34, 0x12, 0x34, # timestamp + 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, # value + ])) + message = parse_message(data, 1) + self.assertEqual(len(message.meter_data), 2) + self.assertEqual(message.meter_data[0].meter.id, + cast_signed(0xAAAAAAAABBBBBBBB)) + self.assertEqual(message.meter_data[1].meter.id, + cast_signed(0xCCCCCCCCDDDDDDDD)) + self.assertEqual(len(message.meter_data[0].measurement_sets), 2) + self.assertEqual(len(message.meter_data[0].measurement_sets[0] + .measurements), 1) + self.assertEqual(message.meter_data[0].measurement_sets[0] + .measurements[0].type, 0) + self.assertEqual(message.meter_data[0].measurement_sets[0] + .measurements[0].unit, 0) + self.assertEqual(message.meter_data[0].measurement_sets[0] + .measurements[0].input_number, 0) + self.assertEqual(message.meter_data[0].measurement_sets[0] + .measurements[0].value, + cast_signed(0x0000000011111111)) + self.assertEqual(message.meter_data[0].measurement_sets[1] + .measurements[0].value, + cast_signed(0x0000000022222222)) + self.assertEqual(message.meter_data[1].measurement_sets[0] + .measurements[0].value, + cast_signed(0x0000000033333333)) + self.assertEqual(message.meter_data[0].measurement_sets[1].timestamp - + message.meter_data[0].measurement_sets[0].timestamp, + datetime.timedelta(seconds=34)) + self.assertEqual(message.__class__.__name__, 'BulkMeasurements') + + def test_notification_ga_add_mode(self): + data = str(bytearray([ + 0x00, 0x00, 0x00, 0x0C, # length + 0x00, 0x00, # padding + 11, # type + 0x00, # flags (not in add mode) + 0x00, 0x00, 0xA4, 0xB2, # time; 11:42:42 + ])) + message = parse_message(data, 1) + self.assertEqual(message.in_add_mode, False) + self.assertEqual(message.timestamp, + datetime.datetime(2000, 1, 1, 11, 42, 42)) + self.assertEqual(message.__class__.__name__, 'NotificationGaAddMode') + + def test_notification_ga_time(self): + data = str(bytearray([ + 0x00, 0x00, 0x00, 0x0C, # length + 0x00, 0x00, # padding + 12, # type + 0x00, # flags + 0x00, 0x00, 0xA4, 0xB2, # time; 11:42:42 + ])) + message = parse_message(data, 1) + self.assertEqual(message.timestamp, + datetime.datetime(2000, 1, 1, 11, 42, 42)) + self.assertEqual(message.__class__.__name__, 'NotificationGaTime') + + def test_notification_ga_connected_set(self): + data = str(bytearray([ + 0x00, 0x00, 0x00, 0x1C, # length + 0x00, 0x00, # padding + 13, # type + 0x00, # flags + 0x00, 0x00, 0x00, 0x02, # count + 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB, # id + 0xCC, 0xCC, 0xCC, 0xCC, 0xDD, 0xDD, 0xDD, 0xDD, # id + ])) + message = parse_message(data, 1) + self.assertEqual(len(message.meters), 2) + self.assertEqual(message.meters[0].id, + cast_signed(0xAAAAAAAABBBBBBBB)) + self.assertEqual(message.meters[1].id, + cast_signed(0xCCCCCCCCDDDDDDDD)) + self.assertEqual(message.__class__.__name__, + 'NotificationGaConnectedSet') + + def test_notification_gp_state(self): + data = str(bytearray([ + 0x00, 0x00, 0x00, 0x14, # length + 0x00, 0x00, # padding + 14, # type + 0x03, # flags (connected, manual mode, relay off) + 0x00, 0x00, 0xA4, 0xB2, # time; 11:42:42 + 0xFF, 0xEE, 0xFF, 0xFF, 0x00, 0x00, 0x11, 0x00, # id + ])) + message = parse_message(data, 1) + self.assertEqual(message.online, True) + self.assertEqual(message.control_manual, True) + self.assertEqual(message.relay_on, False) + self.assertEqual(message.timestamp, + datetime.datetime(2000, 1, 1, 11, 42, 42)) + meter_id = cast_signed(0xFFEEFFFF00001100) + self.assertEqual(message.meter, Meter(0, meter_id)) + self.assertEqual(message.__class__.__name__, 'NotificationGpState') + + +# messages send timestamp as second; i.e. output will *not* match the +# microsecond of input if we use timestamps with microseconds... +def utcsecond(): + return datetime.datetime.utcnow().replace(microsecond=0) + + +class TestRoundtripVersion2(unittest.TestCase): + def test_bulk_measurements(self): + data = [MeterData(Meter(0, 0xaabbcc), + [MeasurementSet(utcsecond(), + [Measurement(0, 0, 5, 123456), + Measurement(0, 0, 9, 456789)]), + MeasurementSet((utcsecond() + + datetime.timedelta(hours=1)), + [Measurement(0, 0, 9, 123457), + Measurement(0, 0, 5, 456788)])]), + MeterData(Meter(0, 0xccddee), + [MeasurementSet(utcsecond(), + [Measurement(0, 0, 1, 123), + Measurement(0, 0, 3, 789)])])] + bytes = StringIO() + messages.write(bytes, BulkMeasurements(data), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.meter_data, data) + self.assertEqual(message.__class__, BulkMeasurements) + + def test_notification_ga_add_mode(self): + timestamp = utcsecond() + in_add_mode = bool(random.randint(0, 1)) + bytes = StringIO() + messages.write(bytes, NotificationGaAddMode(timestamp, in_add_mode), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.timestamp, timestamp) + self.assertEqual(message.in_add_mode, in_add_mode) + self.assertEqual(message.__class__, NotificationGaAddMode) + + def test_notification_ga_time(self): + timestamp = utcsecond() + bytes = StringIO() + messages.write(bytes, NotificationGaTime(timestamp), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.timestamp, timestamp) + self.assertEqual(message.__class__, NotificationGaTime) + + def test_notification_ga_connected_set(self): + # NOTE: IDs are signed numbers --- because they are signed numbers + # towards the DB... + meters = [Meter(0, 0xAa), Meter(1, 0xBb), Meter(2, 0x7CDDEEFFCCDDEEFF)] + bytes = StringIO() + messages.write(bytes, NotificationGaConnectedSet(meters), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.meters, meters) + self.assertEqual(message.__class__, NotificationGaConnectedSet) + + def test_notification_gp_state(self): + meter = Meter(1, 0xAABBCC) + online = bool(random.randint(0, 1)) + control_manual = bool(random.randint(0, 1)) + relay_on = bool(random.randint(0, 1)) + timestamp = utcsecond() + bytes = StringIO() + messages.write(bytes, NotificationGpState( + meter, online, control_manual, relay_on, timestamp), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.meter, meter) + self.assertEqual(message.online, online) + self.assertEqual(message.control_manual, control_manual) + self.assertEqual(message.relay_on, relay_on) + self.assertEqual(message.timestamp, timestamp) + self.assertEqual(message.__class__, NotificationGpState) diff --git a/gridagentserver-protocol/gridagentserver_protocol/datatypes.py b/gridagentserver-protocol/gridagentserver_protocol/datatypes.py new file mode 100644 index 0000000..4402feb --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/datatypes.py @@ -0,0 +1,77 @@ +"""Data types used for members in message objects on the Python side.""" + +# also used outside the protocol module --- but in code depending on the +# protocol module, so extracting this to a separate module/repository would not +# provide any clear benefits + +from collections import namedtuple + +# Measurement data format: +# +# list of "meter_data" +# meter_data: "meter_id", list of "measurement_set" +# meter_id: "connection_type", "id_number" +# connection_type: enum; +# "unknown", +# "ZigBee", +# "MBus primary", +# "MBus secondary", +# "Kamstrup UtiliDriver" +# ...? +# id_number: a local numeric ID specific to the connection technology +# measurement_set: timestamp, list of "measurement" +# measurement: "type", "unit", "input number", "value" +# type: enum; +# "unknown", +# "electricity consumption", +# ... (whatever from M-Bus medium) +# unit: enum; "unknown", "mWh", "mW", ...? + +MeterData = namedtuple('MeterData', ['meter', 'measurement_sets']) +Meter = namedtuple('Meter', ['connection_type', 'id']) +MeasurementSet = namedtuple('MeasurementSet', ['timestamp', 'measurements']) +Measurement = namedtuple('Measurement', + ['type', 'unit', 'input_number', 'value']) + +Rule = namedtuple('Rule', ['relay_on', 'start_time', 'end_time']) +RuleSet = namedtuple('RuleSet', ['override_timeout', 'rules', 'meters']) +Price = namedtuple('Price', ['start_timestamp', 'end_timestamp', 'price']) + +Version = namedtuple( + 'Version', ['major', 'minor', 'revision', 'revisionstring']) + +connection_types = [ + 'unknown', + 'ZigBee', + 'MBus primary', + # Meter IDs in MBus GM legacy follow a spec. from the old GridPortal 1.5 + # days. This should be removed in future software version of the GridAgents + 'MBus GM legacy', + 'Kamstrup UtiliDriver', + 'PLC Mitsubishi FX1S', + 'Modbus', + 'Aux Serial', + 'MBus secondary', +] + +measurement_types = [ + 'unknown', + 'electricity', + 'heat', +] + +measurement_units = [ + 'unknown', + 'mWh', + 'mW', + 'pulse count', + 'um^3', + 'um^3/h', + 'mdegC', + 'mV', + 'mA', + 'mHz', + 'g', + 'mbar', + 's', +] diff --git a/gridagentserver-protocol/gridagentserver_protocol/encryption.py b/gridagentserver-protocol/gridagentserver_protocol/encryption.py new file mode 100644 index 0000000..469f5d1 --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/encryption.py @@ -0,0 +1,147 @@ +"""ARCFOUR encryption, implemented as partial file object interface.""" + +import logging + +logger = logging.getLogger(__name__) + + +# deprecated; replaced +# Encrypter/StreamEncrypter splits responsibility for encryption state away +# from wrapping stream... (Mostly to be able to use encryption without +# streams...) +class Encryption(object): + """ + Simple ARCFOUR encryption implementation. Wrapping an object with read() + and write() operations to do encryption on read() and write(). + """ + def __init__(self, key, stream): + """Initialize encryption/cipher state with the specified key. + Key may be string or bytearray. + (Or an iterable yielding integers [0,255]...)""" + key = bytearray(key) + state = bytearray(range(256)) + j = 0 + for i in range(256): + j = (j + state[i] + key[i % len(key)]) % 256 + state[i], state[j] = state[j], state[i] + self._i = 0 + self._j = 0 + self._state = state + self.stream = stream + + def _crypt(self, data): + """ + Encrypt/decrypt data and update the state of the stream cipher. + Input/output data is represented as strings, for convenient use with + the Python socket interface. Returns the transformed data. + """ + i = self._i + j = self._j + state = self._state + result = bytearray(len(data)) + for n in range(len(data)): + i = (i + 1) % 256 + j = (j + state[i]) % 256 + state[i], state[j] = state[j], state[i] + k = state[(state[i] + state[j]) % 256] + result[n] = (ord(data[n]) ^ k) % 256 + self._i = i + self._j = j + return str(result) + + def read(self, count): + """ + Read and decrypt data from configured file/stream. + """ + # rfile.read does not throw exception if connection closed... + data = self._crypt(self.stream.read(count)) + # we check the length; we only get less than requested on "EOF"; + # i.e. if the connection was closed + if len(data) != count: + raise EOFError + return data + + def write(self, data): + """ + Encrypt and write data to configured file/stream. + """ + # wfile.write throws exception if connection closed + self.stream.write(self._crypt(data)) + self.stream.flush() + + def flush(self): + self.stream.flush() + + +class Encrypter(object): + def __init__(self, key): + key = bytearray(key) + state = bytearray(range(256)) + j = 0 + for i in range(256): + j = (j + state[i] + key[i % len(key)]) % 256 + state[i], state[j] = state[j], state[i] + self._i = 0 + self._j = 0 + self._state = state + + def __call__(self, data): + """ + Encrypt/decrypt data and update the state of the stream cipher. + Input/output data is represented as strings, for interoperability with + Python APIs representing byte arrays as strings. Returns the + transformed data. + """ + i = self._i + j = self._j + state = self._state + result = bytearray(len(data)) + for n in range(len(data)): + i = (i + 1) % 256 + j = (j + state[i]) % 256 + state[i], state[j] = state[j], state[i] + k = state[(state[i] + state[j]) % 256] + result[n] = (ord(data[n]) ^ k) % 256 + self._i = i + self._j = j + return str(result) + + def __cmp__(self, other): + # note that object changes wrt. comparison on use... + # (that's kind of the point of the object...) + return cmp((self._i, self._j, self._state), + (other._i, other._j, other._state)) + + def __hash__(self): + # not a very good hash function, but agrees with __cmp__, correctness + # before performance... + return hash((self._i, self._j)) + + +class StreamEncrypter(object): + def __init__(self, key, stream): + self._crypt = Encrypter(key) + self.stream = stream + + def read(self, count): + """ + Read and decrypt data from configured file/stream. + """ + # rfile.read does not throw exception if connection closed... + data = self._crypt(self.stream.read(count)) + # we check the length; we only get less than requested on "EOF"; + # i.e. if the connection was closed + if len(data) != count: + raise EOFError + return data + + def write(self, data): + """ + Encrypt and write data to configured file/stream. + """ + # wfile.write throws exception if connection closed + self.stream.write(self._crypt(data)) + self.stream.flush() + + def flush(self): + self.stream.flush() diff --git a/gridagentserver-protocol/gridagentserver_protocol/encryption_test.py b/gridagentserver-protocol/gridagentserver_protocol/encryption_test.py new file mode 100644 index 0000000..14288fd --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/encryption_test.py @@ -0,0 +1,61 @@ +import unittest + +from binascii import a2b_hex + +from encryption import Encryption +from StringIO import StringIO + + +# RC4 test vectors from http://en.wikipedia.org/wiki/RC4#Test_vectors ... +examples = [ + { + 'key': 'Key', + 'plain': 'Plaintext', + 'cipher': a2b_hex('BBF316E8D940AF0AD3'), + }, + { + 'key': 'Wiki', + 'plain': 'pedia', + 'cipher': a2b_hex('1021BF0420'), + }, + { + 'key': 'Secret', + 'plain': 'Attack at dawn', + 'cipher': a2b_hex('45A01F645FC35B383552544B9BF5'), + } +] + + +class TestEncryption(unittest.TestCase): + def test_encrypt(self): + for e in examples: + encrypt = Encryption(e['key'], None) + self.assertEqual(encrypt._crypt(e['plain']), e['cipher']) + self.assertNotEqual(encrypt._crypt(e['plain']), e['cipher']) + + def test_decrypt(self): + for e in examples: + encrypt = Encryption(e['key'], None) + self.assertEqual(encrypt._crypt(e['cipher']), e['plain']) + self.assertNotEqual(encrypt._crypt(e['cipher']), e['plain']) + + def test_stream_decrypt(self): + for e in examples: + encrypt = Encryption(e['key'], StringIO(e['cipher'])) + self.assertEqual(encrypt.read(len(e['plain'])), e['plain']) + + def test_stream_encrypt(self): + for e in examples: + stream = StringIO() + encrypt = Encryption(e['key'], stream) + encrypt.write(e['plain']) + self.assertEqual(stream.getvalue(), e['cipher']) + + def test_recursive(self): + # encrypt, then decrypt with same key... + for e in examples: + stream = StringIO() + estream = Encryption(e['key'], stream) + encrypt = Encryption(e['key'], estream) + encrypt.write(e['plain']) + self.assertEqual(stream.getvalue(), e['plain']) diff --git a/gridagentserver-protocol/gridagentserver_protocol/handshake.py b/gridagentserver-protocol/gridagentserver_protocol/handshake.py new file mode 100644 index 0000000..a7a8202 --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/handshake.py @@ -0,0 +1,63 @@ +"""Sending handshake messages.""" + +from struct import Struct +import random +import logging + +from encryption import StreamEncrypter +from . import PROTOCOL_VERSION, SECRET + + +logger = logging.getLogger(__name__) + +# protocol version, ID/nonce +handshake_struct = Struct('!IQ') +uint64 = Struct('!Q') + + +def handshake(wfile, rfile, wdata): + outgoing = handshake_struct.pack(PROTOCOL_VERSION, wdata) + wfile.write(outgoing) + wfile.flush() + incoming = rfile.read(handshake_struct.size) + version, rdata = handshake_struct.unpack(incoming) + return version, rdata + + +def handshake_serverside(wfile, rfile): + nonce = random.randint(0, 2 ** 64) + version, agent_mac = handshake(wfile, rfile, nonce) + logger.debug('Connection from agent %X, protocol %d', agent_mac, version) + if version > PROTOCOL_VERSION or version <= 0: + raise Exception('Protocol %d not supported; disconnecting %X' % ( + version, + agent_mac, + )) + encrypt_write, read_decrypt = init_encryption(wfile, rfile, + agent_mac, nonce) + return (version, agent_mac, encrypt_write, read_decrypt) + + +def handshake_clientside(wfile, rfile, agent_mac): + serverside_version, nonce = handshake(wfile, rfile, agent_mac) + if serverside_version != PROTOCOL_VERSION: + logger.debug('Protocol versions differ: Client: %d, server: %d' % ( + PROTOCOL_VERSION, + serverside_version + )) + # we use version from client anyway + encrypt_write, read_decrypt = init_encryption(wfile, rfile, + agent_mac, nonce) + return encrypt_write, read_decrypt + + +def init_encryption(wfile, rfile, agent_mac, nonce): + # initialise encryption state with nonce + secret + incoming data + key_bytes = bytearray(SECRET) + id_bytes = bytearray(uint64.pack(agent_mac)) + nonce_bytes = bytearray(uint64.pack(nonce)) + for i in range(len(nonce_bytes)): + key_bytes[i] = key_bytes[i] ^ id_bytes[i] ^ nonce_bytes[i] + encrypt_write = StreamEncrypter(key_bytes, wfile) + read_decrypt = StreamEncrypter(key_bytes, rfile) + return encrypt_write, read_decrypt diff --git a/gridagentserver-protocol/gridagentserver_protocol/message_types.py b/gridagentserver-protocol/gridagentserver_protocol/message_types.py new file mode 100644 index 0000000..ea988bb --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/message_types.py @@ -0,0 +1,32 @@ +# break module dependency chain... +# messages module needs the lookup table to construct send/parse message +# headers; but client/server message modules depend on that code... + +import client_messages +import server_messages + +# NOTE: order matters; same as in client... +# (To make ID-number/type mapping simple.) +message_types = [ + client_messages.BulkMeasurements, + server_messages.ConfigGp, + server_messages.ConfigGaRulesets, + server_messages.ConfigGaTime, + server_messages.ConfigGaPrices, + server_messages.ConfigGpSoftware, + server_messages.ConfigGaSoftware, + server_messages.CommandGaPollMeasurements, + server_messages.CommandGaPropagateTime, + server_messages.CommandGpSwitchControl, + server_messages.CommandGpSwitchRelay, + client_messages.NotificationGaAddMode, + client_messages.NotificationGaTime, + client_messages.NotificationGaConnectedSet, + client_messages.NotificationGpState, + client_messages.AcknowledgementGpSoftware, + client_messages.AcknowledgementGaSoftware, + client_messages.ErrorGpSoftware, + client_messages.ErrorGaSoftware, + client_messages.InfoAgentVersions, + client_messages.InfoEventLog, +] diff --git a/gridagentserver-protocol/gridagentserver_protocol/messages.py b/gridagentserver-protocol/gridagentserver_protocol/messages.py new file mode 100644 index 0000000..53ce510 --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/messages.py @@ -0,0 +1,173 @@ +"""Helper module and entry-point with the parse()/write() functions.""" + +import calendar +import datetime +import re +import logging +from struct import Struct + +from pytz import utc + +logger = logging.getLogger(__name__) + +# 1970-01-01 base to 2000-01-01 base ... +epochoffset = calendar.timegm(datetime.date(2000, 1, 1).timetuple()) + + +def timestamp_to_datetime(timestamp): + return datetime.datetime.utcfromtimestamp( + timestamp + epochoffset).replace(tzinfo=utc) + + +def datetime_to_timestamp(datetime): + return calendar.timegm(datetime.timetuple()) - epochoffset + + +class UnknownMessageTypeError(ValueError): + pass + + +class Header(object): + # message-size, type-id, flags + struct = Struct('!IxxBB') + + def __init__(self, length, MessageType, flags=0): + self.length = length + self.datalength = length - self.struct.size + self.MessageType = MessageType + self.flags = flags + + @classmethod + def unpack(cls, read, version): + length, type_id, flags = read(cls.struct) + from message_types import message_types + try: + message_type = message_types[type_id] + except IndexError: + raise UnknownMessageTypeError( + 'Message type %s unknown' % (type_id,)) + return cls(length, message_type, flags) + + def pack(self, version): + from message_types import message_types + type_id = message_types.index(self.MessageType) + return self.struct.pack(self.length, type_id, self.flags) + + def __repr__(self): + return '<{} {}>'.format( + self.__class__.__name__, + ', '.join(['{}={}'.format(k, repr(v)) + for k, v in self.__dict__.iteritems()]) + ) + + +class Message(object): + def accept(self, visitor): + classname = self.__class__.__name__ + underscores_classname = re.sub('([a-z0-9])([A-Z])', + r'\1_\2', + classname).lower() + methodname = 'visit_{}'.format(underscores_classname) + # only catch/handle the immediate failure if the method does not exist + try: + method = getattr(visitor, methodname) + except AttributeError: + return + method(self) + + # implement in children + # (method signature here as a reminder...) + # return child instance + @classmethod + def unpack(cls, read, version): + # "read" is an instance of BufferReader + raise Exception('Implementation missing') + + # implement in children + # return data string + def pack(self, version): + # should normally use self._pack internallyb + raise Exception('Implementation missing') + + # Helper for pack() implementations --- data should be a list of strings. + # This is convenient for use with Struct.pack() --- each call returns a + # string. (And building a list rather than a string is more efficient and + # feels "cleaner" from my point of view. (I may use list comprehensions + # "directly".)) + # + # (Using Struct.pack_into() instead of Struct.pack() is inconvenient, as + # that requires a preallocated buffer and management of the write offset. + # Computing the size for preallocating the buffer for nested structures + # takes about as much code as subsequently actually writing the data to the + # buffer.) + def _pack(self, data, version, header_flags=0): + content_bytes = ''.join(data) + package_size = Header.struct.size + len(content_bytes) + header = Header(package_size, self.__class__, header_flags) + return header.pack(version) + content_bytes + + # for debugging/logging + def __repr__(self): + return '<{} {}>'.format( + self.__class__.__name__, + ', '.join(['{}={}'.format(k, repr(v)) + for k, v in self.__dict__.iteritems()]) + ) + + +class BufferReader(object): + """ + Helper class for deserialising data with struct.Struct: Keep track of + offset for reading, read sequence of same Struct to list. + """ + def __init__(self, data): + self.offset = 0 + self.data = data + + def _read_single(self, struct): + result = struct.unpack_from(self.data, self.offset) + self.offset += struct.size + return result + + def _read_list(self, struct, count): + result = [] + for n in range(count): + result.append(self._read_single(struct)) + return result + + def __call__(self, struct, count=None): + if count is not None: + return self._read_list(struct, count) + else: + return self._read_single(struct) + + def raw(self, count=None): + if count is not None: + new_offset = self.offset + count + else: + new_offset = len(self.data) + assert new_offset <= len(self.data) + result = self.data[self.offset:new_offset] + self.offset = new_offset + return result + + +timestamp_struct = Struct('!I') + + +# Decrypt stream; we read from that; it reads from actual input and decrypts. +# Makes testing easier; we can provide a directly unencrypted "stream". +def parse(stream, version): + header_read = BufferReader(stream.read(Header.struct.size)) + header = Header.unpack(header_read, version) + read = BufferReader(stream.read(header.datalength)) + logger.debug('Received header: %r, payload: %r', header, read.data) + return header.MessageType.unpack(header, read, version) + + +# Encrypt stream; we write to that; it encrypts and writes to actual output. +# Makes testing easier; we may use an unencrypted "stream". +def write(stream, message, version): + bytes = message.pack(version) + logger.debug('Sending message: %r, bytes: %r', message, bytes) + stream.write(bytes) diff --git a/gridagentserver-protocol/gridagentserver_protocol/server_messages.py b/gridagentserver-protocol/gridagentserver_protocol/server_messages.py new file mode 100644 index 0000000..4348699 --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/server_messages.py @@ -0,0 +1,288 @@ +"""Messages to be sent from the GridAgent server to the (virtual) agent.""" + +import logging +from struct import Struct + +from messages import Message, timestamp_to_datetime, datetime_to_timestamp +from datatypes import Meter, Rule, RuleSet, Price + +logger = logging.getLogger(__name__) + +uint32 = Struct('!I') +uint16 = Struct('!H') +uint8 = Struct('B') + +# ZigBee timestamp, i.e. seconds since 2000-01-01 +timestamp_struct = Struct('!I') + +# major, minor, revision, extra string +version_struct = Struct('!BBB12s') + + +def normalise_version(version): + """ + Replace the received fixed-length "extra" string with its prefix before the + first \0 character. + """ + major, minor, revision, extra = version + extra = extra.split('\0', 1)[0] + return (major, minor, revision, extra) + + +# connection_type, ID +meter_struct = Struct('!bq') + + +# DEPRECATED/useless: +# We always want 1 minute interval; ignoring intervals configured in DB... +class ConfigGp(Message): + # ID, interval + config1_struct = Struct('!qi') + + def __init__(self, measurement_intervals): + self.measurement_intervals = measurement_intervals + + @classmethod + def unpack(cls, header, read, version): + pass + + def pack(self, version): + if version == 1: + data = [uint32.pack(len(self.measurement_intervals))] + data.extend([self.config1_struct.pack(meter.id, interval) + for meter, interval + in self.measurement_intervals.iteritems()]) + else: + # deprecated... + data = [] + return self._pack(data, version) + + +class ConfigGaRulesets(Message): + # override timeout, rule-count, meter-count + ruleset_head_struct = Struct('!ihh') + # relay-on?, start-time, end-time + rule_struct = Struct('!xxx?II') + # ID + meter1_struct = Struct('!q') + # connection type, ID + meter2_struct = Struct('!bq') + + def __init__(self, rulesets): + self.rulesets = rulesets + + @classmethod + def unpack(cls, header, read, version): + ruleset_count, = read(uint32) + rulesets = [] + for n in range(ruleset_count): + override_timeout, rule_count, meter_count = \ + read(cls.ruleset_head_struct) + rules = [Rule(*entry) + for entry in read(cls.rule_struct, rule_count)] + if version == 1: + meters = [Meter(0, id) + for id, in read(cls.meter1_struct, meter_count)] + else: + meters = [Meter(*entry) + for entry in read(cls.meter2_struct, meter_count)] + rulesets.append(RuleSet(override_timeout, rules, meters)) + return cls(rulesets) + + def pack(self, version): + data = [uint32.pack(len(self.rulesets))] + for override_timeout, rules, meters in self.rulesets: + data.append(self.ruleset_head_struct.pack(override_timeout, + len(rules), len(meters))) + data.extend([self.rule_struct.pack(*rule) for rule in rules]) + if version == 1: + data.extend([self.meter1_struct.pack(meter.id) + for meter in meters]) + else: + data.extend([self.meter2_struct.pack(*meter) + for meter in meters]) + return self._pack(data, version) + + +class ConfigGaTime(Message): + def __init__(self, timestamp): + self.timestamp = timestamp + + @classmethod + def unpack(cls, header, read, version): + timestamp = timestamp_to_datetime(*read(timestamp_struct)) + return cls(timestamp) + + def pack(self, version): + data = timestamp_struct.pack(datetime_to_timestamp(self.timestamp)) + return self._pack([data], version) + + +class ConfigGaPrices(Message): + # count + price_head_struct = Struct('!xxH') + # start timestamp, end timestamp, price per GWh + # (price in some unspecified unit...) + price_struct = Struct('!III') + + def __init__(self, prices): + self.prices = prices + + @classmethod + def unpack(cls, header, read, version): + price_count, = read(cls.price_head_struct) + prices = [Price(timestamp_to_datetime(start), + timestamp_to_datetime(end), price) + for start, end, price in read(cls.price_struct, price_count)] + return cls(prices) + + def pack(self, version): + data = [self.price_head_struct.pack(len(self.prices))] + data.extend([self.price_struct.pack(datetime_to_timestamp(start), + datetime_to_timestamp(end), price) + for start, end, price in self.prices]) + return self._pack(data, version) + + +class ConfigGpSoftware(Message): + def __init__(self, sw_version, hw_model, target_hw_version, image, meters): + # version: major, minor, revision + self.sw_version = sw_version + self.hw_model = hw_model + self.target_hw_version = target_hw_version + self.image = image + self.meters = meters + + @classmethod + def unpack(cls, header, read, version): + image_offset, = read(uint32) + sw_version = normalise_version(read(version_struct)) + hw_model, = read(uint8) + target_hw_version = normalise_version(read(version_struct)) + meter_count, = read(uint32) + meters = [Meter(*entry) + for entry in read(meter_struct, meter_count)] + image = read.raw() + return cls(sw_version, hw_model, target_hw_version, image, meters) + + def pack(self, version): + assert version >= 3 + # differ from agent software message with inclusion of model, meter ids + image_offset = (uint32.size + 2 * version_struct.size + uint8.size + + uint32.size + len(self.meters) * meter_struct.size) + data = [uint32.pack(image_offset), + version_struct.pack(*self.sw_version), + uint8.pack(self.hw_model), + version_struct.pack(*self.target_hw_version)] + # meter_ids + data.append(uint32.pack(len(self.meters))) + data.extend([meter_struct.pack(*meter) for meter in self.meters]) + # image + data.append(self.image) + return self._pack(data, version) + + +class ConfigGaSoftware(Message): + def __init__(self, sw_version, hw_model, target_hw_version, image): + # version: major, minor, revision + self.sw_version = sw_version + self.hw_model = hw_model + self.target_hw_version = target_hw_version + self.image = image + + @classmethod + def unpack(cls, header, read, version): + image_offset, = read(uint32) + sw_version = normalise_version(read(version_struct)) + hw_model, = read(uint8) + hw_version = normalise_version(read(version_struct)) + image = read.raw() + return cls(sw_version, hw_model, hw_version, image) + + def pack(self, version): + assert version >= 3 + image_offset = uint32.size + 2 * version_struct.size + uint8.size + data = [uint32.pack(image_offset), + version_struct.pack(*self.sw_version), + uint8.pack(self.hw_model), + version_struct.pack(*self.target_hw_version), + self.image] + return self._pack(data, version) + + +class CommandGaPollMeasurements(Message): + # no members... + @classmethod + def unpack(cls, header, read, version): + return cls() + + def pack(self, version): + return self._pack([], version) + + +class CommandGaPropagateTime(Message): + # no members... + @classmethod + def unpack(cls, header, read, version): + return cls() + + def pack(self, version): + return self._pack([], version) + + +class CommandGpSwitchControl(Message): + # ID + meter1_struct = Struct('!q') + # ID, connection type + meter2_struct = Struct('!bq') + + def __init__(self, meter, control_manual): + self.meter = meter + self.control_manual = control_manual + + @classmethod + def unpack(cls, header, read, version): + control_manual = bool(header.flags) + if version == 1: + id, = read(cls.meter1_struct) + meter = Meter(0, id) + else: + meter = Meter(*read(cls.meter2_struct)) + return cls(meter, control_manual) + + def pack(self, version): + if version == 1: + data = self.meter1_struct.pack(self.meter.id) + else: + data = self.meter2_struct.pack(*self.meter) + flags = int(self.control_manual) + return self._pack([data], version, flags) + + +class CommandGpSwitchRelay(Message): + # ID + meter1_struct = Struct('!q') + # ID, connection type + meter2_struct = Struct('!bq') + + def __init__(self, meter, relay_on): + self.meter = meter + self.relay_on = relay_on + + @classmethod + def unpack(cls, header, read, version): + relay_on = bool(header.flags) + if version == 1: + id, = read(cls.meter1_struct) + meter = Meter(0, id) + else: + meter = Meter(*read(cls.meter2_struct)) + return cls(meter, relay_on) + + def pack(self, version): + if version == 1: + data = self.meter1_struct.pack(self.meter.id) + else: + data = self.meter2_struct.pack(*self.meter) + flags = int(self.relay_on) + return self._pack([data], version, flags) diff --git a/gridagentserver-protocol/gridagentserver_protocol/server_messages_test.py b/gridagentserver-protocol/gridagentserver_protocol/server_messages_test.py new file mode 100644 index 0000000..7b2c237 --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/server_messages_test.py @@ -0,0 +1,275 @@ +import unittest +import ctypes +import datetime +from StringIO import StringIO +import random + +from datatypes import Meter, RuleSet, Rule, Price +import server_messages +import messages + +from server_messages import ( + # ConfigGp, + ConfigGaRulesets, + ConfigGaTime, + ConfigGaPrices, + CommandGaPollMeasurements, + CommandGaPropagateTime, + CommandGpSwitchControl, + CommandGpSwitchRelay, + ConfigGaSoftware, + ConfigGpSoftware, +) + + +def signed_64(val): + return ctypes.c_longlong(val).value + + +def signed_32(val): + return ctypes.c_long(val).value + + +class TestSerializingVersion1(unittest.TestCase): + def test_config_gp(self): + pass + + def test_config_ga_rulesets(self): + expected = str(bytearray([ + 0x00, 0x00, 0x00, 0x38, # length + 0x00, 0x00, # padding + 2, # type + 0x00, # flags + 0x00, 0x00, 0x00, 0x02, # count + # entries + 0x00, 0x00, 0x00, 0x01, # override timeout + 0x00, 0x00, # rule count + 0x00, 0x00, # endpoint count + 0x00, 0x00, 0x00, 0x0F, # override timeout + 0x00, 0x01, # rule count + 0x00, 0x02, # endpoint count + # rules + 0x00, 0x00, 0x00, # padding + 0x01, # action (turn on) + 0x00, 0x00, 0x10, 0x00, # time begin + 0x00, 0x00, 0x20, 0x00, # time end + # endpoints + 0xAB, 0xCD, 0xAB, 0xCD, 0xAB, 0xCD, 0xAB, 0xCD, # id + 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, # id + ])) + actual = server_messages.ConfigGaRulesets([ + RuleSet(1, [], []), + RuleSet( + 15, + [Rule(True, 4096, 8192)], + [ + Meter(0, signed_64(0xABCDABCDABCDABCD)), + Meter(0, signed_64(0x1234123412341234)), + ] + ), + ]).pack(1) + self.assertEqual(actual, expected) + + def test_config_ga_time(self): + expected = str(bytearray([ + 0x00, 0x00, 0x00, 0x0C, # length + 0x00, 0x00, # padding + 3, # type + 0x00, # flags + 0x00, 0x00, 0x69, 0x78, # timestamp + ])) + actual = server_messages.ConfigGaTime( + datetime.datetime(2000, 1, 1, 7, 30) + ).pack(1) + self.assertEqual(actual, expected) + + def test_config_ga_prices(self): + expected = str(bytearray([ + 0x00, 0x00, 0x00, 0x24, # length + 0x00, 0x00, # padding + 4, # type + 0x00, # flags + 0x00, 0x00, # padding + 0x00, 0x02, # count + 0x00, 0x00, 0x00, 0x00, # start time + 0x00, 0x00, 0x01, 0x00, # end time + 0x12, 0x12, 0x21, 0x21, # price + 0x00, 0x00, 0x01, 0x00, # start time + 0x00, 0x00, 0x02, 0x00, # end time + 0x32, 0x32, 0x23, 0x23, # price + ])) + actual = server_messages.ConfigGaPrices([ + Price( + datetime.datetime(2000, 1, 1, 0, 0, 0), + datetime.datetime(2000, 1, 1, 0, 4, 16), + signed_32(0x12122121) + ), + Price( + datetime.datetime(2000, 1, 1, 0, 4, 16), + datetime.datetime(2000, 1, 1, 0, 8, 32), + signed_32(0x32322323) + ), + ]).pack(1) + self.assertEqual(len(actual), len(expected)) + self.assertEqual(actual, expected) + + def test_command_ga_poll_measurements(self): + expected = str(bytearray([ + 0x00, 0x00, 0x00, 0x08, # length + 0x00, 0x00, # padding + 7, # type + 0x00, # flags + ])) + actual = server_messages.CommandGaPollMeasurements().pack(1) + self.assertEqual(actual, expected) + + def test_command_ga_propagate_time(self): + expected = str(bytearray([ + 0x00, 0x00, 0x00, 0x08, # length + 0x00, 0x00, # padding + 8, # type + 0x00, # flags + ])) + actual = server_messages.CommandGaPropagateTime().pack(1) + self.assertEqual(actual, expected) + + def test_command_gp_switch_control(self): + expected = str(bytearray([ + 0x00, 0x00, 0x00, 0x10, # length + 0x00, 0x00, # padding + 9, # type + 0x01, # flags (manual control) + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, # id + ])) + actual = server_messages.CommandGpSwitchControl( + Meter(0, signed_64(0x1234567812345678)), + True + ).pack(1) + self.assertEqual(actual, expected) + + def test_command_gp_switch_relay(self): + expected = str(bytearray([ + 0x00, 0x00, 0x00, 0x10, # length + 0x00, 0x00, # padding + 10, # type + 0x01, # flags (relay on) + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, # id + ])) + actual = server_messages.CommandGpSwitchRelay( + Meter(0, signed_64(0x1234567812345678)), + True + ).pack(1) + self.assertEqual(actual, expected) + + +# messages send timestamp as second; i.e. output will *not* match the +# microsecond of input if we use timestamps with microseconds... +def utcsecond(): + return datetime.datetime.utcnow().replace(microsecond=0) + + +class TestRoundtripVersion2(unittest.TestCase): + def test_config_gp(self): + pass + + def test_config_ga_rulesets(self): + rulesets = [RuleSet(0, [Rule(True, 0, 604800)], [Meter(0, 0xAABBCC)]), + RuleSet(15, [Rule(True, 5, 15), Rule(False, 0, 604800)], + [Meter(1, 0xABC), Meter(2, 0xDEF)])] + bytes = StringIO() + messages.write(bytes, ConfigGaRulesets(rulesets), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.rulesets, rulesets) + self.assertEqual(message.__class__, ConfigGaRulesets) + + def test_config_ga_time(self): + timestamp = utcsecond() + bytes = StringIO() + messages.write(bytes, ConfigGaTime(timestamp), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.timestamp, timestamp) + self.assertEqual(message.__class__, ConfigGaTime) + + def test_config_ga_prices(self): + now = utcsecond() + prices = [Price(now, + now + datetime.timedelta(hours=1), + 100), + Price(now + datetime.timedelta(hours=1), + now + datetime.timedelta(hours=2), + 200)] + bytes = StringIO() + messages.write(bytes, ConfigGaPrices(prices), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.prices, prices) + self.assertEqual(message.__class__, ConfigGaPrices) + + def test_command_ga_poll_meauserements(self): + bytes = StringIO() + messages.write(bytes, CommandGaPollMeasurements(), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.__class__, CommandGaPollMeasurements) + + def test_command_ga_propagate_time(self): + bytes = StringIO() + messages.write(bytes, CommandGaPropagateTime(), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.__class__, CommandGaPropagateTime) + + def test_command_gp_switch_control(self): + meter = Meter(1, 0xABCD) + control_manual = bool(random.randint(0, 1)) + bytes = StringIO() + messages.write(bytes, CommandGpSwitchControl(meter, control_manual), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.meter, meter) + self.assertEqual(message.control_manual, control_manual) + self.assertEqual(message.__class__, CommandGpSwitchControl) + + def test_command_gp_switch_relay(self): + meter = Meter(1, 0xABCD) + relay_on = bool(random.randint(0, 1)) + bytes = StringIO() + messages.write(bytes, CommandGpSwitchRelay(meter, relay_on), 2) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.meter, meter) + self.assertEqual(message.relay_on, relay_on) + self.assertEqual(message.__class__, CommandGpSwitchRelay) + + def test_config_ga_software(self): + sw_version = (0xaa, 0xbb, 0xcc, 'debug') + hw_model = 1 + target_hw_version = (0x11, 0x22, 0x33, '') + image = 'abc' * 100 + bytes = StringIO() + messages.write(bytes, ConfigGaSoftware( + sw_version, hw_model, target_hw_version, image), 3) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.sw_version, sw_version) + self.assertEqual(message.target_hw_version, target_hw_version) + self.assertEqual(message.image, image) + + def test_config_ga_gp_software(self): + sw_version = (0xaa, 0xbb, 0xcc, 'test') + hw_model = 3 + target_hw_version = (0x11, 0x22, 0x33, '') + image = 'abc' * 100 + meters = [Meter(1, 0xABCD)] + bytes = StringIO() + messages.write(bytes, ConfigGpSoftware( + sw_version, hw_model, target_hw_version, image, meters), 3) + bytes.seek(0) + message = messages.parse(bytes, 2) + self.assertEqual(message.sw_version, sw_version) + self.assertEqual(message.target_hw_version, target_hw_version) + self.assertEqual(message.hw_model, hw_model) + self.assertEqual(message.image, image) + self.assertEqual(message.meters, meters) diff --git a/gridagentserver-protocol/gridagentserver_protocol/twisted_protocol.py b/gridagentserver-protocol/gridagentserver_protocol/twisted_protocol.py new file mode 100644 index 0000000..328445d --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/twisted_protocol.py @@ -0,0 +1,253 @@ +import random +from struct import Struct +import logging + +from twisted.internet.protocol import Protocol, ServerFactory, connectionDone +from twisted.internet.defer import DeferredQueue, CancelledError + +from . import PROTOCOL_VERSION, SECRET +from encryption import Encrypter +from messages import Header, BufferReader, UnknownMessageTypeError + +logger = logging.getLogger(__name__) + +# protocol version, ID/nonce +handshake_struct = Struct('!IQ') +uint64 = Struct('!Q') +uint32 = Struct('!I') + + +class EncryptedProtocol(Protocol): + """ + A protocol with ARC-4 encryption. + + After handshake, messages start with a 4-byte (network byte order) length + field, and subclasses may receive/parse only complete messages. + + (The encryption initialisation protocol is far from perfect, but should + work...) + """ + + def __init__(self): + self.other_id = None + self.version = None + + def connectionMade(self): + logger.debug('Connection from %s', self.transport.getPeer().host) + self._handshake_done = False + self._buffer = '' + self._nonce = random.randint(0, 2 ** 64) + self.send_handshake() + + def send_handshake(self): + handshake_data = handshake_struct.pack(PROTOCOL_VERSION, self._nonce) + logger.debug('Writing handshake %r %s', handshake_data, + len(handshake_data)) + self.transport.write(handshake_data) + + def dataReceived(self, data): + logger.debug('Received data (%s)', len(data)) + if not self._handshake_done: + self._buffer += data + self.receive_handshake() + else: + self._buffer += self._decrypt(data) + while self.receive_message(): + pass + + def connectionLost(self, reason=connectionDone): + logger.debug('Connection lost, reason: %s', reason) + self.unregister() + + def receive_handshake(self): + assert not self._handshake_done + if len(self._buffer) < handshake_struct.size: + return + logger.debug('Handshake data received') + handshake_data = self._buffer[0:handshake_struct.size] + extra_data = self._buffer[handshake_struct.size:] + self._buffer = '' + self.version, self.other_id = handshake_struct.unpack(handshake_data) + logger.info('Connection from %X, protocol %d', + self.other_id, self.version) + if self.version > PROTOCOL_VERSION or self.version <= 0: + logger.info('Protocol %d not supported; disconnecting %X', + self.version, self.other_id) + self.transport.loseConnection() + return + self.init_encryption() + self._handshake_done = True + self.register() + if extra_data != '': + self.dataReceived(extra_data) + + def init_encryption(self): + # initialise encryption state with nonce + secret + incoming data + key_bytes = bytearray(SECRET) + id_bytes = bytearray(uint64.pack(self.other_id)) + nonce_bytes = bytearray(uint64.pack(self._nonce)) + for i in range(len(nonce_bytes)): + key_bytes[i] = key_bytes[i] ^ id_bytes[i] ^ nonce_bytes[i] + self._encrypt = Encrypter(key_bytes) + self._decrypt = Encrypter(key_bytes) + + def receive_message(self): + if len(self._buffer) < uint32.size: + return False + length, = uint32.unpack_from(self._buffer) + if len(self._buffer) < length: + return False + message = self._buffer[:length] + self._buffer = self._buffer[length:] + self.message_received(message) + return True + + def write_encrypted(self, bytes): + self.transport.write(self._encrypt(bytes)) + + # Override this. + def message_received(self, data): + pass + + # Override this. Called after processing handshake. + def register(self): + pass + + # Override this. Called from connectionLost. + def unregister(self): + pass + + +# gets a "factory" member set to the factory used to obtain it +# connection from: self.transport.getPeer().host (ip addr as string) +class BaseAgentProtocol(EncryptedProtocol): + def __init__(self): + EncryptedProtocol.__init__(self) + self.agent_mac = None + # We serialise incoming/outgoing messages in these queues... + # (Serialise as in "order sequentially"...) + self.outgoing = DeferredQueue(backlog=1) + self.incoming = DeferredQueue(backlog=1) + + # Called after handshake, when encryption is initialised and we have an + # identifier (MAC address) for the other end. (Overridden + called from + # implementation in GridAgent Server.) + def register(self): + """ + Registers self in the factory handlers dictionary; disconnecting any + currently present handler for the same agent MAC. Return True if old + handler removed, False if no old handler existed. + """ + logger.debug('Adding %X to handler map', self.other_id) + self.agent_mac = self.other_id + return self.factory.register(self) + + # Called on disconnect. Return true if agent has already reconnected, + # i.e. new connection for same id exist. (Overridden + called from + # implementation in GridAgent Server.) + def unregister(self): + """ + Stops sending messages from the outgoing queue and removes self from + the factory handlers dictionary; return True if already replaced, False + otherwise. + """ + if self.other_id: + logger.debug('Removing %X from handler map', self.other_id) + for deferred in self.outgoing.waiting: + deferred.cancel() + return self.factory.unregister(self) + + # Called when a complete message is arrived (the base class decrypts and + # reads the length field at the start of each message). + def message_received(self, data): + """ + Parses a complete, decrypted message and puts it on the incoming queue. + Resumes the sending of messages from the outgoing queue if indicated by + resume_sending_after(). + """ + header_read = BufferReader(data[:Header.struct.size]) + try: + header = Header.unpack(header_read, self.version) + read = BufferReader(data[Header.struct.size:]) + message = header.MessageType.unpack(header, read, self.version) + logger.debug('Received message of type %s', message.__class__.__name__) + self.incoming.put(message) + if self.transport.connected and self.resume_sending_after(message): + # process next message when available... + # no-op error handler to allow cancel + self.outgoing.get().addCallbacks(self.send_message, lambda ex: None) + except UnknownMessageTypeError as e: + logger.info(e.message) + + def send_message(self, message): + """ + Serialises and sends a message; pauses the sending of messages + afterwards if indicated by pause_sending_after(); otherwise, sets up + handling/sending of the next message from the outgoing queue. + """ + logger.debug('Sending message of type %s', message.__class__.__name__) + bytes = message.pack(self.version) + self.write_encrypted(bytes) + if self.transport.connected and not self.pause_sending_after(message): + # process next message when available... + # no-op error handler to allow cancel + self.outgoing.get().addCallbacks(self.send_message, lambda ex: None) + + # Some messages --- software updates in particular --- demand the complete + # attention of the GridAgent. After sending such a message, writing + # mesages is paused/delayed until we receive an acknowledgement. + # Override in subclass. + def pause_sending_after(self, message): + """ + Specifies whether sending messages should be paused after sending a + specific message --- by default always False; override in subclass. + """ + return False + + # See pause_sending_after + # Override in subclass. + def resume_sending_after(self, message): + """ + Specifies whether sending messages should be resumed after receiving + (not processing) a specific message --- by default always False; + override in subclass. + """ + return False + + +class BaseAgentProtocolFactory(ServerFactory): + protocol = BaseAgentProtocol + + def __init__(self): + self.handlers = {} + + def register(self, handler): + """ + Return True if this replaces an existing connection; i.e. this is a + reconnect before/without a disconnect; False if this is a "new" + connection. + """ + previous = self.handlers.pop(handler.agent_mac, None) + self.handlers[handler.agent_mac] = handler + if previous is not None: + assert previous is not handler + previous.transport.loseConnection() + # handling/sending outgoing messages now safe; start processing + if handler.transport.connected: + # no-op error handler to allow cancel + # (reading from the queue shouldn't "fail" otherwise, so this + # shouldn't mask real errors...) + handler.outgoing.get().addCallbacks(handler.send_message, + lambda ex: None) + return (previous is not None) + + def unregister(self, handler): + """ + Return True if another handler is registered for this connection, + i.e. a reconnect has occurred before this disconnect; False if this is + a "normal" disconnect. + """ + current = self.handlers.get(handler.agent_mac, None) + if current is handler: + del self.handlers[handler.agent_mac] + return (current is not handler) and (current is not None) diff --git a/gridagentserver-protocol/gridagentserver_protocol/twisted_protocol_test.py b/gridagentserver-protocol/gridagentserver_protocol/twisted_protocol_test.py new file mode 100644 index 0000000..ab788b0 --- /dev/null +++ b/gridagentserver-protocol/gridagentserver_protocol/twisted_protocol_test.py @@ -0,0 +1,92 @@ +from struct import Struct +import copy +import datetime +import random + +from twisted.trial import unittest +from twisted.test import proto_helpers +from twisted.internet.protocol import ServerFactory + +from . import PROTOCOL_VERSION, SECRET +from client_messages import NotificationGpState +from datatypes import Meter +from encryption import Encrypter +from twisted_protocol import ( + EncryptedProtocol, + BaseAgentProtocol, + BaseAgentProtocolFactory, +) + +# version, id/nonce +handshake_struct = Struct('!IQ') +uint64 = Struct('!Q') + + +def make_key(client_id, nonce): + return bytearray(map(lambda a, b, c: (a or 0) ^ (b or 0) ^ (c or 0), + bytearray(SECRET), + bytearray(uint64.pack(client_id)), + bytearray(uint64.pack(nonce)))) + + +class EncryptionProtocolFactory(ServerFactory): + protocol = EncryptedProtocol + + +class EncryptionProtocolTestCase(unittest.TestCase): + def setUp(self): + factory = EncryptionProtocolFactory() + self.proto = factory.buildProtocol(('127.0.0.1', 0)) + self.tr = proto_helpers.StringTransport() + self.proto.makeConnection(self.tr) + + def test_handshake(self): + handshake = handshake_struct.pack(2, 0x3c970e1e8e4e) + self.proto.dataReceived(handshake) + version, nonce = handshake_struct.unpack(self.tr.value()) + self.assertEqual(version, PROTOCOL_VERSION) + + def test_init_encryption(self): + client_id = 0x3c970e1e8e4e + client_version = 2 + handshake = handshake_struct.pack(client_version, client_id) + self.proto.dataReceived(handshake) + server_version, nonce = handshake_struct.unpack(self.tr.value()) + key = make_key(client_id, nonce) + encrypter = Encrypter(key) + self.assertEqual(encrypter, self.proto._encrypt) + self.assertEqual(encrypter, self.proto._decrypt) + + +class BaseAgentProtocolTestCase(unittest.TestCase): + def setUp(self): + self.factory = BaseAgentProtocolFactory() + self.proto = self.factory.buildProtocol(('127.0.0.1', 0)) + self.tr = proto_helpers.StringTransport() + self.proto.makeConnection(self.tr) + self.agent_mac = random.randint(0, 0xffffffffffff) # 6 bytes... + client_version = 2 + handshake = handshake_struct.pack(client_version, self.agent_mac) + self.proto.dataReceived(handshake) + server_version, nonce = handshake_struct.unpack(self.tr.value()) + key = make_key(self.agent_mac, nonce) + self.encrypter = Encrypter(key) + self.decrypter = copy.deepcopy(self.encrypter) + + def test_register(self): + self.assertEqual(self.factory.handlers.keys(), [self.agent_mac]) + + def test_unregister(self): + self.assertEqual(self.factory.handlers.keys(), [self.agent_mac]) + self.proto.connectionLost() + self.assertEqual(self.factory.handlers.keys(), []) + + def test_message(self): + meter = Meter(2, 24) + timestamp = datetime.datetime.now().replace(microsecond=0) + notification = NotificationGpState(meter, True, False, True, timestamp) + data = self.encrypter(notification.pack(2)) + splitpoint = random.randint(0, len(data)) + self.proto.dataReceived(data[:splitpoint]) + self.proto.dataReceived(data[splitpoint:]) + self.assertEqual(self.proto.incoming.pending, [notification]) diff --git a/gridagentserver-protocol/run_tests.sh b/gridagentserver-protocol/run_tests.sh new file mode 100755 index 0000000..39a5703 --- /dev/null +++ b/gridagentserver-protocol/run_tests.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +cd `dirname $0` + +python -m unittest discover -p '**_test.py' + +# unit test library from twisted... +trial gridagentserver_protocol.twisted_protocol_test diff --git a/gridagentserver-protocol/setup.py b/gridagentserver-protocol/setup.py new file mode 100755 index 0000000..c491dd7 --- /dev/null +++ b/gridagentserver-protocol/setup.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +from setuptools import setup, find_packages +setup( + name='GridAgentServerProtocol', + version='2.3.0', + packages=find_packages(), +) diff --git a/gridagentserver/.gitignore b/gridagentserver/.gitignore new file mode 100644 index 0000000..1961679 --- /dev/null +++ b/gridagentserver/.gitignore @@ -0,0 +1,11 @@ +*~ +*.pyc +*.log +*.log.? +daemon.pid +twistd.pid +GridAgentServer.egg-info/ +bin/ +include/ +lib/ +local/ diff --git a/gridagentserver/README b/gridagentserver/README new file mode 100644 index 0000000..0d2262c --- /dev/null +++ b/gridagentserver/README @@ -0,0 +1,15 @@ +This is the GridAgent Server, version 2.1. + +It implements the (new) GridAgent Server Protocol, versions 1 and 2. + +Options are specified in agentserver/settings.py + +Database access is via the Django ORM, through models specified in our GridPlatform project (i.e. the GridPortal 2.0 models). + + +To run in development: +* make and enter a Python virtualenv +* run "setup.py develop" for gridplatform +* run "setup.py develop" for gridagentserver-protocol +* run "setup.py develop" here ... +* start.sh diff --git a/gridagentserver/agent_software.py b/gridagentserver/agent_software.py new file mode 100755 index 0000000..aa0db09 --- /dev/null +++ b/gridagentserver/agent_software.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# dry-run example command: +# ./agent_software.py 3C970E1E8E4E 2.1.0 4.4.0 -v -n + +import argparse + +from client import normalise_mac, normalise_version, send_message + + +parser = argparse.ArgumentParser() +parser.add_argument('agent', help='target agent (MAC address)') +parser.add_argument('sw_version', help='software version (n.n.n[extra])') +parser.add_argument('-m', '--model', + help='hardware model', default=1) +parser.add_argument('target_hw_version', + help='compatible hardware version (n.n.n[extra])') +parser.add_argument('-v', '--verbose', action='store_true', + help='increase output verbosity') +parser.add_argument('-n', '--dry-run', action='store_true', + help='don\'t actually send command') + + +def agent_swupdate(args): + mac = normalise_mac(args.agent) + sw_version = normalise_version(args.sw_version) + hw_model = int(args.model) + hw_version = normalise_version(args.target_hw_version) + routing_key = 'agent.%s' % (mac,) + message = { + 'command': 'gridagent_software', + 'agent': mac, + 'sw_version': sw_version, + 'hw_model': hw_model, + 'target_hw_version': hw_version, + } + send_message(routing_key, message, args.verbose, args.dry_run) + + +if __name__ == '__main__': + agent_swupdate(parser.parse_args()) diff --git a/gridagentserver/agentserver.tac b/gridagentserver/agentserver.tac new file mode 100644 index 0000000..f733afa --- /dev/null +++ b/gridagentserver/agentserver.tac @@ -0,0 +1,49 @@ +# NOTE: this is not intended as a demonstration of correct use of Twisted +# conventions... + +import logging.config +import os + +from twisted.application import internet, service +from twisted.internet import reactor +from twisted.internet.endpoints import TCP4ClientEndpoint +from twisted.python.log import ILogObserver, PythonLoggingObserver + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'agentserver.settings') +os.environ.setdefault('DJANGO_CONFIGURATION', 'Dev') + +import configurations.importer +configurations.importer.install() +from agentserver import settings + + +logging.config.fileConfig('logging.ini') + + +from agentserver.amqp import AmqpFactory +from agentserver.twisted_server import AgentProtocolFactory + + +application = service.Application('gridagent') +# logging from Twisted to standard Python logging +application.setComponent(ILogObserver, PythonLoggingObserver().emit) + +agentprotocol_factory = AgentProtocolFactory() + +agentService = internet.TCPServer(settings.LISTEN_PORT, agentprotocol_factory) +agentService.setServiceParent(application) + +amqp_factory = AmqpFactory( + vhost=settings.AMQP_VHOST, + user=settings.AMQP_USER, + password=settings.AMQP_PASSWORD, + spec_file=settings.AMQP_SPEC) + +# set up circular references... +agentprotocol_factory.amqp = amqp_factory +amqp_factory.agentprotocol = agentprotocol_factory + +amqp_endpint = TCP4ClientEndpoint( + reactor, settings.AMQP_HOST, settings.AMQP_PORT) +amqp_connection = amqp_endpint.connect(amqp_factory) +# amqp_connection.addCallback(gotProtocol) diff --git a/gridagentserver/agentserver/__init__.py b/gridagentserver/agentserver/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gridagentserver/agentserver/amqp.py b/gridagentserver/agentserver/amqp.py new file mode 100644 index 0000000..87cecd6 --- /dev/null +++ b/gridagentserver/agentserver/amqp.py @@ -0,0 +1,289 @@ +import json +import logging + +from twisted.internet import protocol, reactor +from twisted.internet.defer import inlineCallbacks +from twisted.python import log +from txamqp.client import TwistedDelegate +from txamqp.content import Content +from txamqp.protocol import AMQClient +from txamqp.spec import load as load_spec + +from gridagentserver_protocol.server_messages import ( + CommandGpSwitchRelay, + CommandGpSwitchControl, + ConfigGaSoftware, + ConfigGpSoftware, + ConfigGaRulesets, +) +from gridagentserver_protocol.datatypes import ( + Meter, + RuleSet, + Rule, +) + +logger = logging.getLogger(__name__) + + +# factory has: +# * user +# * password +# * exchange +# * exchange_type +# * incoming (queue) +# * outgoing (queue) +# * routes + +# connect -> authenticate -> open channel -> +# declare exchange -> declare "private" (exclusive=True) queue for input +class AmqpProtocol(AMQClient): + def __init__(self, *args, **kwargs): + AMQClient.__init__(self, *args, **kwargs) + self._routes = set() + self._adding_routes = set() + self._removing_routes = set() + + @inlineCallbacks + def connectionMade(self): + # connected to server --- not ready to communicate... + AMQClient.connectionMade(self) + log.msg('connected to server') + self.connected = False + # authenticate + yield self.authenticate(self.factory.user, self.factory.password) + log.msg('authenticated as %s' % (self.factory.user,)) + # open channel + self.chan = yield self.channel(1) + log.msg('got channel') + yield self.chan.channel_open() + log.msg('channel opened') + # declare exchange + yield self.chan.exchange_declare( + exchange=self.factory.exchange, + type=self.factory.exchange_type) + log.msg('exchange (%s, %s) declared' % ( + self.factory.exchange, self.factory.exchange_type)) + # declare queue + result = yield self.chan.queue_declare(exclusive=True) + self.queue_name = result.queue + log.msg('queue (%s) declared' % (self.queue_name,)) + # consume + result = yield self.chan.basic_consume( + queue=self.queue_name, no_ack=True) + self.consumer_tag = result.consumer_tag + log.msg('started consuming (tag: %s)' % (self.consumer_tag,)) + queue = yield self.queue(self.consumer_tag) + d = queue.get() + d.addCallback(self._read_item, queue) + + self.connected = True + + self.routes_updated() + # self.send() + + def routes_updated(self): + """ + Tries to bring the current set of registered routes to the state + specified on the factory. + """ + # We have/use this rather than direct access to add and remove methods, + # to handle the edge cases where a route is to be added/removed while + # it is in the process of being removed/added. + desired_routes = self.factory._routes + to_add = desired_routes - self._routes + to_remove = self._routes - desired_routes + for route in to_add - self._adding_routes: + self._add_route(route) + for route in to_remove - self._removing_routes: + self._remove_route(route) + + @inlineCallbacks + def _add_route(self, routing_key): + assert routing_key not in self._routes + assert routing_key not in self._adding_routes + self._adding_routes.add(routing_key) + yield self.chan.queue_bind(queue=self.queue_name, + exchange=self.factory.exchange, + routing_key=routing_key) + self._adding_routes.remove(routing_key) + self._routes.add(routing_key) + # Check the overall current state of routes --- we might need to remove + # the route we just added again... + log.msg('route (%s) added' % (routing_key,)) + self.routes_updated() + + @inlineCallbacks + def _remove_route(self, routing_key): + assert routing_key in self._routes + assert routing_key not in self._removing_routes + self._removing_routes.add(routing_key) + yield self.chan.queue_unbind(queue=self.queue_name, + exchange=self.factory.exchange, + routing_key=routing_key) + self._removing_routes.remove(routing_key) + self._routes.remove(routing_key) + # Check the overall current state of routes --- we might need to add + # the route we just removed back in... + log.msg('route (%s) removed' % (routing_key,)) + self.routes_updated() + + def _read_item(self, item, queue): + self.factory.received(item) + queue.get().addCallback(self._read_item, queue) + + def send(self, routing_key, msg): + msg = Content(msg) + self.chan.basic_publish(exchange=self.factory.exchange, + routing_key=routing_key, + content=msg) + + +def clean_version(major, minor, revision, extra): + return (int(major), int(minor), int(revision), str(extra)) + + +class AmqpFactory(protocol.ReconnectingClientFactory): + protocol = AmqpProtocol + + def __init__(self, spec_file=None, vhost=None, user=None, password=None): + spec_file = spec_file or 'amqp0-8.stripped.rabbitmq.xml' + self.spec = load_spec(spec_file) + self.user = user or 'guest' + self.password = password or 'guest' + self.vhost = vhost or '/' + self.delegate = TwistedDelegate() + self.exchange = 'agentservers' + self.exchange_type = 'topic' + self._routes = set(['agentserver']) + self.p = None + reactor.addSystemEventTrigger('before', 'shutdown', self.cleanup) + + def cleanup(self): + logger.info('cleaning up twisted connection') + return self.p.chan.channel_close() + + def buildProtocol(self, addr): + self.p = self.protocol(self.delegate, self.vhost, self.spec) + self.p.factory = self + # Reset the reconnection delay since we're connected now. + self.resetDelay() + return self.p + + # ... WTF? + def clientConnectionFailed(self, connector, reason): + print "Connection failed." + protocol.ReconnectingClientFactory.clientConnectionLost( + self, connector, reason) + + def clientConnectionLost(self, connector, reason): + print "Client connection lost." + self.p = None + protocol.ReconnectingClientFactory.clientConnectionFailed( + self, connector, reason) + + def add_route(self, routing_key): + self._routes.add(routing_key) + if self.p and self.p.connected: + self.p.routes_updated() + + def remove_route(self, routing_key): + self._routes.remove(routing_key) + if self.p and self.p.connected: + self.p.routes_updated() + + def send(self, routing_key, msg): + if self.p is not None and self.p.connected: + self.p.send(routing_key, msg) + + def received(self, msg): + try: + body = msg.content.body + properties = msg.content.properties + content_type = properties.get('content type', None) + assert content_type == 'application/json' + data = json.loads(body) + command = data['command'] + logger.debug('handling command: %s', command) + assert command in self.commands + method = getattr(self, command) + agent = data.get('agent', None) + logger.debug('IPC message: %s', body) + if agent is not None: + agent_mac = int(data['agent'], base=16) + handler = self.agentprotocol.handlers.get(agent_mac, None) + if handler is not None: + method(agent_mac, handler, data) + else: + method(data) + except Exception as e: + logger.warning('Error handling IPC message: %s', e) + logger.debug('Error handling IPC message: %s, message: %s', e, msg) + + commands = { + 'current_agents', + 'relay_state', + 'control_mode', + 'gridagent_rules', + 'gridagent_software', + 'gridpoint_software', + } + + def current_agents(self, data): + logger.info('Connected agents: %s', [ + 'agent: %s, serial: %s, sw: %s, hw: %s' % ( + h.agent_mac, h.serial, h.sw_version, h.hw_revision) + for h in self.agentprotocol.handlers.values()]) + + def relay_state(self, agent_mac, handler, data): + relay_on = data['relay_on'] + meters = [Meter(m['connection_type'], m['id']) for m in data['meters']] + for meter in meters: + message = CommandGpSwitchRelay(meter, relay_on) + handler.outgoing.put(message) + + def control_mode(self, agent_mac, handler, data): + control_manual = data['control_manual'] + meters = [Meter(m['connection_type'], m['id']) for m in data['meters']] + for meter in meters: + message = CommandGpSwitchControl(meter, control_manual) + handler.outgoing.put(message) + + def gridagent_software(self, agent_mac, handler, data): + name_template = 'sw/{}-hw{:02d}_{:02d}_{:02d}{}-' \ + 'sw{:02d}_{:02d}_{:02d}{}.hex' + filename = name_template.format( + data['hw_model'], + *(data['target_hw_version'] + data['sw_version'])) + with open(filename) as f: + image = f.read() + message = ConfigGaSoftware(clean_version(*data['sw_version']), + data['hw_model'], + clean_version(*data['target_hw_version']), + image) + handler.outgoing.put(message) + + def gridpoint_software(self, agent_mac, handler, data): + meters = [Meter(m['connection_type'], m['id']) for m in data['meters']] + name_template = 'sw/{}-hw{:02d}_{:02d}_{:02d}{}-' \ + 'sw{:02d}_{:02d}_{:02d}{}.hex' + filename = name_template.format( + data['hw_model'], + *(data['target_hw_version'] + data['sw_version'])) + with open(filename) as f: + image = f.read() + message = ConfigGpSoftware(clean_version(*data['sw_version']), + data['hw_model'], + clean_version(*data['target_hw_version']), + image, + meters) + handler.outgoing.put(message) + + def gridagent_rules(self, agent_mac, handler, data): + rulesets = [ + RuleSet(0, + [Rule(**rule) for rule in ruleset['rules']], + [Meter(**meter) for meter in ruleset['meters']]) + for ruleset in data['rulesets']] + + message = ConfigGaRulesets(rulesets) + handler.outgoing.put(message) diff --git a/gridagentserver/agentserver/db.py b/gridagentserver/agentserver/db.py new file mode 100644 index 0000000..23177d2 --- /dev/null +++ b/gridagentserver/agentserver/db.py @@ -0,0 +1,172 @@ +""" +Database interface exposing (limited) functionality as functions. +""" +# TODO: calculation points and rules are not yet defined in GridPlatform +import logging +import numbers + +from legacy.devices.models import Agent, Meter, PhysicalInput, AgentEvent + +logger = logging.getLogger(__name__) + + +BUCKINGHAM_MAP = { + 0: 'none', # unknown unit + 1: "milliwatt*hour", + 2: "milliwatt", + 3: "impulse", + 4: "milliliter", + 5: "milliliter*hour^-1", + 6: "millikelvin", + 7: "millivolt", + 8: "milliampere", + 9: "millihertz", + 10: "gram", + 11: "millibar", + 12: "second", + 13: "none", # "binary states" + 14: "millinone", # "milli" power factor +} + + +# for models with encrypted fields, we store the empty string for those fields +# (representing the encrypted form of the empty string) but we still need +# "something" for an initialisation vector to avoid special cases in decryption +fake_iv = bytearray('\x00' * 16) + +# TODO: We need a cache clean-up method once we introduce GAS load +# balancing +value_cache = {} + + +def agent_exists(agent_mac): + return Agent.objects.filter(mac=agent_mac).exists() + + +def get_agent(agent_mac): + if isinstance(agent_mac, Agent): + return agent_mac + elif isinstance(agent_mac, numbers.Number): + return Agent.objects.get(mac=agent_mac) + else: + raise Exception('Invalid data type for agent MAC: {}'.format( + agent_mac)) + + +def set_agent_info(agent_mac, serial, device_type, hw_version, sw_version): + agent = get_agent(agent_mac) + agent._set_info(serial, device_type, hw_version, sw_version) + + +def get_meter(meter_id, agent_mac): + agent = get_agent(agent_mac) + connection_type, manufactoring_id = meter_id + obj, created = Meter.objects.get_or_create( + connection_type=connection_type, + manufactoring_id=manufactoring_id, + agent=agent, + customer_id=agent.customer_id, + defaults={ + 'encryption_data_initialization_vector': fake_iv, + 'location_id': agent.location_id, + }) + return obj + + +def get_physicalinput(datatype, agent_unit, input_number, meter): + if agent_unit in BUCKINGHAM_MAP: + obj, created = PhysicalInput.objects.get_or_create( + customer_id=meter.customer_id, + type=datatype, unit=BUCKINGHAM_MAP[agent_unit], + order=input_number, meter=meter, + defaults={ + 'encryption_data_initialization_vector': fake_iv, + 'store_measurements': True, + 'hardware_id': + 'GA-{agent_id:012x}-{meter_id:016x}-{input_id}'.format( + agent_id=int(meter.agent.mac), + meter_id=meter.manufactoring_id, + input_id=input_number, + ) + }) + return obj + else: + logger.warning( + 'Unsupported unit %s from meter %d input %d.' % ( + agent_unit, meter, input_number)) + return None + + +def set_meter_state(control_manual, relay_on, online, timestamp, + meter_id, agent_mac): + meter = get_meter(meter_id, agent_mac) + meter._set_state(control_manual, relay_on, online, timestamp) + + +def set_agent_online(online, timestamp, agent_mac): + agent = get_agent(agent_mac) + agent._set_online(online, timestamp) + + +def set_agent_add_mode(add_mode, timestamp, agent_mac): + agent = get_agent(agent_mac) + agent._set_add_mode(add_mode, timestamp) + + +def store_event(mac, timestamp, code, text): + agent = Agent.objects.get(mac=mac) + AgentEvent.objects.create( + agent=agent, timestamp=timestamp, code=code, message=text) + + +def set_meters_online(mac, meter_list, version_list, device_opts_list): + agent = get_agent(mac) + if version_list and device_opts_list: + for meter_id, versions, device_opts in \ + zip(meter_list, version_list, device_opts_list): + connection_type, manufactoring_id = meter_id + try: + meter = Meter.objects.get( + connection_type=connection_type, + manufactoring_id=manufactoring_id, + agent=agent, + customer_id=agent.customer_id) + except Meter.DoesNotExist: + # Quick fix for bug in GridAgent SW version 2.3.0. + # It sometimes sends junk in the meters connected set. + continue + meter.online = True + meter.device_type = device_opts[0] + meter.hw_major = versions[0].major + meter.hw_minor = versions[0].minor + meter.hw_revision = versions[0].revision + meter.hw_subrevision = \ + versions[0].revisionstring.decode('iso8859-1') + meter.sw_major = versions[1].major + meter.sw_minor = versions[1].minor + meter.sw_revision = versions[1].revision + meter.sw_subrevision = \ + versions[1].revisionstring.decode('iso8859-1') + meter.save(update_fields=[ + 'online', + 'device_type', + 'hw_major', 'hw_minor', 'hw_revision', 'hw_subrevision', + 'sw_major', 'sw_minor', 'sw_revision', 'sw_subrevision', + ]) + else: + # missing version_list or device_opts_list --- data from old agent + # sw version which does not provide this... + for meter_id in meter_list: + connection_type, manufactoring_id = meter_id + try: + meter = Meter.objects.get( + connection_type=connection_type, + manufactoring_id=manufactoring_id, + agent=agent, + customer_id=agent.customer_id) + except Meter.DoesNotExist: + # Quick fix for bug in GridAgent SW version 2.3.0. + # It sometimes sends junk in the meters connected set. + continue + meter.online = True + meter.save(update_fields=['online']) diff --git a/gridagentserver/agentserver/settings.py b/gridagentserver/agentserver/settings.py new file mode 100644 index 0000000..82256f7 --- /dev/null +++ b/gridagentserver/agentserver/settings.py @@ -0,0 +1,95 @@ +# Django/agent server configuration +import datetime + +from configurations import Settings + + +class Base(Settings): + TIME_ZONE = 'UTC' + USE_TZ = True + + INSTALLED_APPS = ( + 'gridplatform.encryption', + 'gridplatform.users', + 'gridplatform.customers', + 'legacy.devices', + 'legacy.measurementpoints', + 'gridplatform.datasequences', + ) + + SECRET_KEY = 'abc' + + # agent server config... + POLL_INTERVAL = 60.0 + POLL_START_DELAY = 15.0 + + TIME_SYNC_INTERVAL = datetime.timedelta(days=1) + TIME_SYNC_TOLERANCE = 15.0 + + LISTEN_PORT = 30001 + + AMQP_PORT = 5672 + AMQP_VHOST = '/' + AMQP_USER = "guest" + AMQP_PASSWORD = "guest" + AMQP_SPEC = 'amqp0-8.stripped.rabbitmq.xml' + + SITE_NAME = 'gridplatform' + + +class Prod(Base): + SITE_MAIL_ADDRESS = "no-reply@grid-manager.com" + AMQP_HOST = "engine.grid-manager.com" + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'gridportal', + 'USER': 'grid', + 'PASSWORD': 'ugOk9Blim', + 'HOST': '77.66.29.230', + 'PORT': '5432', + } + } + + +class Local(Base): + AMQP_HOST = 'localhost' + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'portal', + # Current *nix user have local sockec access... + 'USER': '', + 'PASSWORD': '', + 'HOST': '', + 'PORT': '', + } + } + + +# Configuration for the GreenTech Center server. The server is physically +# located at the GTC in Vejle, Denmark. +class GreenTech(Local): + SITE_MAIL_ADDRESS = "no-reply@greentech.gridmanager.dk" + + +# Configuration for the server at Cheminova. Will be running for approximately +# 3 months. +class Cheminova(Local): + SITE_MAIL_ADDRESS = "no-reply@cheminova.gridmanager.dk" + + +# For the GridManager Iberia server. Located in Spain, managed by Netgroup. +class Iberia(Local): + SITE_MAIL_ADDRESS = "no-reply@iberia.grid-manager.com" + + +class Test(Local): + SITE_MAIL_ADDRESS = "no-reply@test.grid-manager.com" + + +class Dev(Local): + DEBUG = True + EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' diff --git a/gridagentserver/agentserver/twisted_server.py b/gridagentserver/agentserver/twisted_server.py new file mode 100644 index 0000000..0c170ee --- /dev/null +++ b/gridagentserver/agentserver/twisted_server.py @@ -0,0 +1,337 @@ +from __future__ import absolute_import + +import datetime +import logging +import traceback + +from django.db import DatabaseError +from django.db import close_connection +from django.db import transaction +from pytz import utc +from twisted.internet import reactor +from twisted.internet import task +from twisted.internet import threads + +from gridagentserver_protocol import server_messages +from gridagentserver_protocol.client_messages import AcknowledgementGaSoftware +from gridagentserver_protocol.client_messages import AcknowledgementGpSoftware +from gridagentserver_protocol.client_messages import ErrorGaSoftware +from gridagentserver_protocol.client_messages import ErrorGpSoftware +from gridagentserver_protocol.server_messages import ConfigGaSoftware +from gridagentserver_protocol.server_messages import ConfigGpSoftware +from gridagentserver_protocol.twisted_protocol import BaseAgentProtocol +from gridagentserver_protocol.twisted_protocol import BaseAgentProtocolFactory +from legacy.devices.models import Agent +from legacy.devices.models import RawData + +from . import db +from . import settings + + +logger = logging.getLogger(__name__) + + +WATER_FREEZING_POINT_MILLIKELVIN = 273150 + + +class AgentProtocol(BaseAgentProtocol): + def __init__(self): + BaseAgentProtocol.__init__(self) + self.polling = None + self.syncing = None + self.incoming.get().addCallback(self.process_message) + self.agent_mac = None + # self.software_message = None + self.sw_version = None + self.hw_revision = None + self.serial = None + self.poll_response_pending = False + + def pause_sending_after(self, message): + if isinstance(message, (ConfigGpSoftware, ConfigGaSoftware)): + # self.software_message = message + return True + else: + return False + + def resume_sending_after(self, message): + if isinstance(message, (AcknowledgementGpSoftware, + AcknowledgementGaSoftware)): + # self.software_message = None + return True + elif isinstance(message, (ErrorGpSoftware, ErrorGaSoftware)): + # self.send_message(self.software_message) + # return False + # NOTE: continue normal processing on "error" + # TODO: put in event log...? + return True + else: + return False + + # Messages from the "incoming" queue should be handled in background + # threads for the database access, but one at a time to serialise the + # database access per agent connection... + def process_message(self, message): + logger.debug('Processing message %s for %X', message, self.agent_mac) + background_task = threads.deferToThread( + self.do_process_message, message) + + # Attach (and possibly immediately call) callback to handle next + # incoming message as soon as the background processing of the current + # message is done. (The return value of the background call is + # provided as argument.) + def attach_next_callback(_ignored): + deferred = self.incoming.get() + deferred.addCallback(self.process_message) + background_task.addCallback(attach_next_callback) + + def do_process_message(self, message): + try: + message.accept(self) + except DatabaseError as e: + logger.warning('DatabaseError on processing message: %s', e) + logger.warning(traceback.format_exc()) + close_connection() + + def register(self): + logger.info('Agent %X connected', self.other_id) + old_replaced = BaseAgentProtocol.register(self) + if old_replaced: + logger.info('Replaced old handler for %X', self.agent_mac) + self.store_online(initial=True) + + def store_online(self, initial=False): + timestamp = datetime.datetime.utcnow().replace(tzinfo=utc) + + def does_not_exist_handler(failure): + failure.trap(Agent.DoesNotExist) + logger.info('Unknown agent %X; disconnecting', self.agent_mac) + self.transport.loseConnection() + return failure + + @transaction.commit_on_success + def background_store_online(): + db.set_agent_online(True, timestamp, self.agent_mac) + + background_task = threads.deferToThread(background_store_online) + background_task.addErrback(does_not_exist_handler) + background_task.addCallback(self.stored_online) + if initial: + background_task.addCallback(self.delayed_start_periodic) + + def stored_online(self, _ignored=None): + assert self.agent_mac + if self.agent_mac not in self.factory.handlers: + # currently offline, so undo setting it online + self.store_offline() + + def unregister(self): + replaced = BaseAgentProtocol.unregister(self) + self.stop_periodic() + if not self.agent_mac: + return + if replaced: + logger.info('Agent %X already reconnected', self.agent_mac) + else: + logger.info('Agent %X disconnected', self.agent_mac) + self.store_offline() + + def store_offline(self): + timestamp = datetime.datetime.utcnow().replace(tzinfo=utc) + + @transaction.commit_on_success + def background_store_offline(): + db.set_agent_online(False, timestamp, self.agent_mac) + background_task = threads.deferToThread(background_store_offline) + background_task.addCallback(self.stored_offline) + + def stored_offline(self, _ignored=None): + if self.agent_mac and self.agent_mac in self.factory.handlers: + # currently online, so undo setting it offline... + self.store_online() + + def start_periodic(self, _ignored=None): + logger.debug('Starting periodic tasks for %X', self.agent_mac) + + def poll(): + if self.poll_response_pending: + logger.info( + 'Agent %s did not respond to poll in time; disconnecting', + self.agent_mac) + self.transport.loseConnection() + else: + self.poll_response_pending = True + self.outgoing.put(server_messages.CommandGaPollMeasurements()) + + self.polling = task.LoopingCall(poll) + self.polling.start(settings.POLL_INTERVAL, now=False) + + def sync(): + timestamp = datetime.datetime.utcnow().replace(tzinfo=utc) + self.outgoing.put(server_messages.ConfigGaTime(timestamp)) + + self.syncing = task.LoopingCall(sync) + self.syncing.start(settings.TIME_SYNC_INTERVAL.total_seconds(), + now=True) + + def delayed_start_periodic(self, _ignored=None): + reactor.callLater(10, self.start_periodic) + + def stop_periodic(self): + if self.agent_mac: + logger.debug('Stopping periodic tasks for %X', self.agent_mac) + if self.polling: + self.polling.stop() + if self.syncing: + self.syncing.stop() + + @transaction.commit_on_success + def visit_bulk_measurements(self, message): + self.poll_response_pending = False + meter_ids = set([ + meter + for meter, measurement_sets in message.meter_data]) + meters = { + meter_id: db.get_meter(meter_id, self.agent_mac) + for meter_id in meter_ids} + + physicalinput_params = set() + + for meter_id, measurement_sets in message.meter_data: + for timestamp, measurements in measurement_sets: + for measurement in measurements: + datatype, agent_unit, input_number, value = measurement + physicalinput_params.add( + (datatype, agent_unit, input_number, meter_id)) + physicalinputs = { + (datatype, agent_unit, input_number, meter_id): + db.get_physicalinput( + datatype, agent_unit, input_number, meters[meter_id]) + for (datatype, agent_unit, input_number, meter_id) + in physicalinput_params + if db.get_physicalinput( + datatype, agent_unit, input_number, meters[meter_id]) + } + + result_measurements = [] + + for meter_id, measurement_sets in message.meter_data: + for timestamp, measurements in measurement_sets: + if timestamp.tzinfo is None: + aware_timestamp = timestamp.replace(tzinfo=utc) + else: + aware_timestamp = timestamp + for measurement in measurements: + datatype, agent_unit, input_number, value = measurement + if (datatype, agent_unit, input_number, meter_id) not in \ + physicalinputs: + # Ignore inputs with unsupported units + continue + physicalinput = physicalinputs[ + (datatype, agent_unit, input_number, meter_id)] + if aware_timestamp > datetime.datetime.now(utc) + \ + datetime.timedelta(days=1): + # FIXME: Temporary workaround for GridLink bug; + # sometimes gives spurious future data. To be removed + # ASAP, after making/deploying GridLink fix. + # skip storing this wrong data to the database... + continue + if physicalinput.store_measurements: + # FIXME: Temporary work-around for GridAgents reporting + # absolute temperatures in Celsius. + MILLIKELVIN = 6 + if agent_unit == MILLIKELVIN: + result_measurements.append( + RawData( + datasource=physicalinput, + value=( + measurement.value + + WATER_FREEZING_POINT_MILLIKELVIN), + timestamp=aware_timestamp)) + else: + result_measurements.append( + RawData( + datasource=physicalinput, + value=measurement.value, + timestamp=aware_timestamp)) + RawData.objects.bulk_create(result_measurements) + + @transaction.commit_on_success + def visit_notification_ga_add_mode(self, message): + db.set_agent_add_mode(message.in_add_mode, message.timestamp, + self.agent_mac) + + # avoid background thread? + def visit_notification_ga_time(self, message): + now = datetime.datetime.utcnow().replace(tzinfo=utc) + diff = message.timestamp.replace(tzinfo=utc) - now + if abs(diff.total_seconds()) < settings.TIME_SYNC_TOLERANCE: + reactor.callFromThread(self.outgoing.put, + server_messages.CommandGaPropagateTime()) + else: + reactor.callFromThread(self.outgoing.put, + server_messages.ConfigGaTime(now)) + + @transaction.commit_on_success + def visit_notification_ga_connected_set(self, message): + logger.debug('Agent %X reported meters %s', + self.agent_mac, message.meters) + db.set_meters_online(self.agent_mac, message.meters, message.versions, + message.device_opts) + + @transaction.commit_on_success + def visit_notification_gp_state(self, message): + db.set_meter_state(message.control_manual, message.relay_on, + message.online, message.timestamp, + message.meter, self.agent_mac) + + @transaction.commit_on_success + def visit_info_agent_versions(self, message): + self.sw_version = message.sw_version + self.device_type = message.device_type + self.hw_revision = message.hw_revision + self.serial = message.serial + if self.serial < 0: + logger.warning('Invalid serial#: %s, agent: %X', + self.serial, self.agent_mac) + self.serial = 0 + db.set_agent_info(self.agent_mac, self.serial, self.device_type, + self.hw_revision, self.sw_version) + + @transaction.commit_on_success + def visit_info_event_log(self, message): + db.store_event( + self.agent_mac, + message.timestamp, + message.code, + message.text) + + # @transaction.commit_on_success + def send_complete_configuration(self, conn): + """Obtain and send configuration for agent.""" + # TODO: implement... + + +# must initialise self.amqp after init +class AgentProtocolFactory(BaseAgentProtocolFactory): + protocol = AgentProtocol + + def __init__(self): + BaseAgentProtocolFactory.__init__(self) + + def register(self, handler): + result = BaseAgentProtocolFactory.register(self, handler) + self.amqp.add_route('agent.{:012x}'.format(handler.agent_mac)) + return result + + def unregister(self, handler): + replaced = BaseAgentProtocolFactory.unregister(self, handler) + if not replaced and handler.agent_mac: + self.amqp.remove_route('agent.{:012x}'.format(handler.agent_mac)) + return replaced + + def startFactory(self): + logger.info('Started') + + def stopFactory(self): + logger.info('Stopping') diff --git a/gridagentserver/all_messages.py b/gridagentserver/all_messages.py new file mode 100755 index 0000000..2a74630 --- /dev/null +++ b/gridagentserver/all_messages.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +import pika + + +mqhost = 'localhost' + + +def callback(ch, method, properties, body): + print '%s: %s' % (method.routing_key, body) + + +def all_agent_messages(): + connection = pika.BlockingConnection(pika.ConnectionParameters( + host=mqhost)) + channel = connection.channel() + channel.exchange_declare(exchange='agentservers', exchange_type='topic') + result = channel.queue_declare(exclusive=True) + queue_name = result.method.queue + channel.queue_bind(exchange='agentservers', + queue=queue_name, + routing_key='agentserver') + channel.queue_bind(exchange='agentservers', + queue=queue_name, + routing_key='agent.*') + channel.basic_consume(callback, queue=queue_name, no_ack=True) + channel.start_consuming() + + +if __name__ == '__main__': + all_agent_messages() diff --git a/gridagentserver/amqp0-8.stripped.rabbitmq.xml b/gridagentserver/amqp0-8.stripped.rabbitmq.xml new file mode 100644 index 0000000..d1fd2c0 --- /dev/null +++ b/gridagentserver/amqp0-8.stripped.rabbitmq.xml @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gridagentserver/amqp0-9-1.stripped.xml b/gridagentserver/amqp0-9-1.stripped.xml new file mode 100644 index 0000000..fa95d99 --- /dev/null +++ b/gridagentserver/amqp0-9-1.stripped.xml @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gridagentserver/client.py b/gridagentserver/client.py new file mode 100644 index 0000000..8e5499c --- /dev/null +++ b/gridagentserver/client.py @@ -0,0 +1,59 @@ +from string import hexdigits +from struct import Struct +import json +import re + +import pika + + +mqhost = 'engine.grid-manager.com' +#mqhost = 'localhost' + + +def send_message(routing_key, message, verbose=False, dry_run=False): + if not dry_run: + connection = pika.BlockingConnection(pika.ConnectionParameters( + host=mqhost)) + channel = connection.channel() + channel.exchange_declare(exchange='agentservers', + exchange_type='topic') + channel.basic_publish(exchange='agentservers', + routing_key=routing_key, + properties=pika.BasicProperties( + content_type='application/json'), + body=json.dumps(message)) + connection.close() + if verbose: + print 'message:\n%s\n(routing key %s)' % ( + json.dumps(message, indent=2), routing_key) + if dry_run: + print '(not sent)' + else: + print '(sent)' + + +def normalise_mac(mac, bytes=6): + norm = filter(lambda c: c in hexdigits, mac.lower()) + if len(norm) != bytes * 2: + raise Exception('invalid mac address %s (%s)' % (mac, norm)) + return norm + + +number_splitter = re.compile(r'^(\d+)(.*)$') + + +def normalise_version(version): + major, minor, revision = version.split('.') + revision, extra = number_splitter.match(revision).groups() + return (int(major), int(minor), int(revision), extra) + + +uint64 = Struct('!Q') +int64 = Struct('!q') + + +def gridpoint_id(mac): + n = int(mac, base=16) + m, = int64.unpack(uint64.pack(n)) + # 1 for connection type ZigBee + return {'connection_type': 1, 'id': m} diff --git a/gridagentserver/control_mode.py b/gridagentserver/control_mode.py new file mode 100755 index 0000000..e51f9aa --- /dev/null +++ b/gridagentserver/control_mode.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# dry-run example command: +# ./control_mode.py -n -v 00:24:21:0e:8f:cd --manual \ +# aa:bb:cc:dd:11:22:33:44 11:22:33:44:aa:bb:cc:dd + +import argparse + +from client import normalise_mac, send_message, gridpoint_id + + +parser = argparse.ArgumentParser() +parser.add_argument('agent', help='target agent (MAC address)') +parser.add_argument('meters', nargs='+', + help='target meters (ZigBee MAC addresses)') +parser.add_argument('-v', '--verbose', action='store_true', + help='increase output verbosity') +parser.add_argument('-n', '--dry-run', action='store_true', + help='don\'t actually send command') +group = parser.add_mutually_exclusive_group(required=True) +group.add_argument('-a', '--auto', action='store_true', help='auto mode') +group.add_argument('-m', '--manual', action='store_true', help='manual mode') + + +def control_mode(args): + agent_mac = normalise_mac(args.agent) + meters = [gridpoint_id(normalise_mac(meter, bytes=8)) + for meter in args.meters] + routing_key = 'agent.%s' % (agent_mac,) + assert args.manual != args.auto + control_manual = args.manual + message = { + 'command': 'control_mode', + 'agent': agent_mac, + 'control_manual': control_manual, + 'meters': meters, + } + send_message(routing_key, message, args.verbose, args.dry_run) + + +if __name__ == '__main__': + control_mode(parser.parse_args()) diff --git a/gridagentserver/current_agents.py b/gridagentserver/current_agents.py new file mode 100755 index 0000000..84f4f2c --- /dev/null +++ b/gridagentserver/current_agents.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +# dry-run example command: +# ./current_agents.py -n -v + +import argparse + +from client import send_message + + +parser = argparse.ArgumentParser() +parser.add_argument('-v', '--verbose', action='store_true', + help='increase output verbosity') +parser.add_argument('-n', '--dry-run', action='store_true', + help='don\'t actually send command') + + +def current_agents(args): + routing_key = 'agentserver' + message = { + 'command': 'current_agents', + } + send_message(routing_key, message, args.verbose, args.dry_run) + + +if __name__ == '__main__': + current_agents(parser.parse_args()) diff --git a/gridagentserver/gas-check.sh b/gridagentserver/gas-check.sh new file mode 100755 index 0000000..4158bbb --- /dev/null +++ b/gridagentserver/gas-check.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +cd $(dirname $0) + +maxmemusage=$((300*1024)) +pidfile='twistd.pid' +if [ -a $pidfile ]; then + pid=`cat $pidfile` + mem=`ps --pid $pid -o rss --no-headers` + + if [ -z $mem ]; then + echo 'GridAgent ERROR: GAS was dead. Reviving it now!' + source $HOME/ve/bin/activate + ./start.sh + else + if [ $pid -gt $maxmemusage ]; then + echo 'GridAgent ERROR: GAS used too much memory! Restarting it!' + source $HOME/ve/bin/activate + ./stop.sh + ./start.sh + fi + fi +elif [ ! -e $HOME/gas-stopped-intentionally ]; then + echo 'GridAgent ERROR: GAS was not started. Starting it now!' + source $HOME/ve/bin/activate + ./start.sh +fi diff --git a/gridagentserver/gridagentserver_protocol b/gridagentserver/gridagentserver_protocol new file mode 120000 index 0000000..6070ff0 --- /dev/null +++ b/gridagentserver/gridagentserver_protocol @@ -0,0 +1 @@ +../gridagentserver-protocol/gridagentserver_protocol \ No newline at end of file diff --git a/gridagentserver/gridplatform b/gridagentserver/gridplatform new file mode 120000 index 0000000..0e3399d --- /dev/null +++ b/gridagentserver/gridplatform @@ -0,0 +1 @@ +../gridplatform \ No newline at end of file diff --git a/gridagentserver/gridportal b/gridagentserver/gridportal new file mode 120000 index 0000000..7e56798 --- /dev/null +++ b/gridagentserver/gridportal @@ -0,0 +1 @@ +../gridportal/gridportal \ No newline at end of file diff --git a/gridagentserver/legacy b/gridagentserver/legacy new file mode 120000 index 0000000..6e0542b --- /dev/null +++ b/gridagentserver/legacy @@ -0,0 +1 @@ +../legacy \ No newline at end of file diff --git a/gridagentserver/logging.ini b/gridagentserver/logging.ini new file mode 100644 index 0000000..c7e10e6 --- /dev/null +++ b/gridagentserver/logging.ini @@ -0,0 +1,64 @@ +[loggers] +keys=root,agentserver,protocol,twisted + +[handlers] +keys=warn,info,debug,debug_stderr + +[formatters] +keys=default + +[logger_root] +level=WARNING +handlers=warn + +[logger_agentserver] +level=DEBUG +# running as daemon redirects stderr to /dev/null... +# handlers=debug_stderr,debug,info +handlers=debug,info +# handlers=info +propagate=1 +qualname=agentserver + +[logger_protocol] +level=DEBUG +# running as daemon redirects stderr to /dev/null... +# handlers=debug_stderr,debug,info +handlers=debug,info +# handlers=info +propagate=1 +qualname=gridagentserver_protocol + +[logger_twisted] +level=DEBUG +handlers=debug,info +propagate=1 +qualname=twisted + +[handler_debug_stderr] +class=StreamHandler +level=DEBUG +formatter=default +args=() + +[handler_debug] +class=handlers.RotatingFileHandler +level=DEBUG +formatter=default +args=('debug.log', 'a', 16*1024*1024, 9) + +[handler_info] +class=handlers.RotatingFileHandler +level=INFO +formatter=default +args=('info.log', 'a', 1024*1024, 9) + +[handler_warn] +class=handlers.RotatingFileHandler +level=WARNING +formatter=default +args=('warn.log', 'a', 1024*1024, 9) + + +[formatter_default] +format=%(asctime)-15s %(levelname)s: %(message)s (%(name)s %(funcName)s) diff --git a/gridagentserver/meter_software.py b/gridagentserver/meter_software.py new file mode 100755 index 0000000..3222990 --- /dev/null +++ b/gridagentserver/meter_software.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +# dry-run example command: +# ./meter_software.py 3C970E1E8E4E 2.1.1 3.0.9 0000aabbcc000009 -v -n + +import argparse + +from client import normalise_mac, normalise_version, send_message, gridpoint_id + + +parser = argparse.ArgumentParser() +parser.add_argument('agent', help='target agent (MAC address)') +parser.add_argument('sw_version', help='software version (n.n.n[extra])') +parser.add_argument('-m', '--model', + help='hardware model', default=3) +parser.add_argument('target_hw_version', + help='compatible hardware version (n.n.n[extra])') +parser.add_argument('meters', nargs='+', + help='target meters (ZigBee MAC addresses)') +parser.add_argument('-v', '--verbose', action='store_true', + help='increase output verbosity') +parser.add_argument('-n', '--dry-run', action='store_true', + help='don\'t actually send command') + + +def meter_swupdate(args): + agent_mac = normalise_mac(args.agent) + sw_version = normalise_version(args.sw_version) + hw_model = int(args.model) + hw_version = normalise_version(args.target_hw_version) + meters = [gridpoint_id(normalise_mac(meter, bytes=8)) + for meter in args.meters] + routing_key = 'agent.%s' % (agent_mac,) + message = { + 'command': 'gridpoint_software', + 'agent': agent_mac, + 'sw_version': sw_version, + 'hw_model': hw_model, + 'target_hw_version': hw_version, + 'meters': meters, + } + send_message(routing_key, message, args.verbose, args.dry_run) + + +if __name__ == '__main__': + meter_swupdate(parser.parse_args()) diff --git a/gridagentserver/notes/AFT_NOTES.txt b/gridagentserver/notes/AFT_NOTES.txt new file mode 100644 index 0000000..10dc9ce --- /dev/null +++ b/gridagentserver/notes/AFT_NOTES.txt @@ -0,0 +1,4 @@ + +- README + +- Short design document. A full document will be required once we got to GridPlatform 2.0.0 diff --git a/gridagentserver/notes/accessService.wsdl b/gridagentserver/notes/accessService.wsdl new file mode 100644 index 0000000..dce6979 --- /dev/null +++ b/gridagentserver/notes/accessService.wsdl @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Service definition of function __ns1__agentsUpdated + + + + + Service definition of function __ns1__switchOn + + + + + Service definition of function __ns1__switchOff + + + + + Service definition of function __ns1__switchCancel + + + + + Service definition of function __ns1__controlAuto + + + + + Service definition of function __ns1__controlManual + + + + + Service definition of function __ns1__controlCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gSOAP 2.7.13 generated service definition + + + + + diff --git a/gridagentserver/notes/notificationService.wsdl b/gridagentserver/notes/notificationService.wsdl new file mode 100644 index 0000000..481068a --- /dev/null +++ b/gridagentserver/notes/notificationService.wsdl @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gridagentserver/notes/setup_on_old_ubuntu.txt b/gridagentserver/notes/setup_on_old_ubuntu.txt new file mode 100644 index 0000000..981ddb8 --- /dev/null +++ b/gridagentserver/notes/setup_on_old_ubuntu.txt @@ -0,0 +1,27 @@ +# Current setup on test.gridmanager.dk +# (Ubuntu 10.04 has Python 2.6; we need 2.7.) + +# So; local install in homedir +# Note: Shell-init adds $HOME/bin to start of $PATH if it exists. + +wget http://python.org/ftp/python/2.7.3/Python-2.7.3.tgz +tar xzf Python-2.7.3.tgz +cd Python-2.7.3 +./configure --prefix=$HOME +make +make install +export PATH=$HOME/bin:$PATH +wget http://python-distribute.org/distribute_setup.py +python distribute_setup.py +easy_install pip + + +# Could have done +# pip install virtualenv +# and used script from here... + + +pip install SQLAlchemy +pip install python-daemon +pip install pysimplesoap +... diff --git a/gridagentserver/relay_state.py b/gridagentserver/relay_state.py new file mode 100755 index 0000000..b5de8ec --- /dev/null +++ b/gridagentserver/relay_state.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# dry-run example command: +# ./relay_state.py -n -v 00:24:21:0e:8f:cd --on aa:bb:cc:dd:11:22:33:44 \ +# 11:22:33:44:aa:bb:cc:dd + +import argparse + +from client import normalise_mac, send_message, gridpoint_id + + +parser = argparse.ArgumentParser() +parser.add_argument('agent', help='target agent (MAC address)') +parser.add_argument('meters', nargs='+', + help='target meters (ZigBee MAC addresses)') +parser.add_argument('-v', '--verbose', action='store_true', + help='increase output verbosity') +parser.add_argument('-n', '--dry-run', action='store_true', + help='don\'t actually send command') +group = parser.add_mutually_exclusive_group(required=True) +group.add_argument('-o', '--on', action='store_true', help='switch relay on') +group.add_argument('-f', '--off', action='store_true', help='switch relay off') + + +def relay_state(args): + agent_mac = normalise_mac(args.agent) + meters = [gridpoint_id(normalise_mac(meter, bytes=8)) + for meter in args.meters] + routing_key = 'agent.%s' % (agent_mac,) + assert args.on != args.off + relay_on = args.on + message = { + 'command': 'relay_state', + 'agent': agent_mac, + 'relay_on': relay_on, + 'meters': meters, + } + send_message(routing_key, message, args.verbose, args.dry_run) + + +if __name__ == '__main__': + relay_state(parser.parse_args()) diff --git a/gridagentserver/requirements.txt b/gridagentserver/requirements.txt new file mode 100644 index 0000000..ef5258e --- /dev/null +++ b/gridagentserver/requirements.txt @@ -0,0 +1,20 @@ +Django==1.6.5 # high-level Python Web framework +django-configurations==0.1 # more flexible settings.py configuration +django-durationfield==0.4.0 # field type representing datetime.timedelta +django-historicalrecords==1.0 # generic history for Django models. +django-mptt==0.5.5 # implementing Modified Preorder Tree Traversal with Django Models +django-timezones2==1.0.4 # helper for pytz +isoweek==1.2.0 # translating ISO week numbers to datetime dates +pika==0.9.13 # AMQP (message queue) client library +psycopg2==2.5 # PostgreSQL driver +pycrypto==2.6 # cryptography toolkit +python-dateutil==2.1 # real month deltas +pytz==2013b # brings the Olson timezone database into Python +south==0.8.4 # database migrations +Twisted==13.0.0 # cooperative multithreading/network server +txAMQP==0.6.1 # async message queue client integrating with Twisted +django-model-utils==2.0.2 # utilities for models and managers +celery==3.1.8 # Python background task queue/runner +Pillow==2.4.0 # Python Image Library distribution; may require libjpeg-dev for JPEG support +pilkit==1.1.6 # dependency of django-imagekit +django-imagekit==3.0.1 # ProcessedImageField for Django diff --git a/gridagentserver/start.sh b/gridagentserver/start.sh new file mode 100755 index 0000000..6e635f1 --- /dev/null +++ b/gridagentserver/start.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +cd `dirname $0` + +twistd -y agentserver.tac +rm -f $HOME/gas-stopped-intentionally diff --git a/gridagentserver/stop.sh b/gridagentserver/stop.sh new file mode 100755 index 0000000..a848533 --- /dev/null +++ b/gridagentserver/stop.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +cd `dirname $0` + +if [ -e twistd.pid ] +then + kill `cat twistd.pid` +fi +touch $HOME/gas-stopped-intentionally diff --git a/gridplatform/__init__.py b/gridplatform/__init__.py new file mode 100644 index 0000000..263aedd --- /dev/null +++ b/gridplatform/__init__.py @@ -0,0 +1,7 @@ +from __future__ import absolute_import + +# This will make sure the app is always imported when +# Django starts so that shared_task will use this app. +from .celery import app as celery_app # noqa + +__version__ = 'v2.2.1' diff --git a/gridplatform/api.py b/gridplatform/api.py new file mode 100644 index 0000000..eeb0f3a --- /dev/null +++ b/gridplatform/api.py @@ -0,0 +1,288 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from collections import OrderedDict + +import rest_framework.viewsets +import rest_framework.reverse + +import gridplatform.rest.routers +import gridplatform.consumptions.viewsets +import gridplatform.cost_compensations.viewsets +import gridplatform.customer_datasources.viewsets +import gridplatform.customers.viewsets +import gridplatform.datasequences.viewsets +import gridplatform.energyperformances.viewsets +import gridplatform.energyperformances.views +import gridplatform.global_datasources.viewsets +import gridplatform.productions.viewsets +import gridplatform.provider_datasources.viewsets +import gridplatform.tariffs.viewsets +import energymanager.price_relay_site.viewsets + + +class EnergyPerformances(rest_framework.viewsets.ViewSet): + _ignore_model_permissions = True + + def list(self, request, format=None): + return rest_framework.response.Response(OrderedDict(sorted([ + ('production_energyperformances', rest_framework.reverse.reverse( + 'api:energyperformances:productionenergyperformance-list', + request=request, format=format)), + ('time_energyperformances', rest_framework.reverse.reverse( + 'api:energyperformances:timeenergyperformance-list', + request=request, format=format)), + ]))) + + +class DataSequences(rest_framework.viewsets.ViewSet): + _ignore_model_permissions = True + + def list(self, request, format=None): + return rest_framework.response.Response(OrderedDict(sorted([ + ('main_consumptions', rest_framework.reverse.reverse( + 'api:consumptions:mainconsumption-list', + request=request, format=format)), + ('consumption_groups', rest_framework.reverse.reverse( + 'api:consumptions:consumptiongroup-list', + request=request, format=format)), + ('consumption_datasequences', rest_framework.reverse.reverse( + 'api:consumptions:consumption-list', + request=request, format=format)), + ('production_groups', rest_framework.reverse.reverse( + 'api:productions:productiongroup-list', + request=request, format=format)), + ('production_datasequences', rest_framework.reverse.reverse( + 'api:productions:production-list', + request=request, format=format)), + ('energy_per_volume_datasequences', rest_framework.reverse.reverse( + 'api:datasequences:energypervolumedatasequence-list', + request=request, format=format)), + ('nonaccumulation_datasequences', rest_framework.reverse.reverse( + 'api:datasequences:nonaccumulationdatasequence-list', + request=request, format=format)), + ('energy_tariff_datasequences', rest_framework.reverse.reverse( + 'api:tariffs:energytariff-list', + request=request, format=format)), + ('volume_tariff_datasequences', rest_framework.reverse.reverse( + 'api:tariffs:volumetariff-list', + request=request, format=format)), + ('cost_compensation_datasequences', rest_framework.reverse.reverse( + 'api:cost_compensations:costcompensation-list', + request=request, format=format)), + ]))) + + +class DataSources(rest_framework.viewsets.ViewSet): + _ignore_model_permissions = True + + def list(self, request, format=None): + return rest_framework.response.Response(OrderedDict(sorted([ + ('global_datasources', rest_framework.reverse.reverse( + 'api:global_datasources:globaldatasource-list', + request=request, format=format)), + ('provider_datasources', rest_framework.reverse.reverse( + 'api:provider_datasources:providerdatasource-list', + request=request, format=format)), + ('customer_datasources', rest_framework.reverse.reverse( + 'api:customer_datasources:customerdatasource-list', + request=request, format=format)), + ]))) + + +root_routes = gridplatform.rest.routers.DefaultRouter() +root_routes.description = """ +# Welcome to the GridPlatform API. + +The URL +[https://portal.grid-manager.com/api/current](https://portal.grid-manager.com/api/current) +will always redirect to the current version of the API. + +Authentication is either done by logging in with username and password, which +is practical when navigating the browsable API to familiarise oneself with the +available resources, or it can be done using an authentication token, which is +the normal way of accessing the API programmatically. + +To get an authentication token you must contact your GridPlatform access +provider and make then issue you a suitable one. + +The token must be part of the header of every HTTP request. The HTTP headers +should be extended with the following line: + + Authorization: token + +where is the API authentication token. A token is just a text string +and might look something like this: + + 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b + + +## Filter Fields +* GET list resource data has a property called `filterFields` containing + a list of field names. Each name is this list can be used a querystring + parameter for filtering the list results on equality for the that fields + value. +* OPTIONS for a list resource shows all the possible actions for that + resource, and more. One of the properties for each field is `filterField`. + It is either `null` (i.e. the field is not a filter field) or contains the + query string parameter name corresponding to that field. The query string + parameter can be used for filtering the list, checking for equality on that + field. + +## Bulk Actions +* OPTIONS for list a resource may contain a `bulkActions` property containing a + list of HTTP actions that support bulk operation. Currently only bulk + creation (POST) is supported, and that is only on the various data source + `rawData` list resources. To perform a `rawData` bulk creation simply POST an + array of `rawData` objects to the relevant `rawData` list resource. + +# API Root +""" +root_routes.register( + r'customers', gridplatform.customers.viewsets.CustomerViewSet) + +energyperformance_routes = root_routes.register( + r'energy_performances', EnergyPerformances, base_name='energyperformances') +energyperformance_routes.register( + r'production_energy_performances', + gridplatform.energyperformances.viewsets.ProductionEnergyPerformance) +energyperformance_routes.register( + r'time_energy_performances', + gridplatform.energyperformances.viewsets.TimeEnergyPerformance) + +datasequence_routes = root_routes.register( + r'datasequences', DataSequences, base_name='datasequences') +datasequence_routes.register( + r'main_consumptions', + gridplatform.consumptions.viewsets.MainConsumption) +datasequence_routes.register( + r'consumption_groups', + gridplatform.consumptions.viewsets.ConsumptionGroup) +datasequence_routes.register( + r'production_groups', + gridplatform.productions.viewsets.ProductionGroup) + +consumption_routes = datasequence_routes.register( + r'consumption_datasequences', + gridplatform.consumptions.viewsets.Consumption) +consumption_routes.register( + r'offline_tolerances', + gridplatform.consumptions.viewsets.OfflineTolerance, + filter_by='datasequence_id') +consumption_routes.register( + r'nonpulse_periods', + gridplatform.consumptions.viewsets.NonpulsePeriod, + filter_by='datasequence_id') +consumption_routes.register( + r'pulse_periods', + gridplatform.consumptions.viewsets.PulsePeriod, + filter_by='datasequence_id') +consumption_routes.register( + r'single_value_periods', + gridplatform.consumptions.viewsets.SingleValuePeriod, + filter_by='datasequence_id') + +production_routes = datasequence_routes.register( + r'production_datasequences', + gridplatform.productions.viewsets.Production) +production_routes.register( + r'offline_tolerances', + gridplatform.productions.viewsets.OfflineTolerance, + filter_by='datasequence_id') +production_routes.register( + r'nonpulse_periods', + gridplatform.productions.viewsets.NonpulsePeriod, + filter_by='datasequence_id') +production_routes.register( + r'pulse_periods', + gridplatform.productions.viewsets.PulsePeriod, + filter_by='datasequence_id') +production_routes.register( + r'single_value_periods', + gridplatform.productions.viewsets.SingleValuePeriod, + filter_by='datasequence_id') + +energypervolume_routes = datasequence_routes.register( + r'energy_per_volume_datasequences', + gridplatform.datasequences.viewsets.EnergyPerVolumeDataSequence) +energypervolume_routes.register( + r'energy_per_volume_periods', + gridplatform.datasequences.viewsets.EnergyPerVolumePeriod, + filter_by='datasequence_id') + +nonaccumulation_routes = datasequence_routes.register( + r'nonaccumulation_datasequences', + gridplatform.datasequences.viewsets.NonaccumulationDataSequence) +nonaccumulation_routes.register( + r'nonaccumulation_periods', + gridplatform.datasequences.viewsets.NonaccumulationPeriod, + filter_by='datasequence_id') +nonaccumulation_routes.register( + r'offline_tolerances', + gridplatform.datasequences.viewsets.NonaccumulationOfflineTolerance, + filter_by='datasequence_id') + +energytariff_routes = datasequence_routes.register( + r'energytariffs', + gridplatform.tariffs.viewsets.EnergyTariff) +energytariff_routes.register( + 'fixed_price_periods', + gridplatform.tariffs.viewsets.FixedPricePeriod, + filter_by='datasequence_id') +energytariff_routes.register( + 'spot_price_periods', + gridplatform.tariffs.viewsets.SpotPricePeriod, + filter_by='datasequence_id') + +volumetariff_routes = datasequence_routes.register( + r'volumetariffs', + gridplatform.tariffs.viewsets.VolumeTariff) +volumetariff_routes.register( + 'fixed_price_periods', + gridplatform.tariffs.viewsets.FixedPricePeriod, + filter_by='datasequence_id') +volumetariff_routes.register( + 'spot_price_periods', + gridplatform.tariffs.viewsets.SpotPricePeriod, + filter_by='datasequence_id') + + +cost_compensation_routes = datasequence_routes.register( + r'cost_compensation', + gridplatform.cost_compensations.viewsets.CostCompensation) +cost_compensation_routes.register( + 'fixed_compensation_period', + gridplatform.cost_compensations.viewsets.FixedCompensationPeriod, + filter_by='datasequence_id') + + +datasource_routes = root_routes.register( + r'datasources', DataSources, base_name='datasources') +datasource_routes.register( + r'raw_data', + gridplatform.datasources.viewsets.RawDataViewSet, + filter_by='datasource_id') +datasource_routes.register( + r'datasource', + gridplatform.datasources.viewsets.DataSourceViewSet) + +global_datasource_routes = datasource_routes.register( + r'global_datasources', + gridplatform.global_datasources.viewsets.GlobalDataSourceViewSet) + +provider_datasource_routes = datasource_routes.register( + r'provider_datasources', + gridplatform.provider_datasources.viewsets.ProviderDataSourceViewSet) + +customer_datasource_routes = datasource_routes.register( + r'customer_datasources', + gridplatform.customer_datasources.viewsets.CustomerDataSourceViewSet) + +root_routes.register( + r'pricerelays', + energymanager.price_relay_site.viewsets.RelaySettingsViewSet, + base_name='pricerelays' +) + +urlpatterns = root_routes.urls diff --git a/gridplatform/bootstrap/__init__.py b/gridplatform/bootstrap/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gridplatform/bootstrap/conf.py b/gridplatform/bootstrap/conf.py new file mode 100644 index 0000000..97f0931 --- /dev/null +++ b/gridplatform/bootstrap/conf.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +""" +.. py:data:: settings.BOOTSTRAP_THEME + + Defaults to 'base'. Templates used by Bootstrap tags in this app are + loaded from the template path 'bootstrap//'. See also + :meth:`gridplatform.bootstrap.templatetags.bootstrap_tags.BootstrapNode.get_templates`. + +.. py:data:: settings.BOOTSTRAP_FORM_LAYOUT + + Layout applied by default to forms using + :func:`gridplatform.bootstrap.templatetags.bootstrap_tags.do_form` (``{% + form ... %}``) template tag. Must be one of "horizontal", "inline" and + "basic". + +Bootstrap uses a grid-layout so that cells in each row take up a total of 12 +columns. The following two settings are used to balance these 12 columns +between the label and the input field: + +.. py:data:: settings.BOOSTRAP_LABEL_COLUMNS + + Defaults to 2. + +.. py:data:: settings.BOOSTRAP_INPUT_COLUMNS + + Defaults to 10. +""" +from __future__ import absolute_import +from __future__ import unicode_literals + +from django.conf import settings + +from appconf import AppConf + + +__all__ = ['settings', 'BootstrapConf'] + + +class BootstrapConf(AppConf): + THEME = 'base' + # Default layout: "horizontal", "inline", "basic" + FORM_LAYOUT = 'horizontal' + # Default columns for label [1..12]: + FORM_LABEL_COLUMNS = 2 + # Default columns for field [1..12]: + FORM_INPUT_COLUMNS = 10 diff --git a/gridplatform/bootstrap/context_processors.py b/gridplatform/bootstrap/context_processors.py new file mode 100644 index 0000000..4ca14e7 --- /dev/null +++ b/gridplatform/bootstrap/context_processors.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from .conf import settings + + +def bootstrap(request): + """ + Provide template context variable boostrap_template for identifying what + theme is currently being used. This is needed in boostrap/base.html to load + the correct js and css files. + """ + return { + 'bootstrap_theme': settings.BOOTSTRAP_THEME, + } diff --git a/gridplatform/bootstrap/locale/da/LC_MESSAGES/django.mo b/gridplatform/bootstrap/locale/da/LC_MESSAGES/django.mo new file mode 100644 index 0000000..6a608d3 Binary files /dev/null and b/gridplatform/bootstrap/locale/da/LC_MESSAGES/django.mo differ diff --git a/gridplatform/bootstrap/locale/da/LC_MESSAGES/django.po b/gridplatform/bootstrap/locale/da/LC_MESSAGES/django.po new file mode 100644 index 0000000..6943e2d --- /dev/null +++ b/gridplatform/bootstrap/locale/da/LC_MESSAGES/django.po @@ -0,0 +1,73 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-10-23 14:38+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: templates/bootstrap/_navbar_base.html:63 +msgid "Profile" +msgstr "Profil" + +#: templates/bootstrap/_navbar_base.html:64 +msgid "Logout" +msgstr "Log ud" + +#: templates/bootstrap/base.html:114 +msgid "Confirm" +msgstr "Bekræft" + +#: templates/bootstrap/base.html:117 +msgid "Are you sure you want to delete this?" +msgstr "Er du sikker på, om du ønsker at slette dette?" + +#: templates/bootstrap/base.html:122 templatetags/bootstrap_tags.py:452 +msgid "Delete" +msgstr "Slet" + +#: templates/bootstrap/base.html:123 templatetags/bootstrap_tags.py:453 +msgid "Cancel" +msgstr "Annullér" + +#: templates/bootstrap/base/panel.html:8 +#: templates/bootstrap/genius/panel.html:9 +msgid "Search" +msgstr "Søg" + +#: templatetags/bootstrap_tags.py:451 +msgid "Save" +msgstr "Gem" + +#~ msgid "GridPortal" +#~ msgstr "GridPortal" + +#~ msgid "Sales" +#~ msgstr "Salg" + +#~ msgid "Configuration" +#~ msgstr "Konfiguration" + +#~ msgid "Product List" +#~ msgstr "Produktliste" + +#~ msgid "System Health" +#~ msgstr "Systemstatus" + +#~ msgid "Admin" +#~ msgstr "Admin" + +#~ msgid "Welcome!" +#~ msgstr "Velkommen!" diff --git a/gridplatform/bootstrap/locale/da/LC_MESSAGES/djangojs.mo b/gridplatform/bootstrap/locale/da/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..ee88cd4 Binary files /dev/null and b/gridplatform/bootstrap/locale/da/LC_MESSAGES/djangojs.mo differ diff --git a/gridplatform/bootstrap/locale/da/LC_MESSAGES/djangojs.po b/gridplatform/bootstrap/locale/da/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..bfa24b2 --- /dev/null +++ b/gridplatform/bootstrap/locale/da/LC_MESSAGES/djangojs.po @@ -0,0 +1,214 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-10-23 14:38+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: static/bootstrap/base.js:91 static/bootstrap/base.js.c:98 +msgid "Sunday" +msgstr "Søndag" + +#: static/bootstrap/base.js:92 +msgid "Monday" +msgstr "Mandag" + +#: static/bootstrap/base.js:93 +msgid "Tuesday" +msgstr "Tirsdag" + +#: static/bootstrap/base.js:94 +msgid "Wednesday" +msgstr "Onsdag" + +#: static/bootstrap/base.js:95 +msgid "Thursday" +msgstr "Torsdag" + +#: static/bootstrap/base.js:96 +msgid "Friday" +msgstr "Fredag" + +#: static/bootstrap/base.js:97 +msgid "Saturday" +msgstr "Lørdag" + +#: static/bootstrap/base.js:101 static/bootstrap/base.js.c:108 +msgid "Sun" +msgstr "Søn" + +#: static/bootstrap/base.js:102 +msgid "Mon" +msgstr "Man" + +#: static/bootstrap/base.js:103 +msgid "Tue" +msgstr "Tir" + +#: static/bootstrap/base.js:104 +msgid "Wed" +msgstr "Ons" + +#: static/bootstrap/base.js:105 +msgid "Thu" +msgstr "Tor" + +#: static/bootstrap/base.js:106 +msgid "Fri" +msgstr "Fre" + +#: static/bootstrap/base.js:107 +msgid "Sat" +msgstr "Lør" + +#: static/bootstrap/base.js:111 static/bootstrap/base.js.c:118 +msgctxt "weekday" +msgid "Su" +msgstr "Sø" + +#: static/bootstrap/base.js:112 +msgctxt "weekday" +msgid "Mo" +msgstr "Ma" + +#: static/bootstrap/base.js:113 +msgctxt "weekday" +msgid "Tu" +msgstr "Ti" + +#: static/bootstrap/base.js:114 +msgctxt "weekday" +msgid "We" +msgstr "On" + +#: static/bootstrap/base.js:115 +msgctxt "weekday" +msgid "Th" +msgstr "To" + +#: static/bootstrap/base.js:116 +msgctxt "weekday" +msgid "Fr" +msgstr "Fr" + +#: static/bootstrap/base.js:117 +msgctxt "weekday" +msgid "Sa" +msgstr "Lø" + +#: static/bootstrap/base.js:121 +msgid "January" +msgstr "Januar" + +#: static/bootstrap/base.js:122 +msgid "February" +msgstr "Februar" + +#: static/bootstrap/base.js:123 +msgid "March" +msgstr "Marts" + +#: static/bootstrap/base.js:124 +msgid "April" +msgstr "April" + +#: static/bootstrap/base.js:125 +msgid "May" +msgstr "Maj" + +#: static/bootstrap/base.js:126 +msgid "June" +msgstr "Juni" + +#: static/bootstrap/base.js:127 +msgid "July" +msgstr "Juli" + +#: static/bootstrap/base.js:128 +msgid "August" +msgstr "August" + +#: static/bootstrap/base.js:129 +msgid "September" +msgstr "Septemeber" + +#: static/bootstrap/base.js:130 +msgid "October" +msgstr "Oktober" + +#: static/bootstrap/base.js:131 +msgid "November" +msgstr "November" + +#: static/bootstrap/base.js:132 +msgid "December" +msgstr "December" + +#: static/bootstrap/base.js:135 +msgid "jan" +msgstr "jan" + +#: static/bootstrap/base.js:136 +msgid "feb" +msgstr "feb" + +#: static/bootstrap/base.js:137 +msgid "mar" +msgstr "mar" + +#: static/bootstrap/base.js:138 +msgid "apr" +msgstr "apr" + +#: static/bootstrap/base.js:139 +msgid "may" +msgstr "maj" + +#: static/bootstrap/base.js:140 +msgid "jun" +msgstr "jun" + +#: static/bootstrap/base.js:141 +msgid "jul" +msgstr "jul" + +#: static/bootstrap/base.js:142 +msgid "aug" +msgstr "aug" + +#: static/bootstrap/base.js:143 +msgid "sep" +msgstr "sep" + +#: static/bootstrap/base.js:144 +msgid "oct" +msgstr "okt" + +#: static/bootstrap/base.js:145 +msgid "nov" +msgstr "nov" + +#: static/bootstrap/base.js:146 +msgid "dec" +msgstr "dec" + +#: static/bootstrap/base.js:148 +msgid "Today" +msgstr "I dag" + +#: static/bootstrap/base.js:580 +msgid "Your changes are not saved" +msgstr "Dine ændringer er ikke gemt" diff --git a/gridplatform/bootstrap/locale/es/LC_MESSAGES/django.mo b/gridplatform/bootstrap/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000..217b194 Binary files /dev/null and b/gridplatform/bootstrap/locale/es/LC_MESSAGES/django.mo differ diff --git a/gridplatform/bootstrap/locale/es/LC_MESSAGES/django.po b/gridplatform/bootstrap/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000..8a580f8 --- /dev/null +++ b/gridplatform/bootstrap/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,54 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-09-15 13:43+0200\n" +"PO-Revision-Date: 2014-09-20 19:50+0100\n" +"Last-Translator: GMI \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: templates/bootstrap/_navbar_base.html:63 +msgid "Profile" +msgstr "Perfil" + +#: templates/bootstrap/_navbar_base.html:64 +msgid "Logout" +msgstr "Salir" + +#: templates/bootstrap/base.html:114 +msgid "Confirm" +msgstr "Confirmar" + +#: templates/bootstrap/base.html:117 +msgid "Are you sure you want to delete this?" +msgstr "¿Está seguro de que desea borrar este elemento?" + +#: templates/bootstrap/base.html:122 +#: templatetags/bootstrap_tags.py:452 +msgid "Delete" +msgstr "Borrar" + +#: templates/bootstrap/base.html:123 +#: templatetags/bootstrap_tags.py:453 +msgid "Cancel" +msgstr "Cancelar" + +#: templates/bootstrap/base/panel.html:8 +#: templates/bootstrap/genius/panel.html:9 +msgid "Search" +msgstr "Buscar" + +#: templatetags/bootstrap_tags.py:451 +msgid "Save" +msgstr "Guardar" + diff --git a/gridplatform/bootstrap/locale/es/LC_MESSAGES/djangojs.mo b/gridplatform/bootstrap/locale/es/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..069dafc Binary files /dev/null and b/gridplatform/bootstrap/locale/es/LC_MESSAGES/djangojs.mo differ diff --git a/gridplatform/bootstrap/locale/es/LC_MESSAGES/djangojs.po b/gridplatform/bootstrap/locale/es/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..3e0fb7c --- /dev/null +++ b/gridplatform/bootstrap/locale/es/LC_MESSAGES/djangojs.po @@ -0,0 +1,217 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-09-15 13:43+0200\n" +"PO-Revision-Date: 2014-09-20 19:54+0100\n" +"Last-Translator: GMI \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: static/bootstrap/base.js:91 +#: static/bootstrap/base.js.c:98 +msgid "Sunday" +msgstr "Domingo" + +#: static/bootstrap/base.js:92 +msgid "Monday" +msgstr "Lunes" + +#: static/bootstrap/base.js:93 +msgid "Tuesday" +msgstr "Martes" + +#: static/bootstrap/base.js:94 +msgid "Wednesday" +msgstr "Miercoles" + +#: static/bootstrap/base.js:95 +msgid "Thursday" +msgstr "Jueves" + +#: static/bootstrap/base.js:96 +msgid "Friday" +msgstr "Viernes" + +#: static/bootstrap/base.js:97 +msgid "Saturday" +msgstr "Sabado" + +#: static/bootstrap/base.js:101 +#: static/bootstrap/base.js.c:108 +msgid "Sun" +msgstr "Dom" + +#: static/bootstrap/base.js:102 +msgid "Mon" +msgstr "Lun" + +#: static/bootstrap/base.js:103 +msgid "Tue" +msgstr "Mar" + +#: static/bootstrap/base.js:104 +msgid "Wed" +msgstr "Mier" + +#: static/bootstrap/base.js:105 +msgid "Thu" +msgstr "Jue" + +#: static/bootstrap/base.js:106 +msgid "Fri" +msgstr "Vier" + +#: static/bootstrap/base.js:107 +msgid "Sat" +msgstr "Sab" + +#: static/bootstrap/base.js:111 +#: static/bootstrap/base.js.c:118 +msgctxt "weekday" +msgid "Su" +msgstr "Do" + +#: static/bootstrap/base.js:112 +msgctxt "weekday" +msgid "Mo" +msgstr "Lu" + +#: static/bootstrap/base.js:113 +msgctxt "weekday" +msgid "Tu" +msgstr "Ma" + +#: static/bootstrap/base.js:114 +msgctxt "weekday" +msgid "We" +msgstr "Mi" + +#: static/bootstrap/base.js:115 +msgctxt "weekday" +msgid "Th" +msgstr "Ju" + +#: static/bootstrap/base.js:116 +msgctxt "weekday" +msgid "Fr" +msgstr "Vi" + +#: static/bootstrap/base.js:117 +msgctxt "weekday" +msgid "Sa" +msgstr "Sa" + +#: static/bootstrap/base.js:121 +msgid "January" +msgstr "Enero" + +#: static/bootstrap/base.js:122 +msgid "February" +msgstr "Febrero" + +#: static/bootstrap/base.js:123 +msgid "March" +msgstr "Marzo" + +#: static/bootstrap/base.js:124 +msgid "April" +msgstr "Abril" + +#: static/bootstrap/base.js:125 +msgid "May" +msgstr "Mayo" + +#: static/bootstrap/base.js:126 +msgid "June" +msgstr "Junio" + +#: static/bootstrap/base.js:127 +msgid "July" +msgstr "Julio" + +#: static/bootstrap/base.js:128 +msgid "August" +msgstr "Agosto" + +#: static/bootstrap/base.js:129 +msgid "September" +msgstr "Septiembre" + +#: static/bootstrap/base.js:130 +msgid "October" +msgstr "Octubre" + +#: static/bootstrap/base.js:131 +msgid "November" +msgstr "Noviembre" + +#: static/bootstrap/base.js:132 +msgid "December" +msgstr "Diciembre" + +#: static/bootstrap/base.js:135 +msgid "jan" +msgstr "ene" + +#: static/bootstrap/base.js:136 +msgid "feb" +msgstr "feb" + +#: static/bootstrap/base.js:137 +msgid "mar" +msgstr "mar" + +#: static/bootstrap/base.js:138 +msgid "apr" +msgstr "abr" + +#: static/bootstrap/base.js:139 +msgid "may" +msgstr "may" + +#: static/bootstrap/base.js:140 +msgid "jun" +msgstr "jun" + +#: static/bootstrap/base.js:141 +msgid "jul" +msgstr "jul" + +#: static/bootstrap/base.js:142 +msgid "aug" +msgstr "ago" + +#: static/bootstrap/base.js:143 +msgid "sep" +msgstr "sep" + +#: static/bootstrap/base.js:144 +msgid "oct" +msgstr "oct" + +#: static/bootstrap/base.js:145 +msgid "nov" +msgstr "nov" + +#: static/bootstrap/base.js:146 +msgid "dec" +msgstr "dic" + +#: static/bootstrap/base.js:148 +msgid "Today" +msgstr "Hoy" + +#: static/bootstrap/base.js:580 +msgid "Your changes are not saved" +msgstr "Sus cambios no han sido guardados" + diff --git a/gridplatform/bootstrap/models.py b/gridplatform/bootstrap/models.py new file mode 100644 index 0000000..89c2ca5 --- /dev/null +++ b/gridplatform/bootstrap/models.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +from __future__ import unicode_literals + +from .conf import settings + + +__all__ = ['settings'] diff --git a/gridplatform/bootstrap/static/bootstrap/base.css b/gridplatform/bootstrap/static/bootstrap/base.css new file mode 100644 index 0000000..e5fdd19 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/base.css @@ -0,0 +1,146 @@ +#history-table .fa-arrow-right { + margin: 0 10px 0 10px; +} + +.ms-container { + width: auto; +} + +.appicon-wrapper { + width: 33%; + height: 100px; + float: left; + margin-bottom: 5px; + text-align:center; +} + +.appicon { + margin-left: auto; + margin-right: auto; + display: block; +} + +.app-switcher-menu { + width: 360px; + padding-top: 20px; +} + +.navbar-text { + background: transparent; + height: 40px; + width: auto; + padding: 8px 0 5px 10px!important; + margin: 0 0 0 3px; + position: relative; + color: #fff!important; +} + +.navbar-text span { + display: inline-block; + text-align: left; + margin-top: -5px; + padding: 0; +} + +span.disabled { + color: #aaa; +} + +.popover .close { + line-height: 150%; +} + +.popover h3 { + padding-right: 20px; +} + +.bar-legend { + list-style: none; + padding: 0; + float: right; + position: relative; +} + +.bar-legend li{ + float: left; + margin-left: 5px; +} + +.bar-legend li span{ + padding: 5px; +} + +#time-selection #id_week, #time-selection #id_year{ + width: 75px; +} + +#time-selection { + float: left; +} + +.graph-link { + float: right; +} + +.graph-link:after { + content:''; + display:block; + clear: both; +} + +@media only screen and (max-width: 767px) { + .pull-right { + width: 100%; + margin: 10px auto; + text-align: center; + } + + + + .light-dashboard .pull-left { + width: 100%; + margin: 10px auto; + text-align: center; + } + + .dropdown.pull-right { + width: auto; + margin: auto auto; + text-align: inherit; + } +} + +.dropdown a > span { + border-radius: 0; + margin: 0; + font-size: 14px; + line-height: 16px; + font-weight: 300; + top: 8px; + padding: 11px 15px; + height: 40px; + position: relative; + border-left: 1px solid #ced1d4; +} + +.dropdown > a { + text-decoration: none; +} + +.dropdown-menu { + top: 25px; +} + +.stats.led li { + width: 50%; +} + +.backgroundColor.darkgreen { + background: #637B3A; +} + +.info-boxes { + margin-left: -15px; + margin-right: -15px; +} + diff --git a/gridplatform/bootstrap/static/bootstrap/base.js b/gridplatform/bootstrap/static/bootstrap/base.js new file mode 100644 index 0000000..098e201 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/base.js @@ -0,0 +1,597 @@ +/*jslint browser: true */ +/*global $, jQuery, gettext, pgettext, get_format*/ + +var ui = window.ui || {}; + +// The javascript version of the icon templatetag +ui.icon = function (iconName, size, spin) { + 'use strict'; + var icon = $(''); + icon.addClass('fa-' + iconName); + if (size) { + icon.addClass('fa-' + size); + } + if (spin) { + icon.addClass('fa-spin'); + } + + //hack html() returns the html contents of the first node + return $('
').append(icon).html(); +}; + +ui.parseNumber = function (numberString) { + 'use strict'; + var thousandSeparator = get_format('THOUSAND_SEPARATOR'), + decimalSeparator = get_format('DECIMAL_SEPARATOR'); + while (numberString.length !== numberString.replace(thousandSeparator, '').length) { + numberString = numberString.replace(thousandSeparator, ''); + } + return parseFloat(numberString.replace(decimalSeparator, '.')); +}; + +ui.formatNumber = function (number, decimalPlaces) { + 'use strict'; + var formattedWithoutThousandSeparator = number.toFixed(decimalPlaces).replace('.', get_format('DECIMAL_SEPARATOR')), + addThousandSeparator = function (numberString, thousandSeparator) { + var rx = /(\d+)(\d{3})/; + return numberString.replace(/\d+/, function (w) { + while (rx.test(w)) { + w = w.replace(rx, '$1' + thousandSeparator + '$2'); + } + return w; + }); + }; + return addThousandSeparator(formattedWithoutThousandSeparator, get_format('THOUSAND_SEPARATOR')); +}; + +ui.addFormsetForm = function (event) { + 'use strict'; + event.preventDefault(); + var parent = $(event.target).closest('div.box'), + emptyForm = parent.find('.empty-form'), + newForm = emptyForm.clone(), + totalForms = parent.find('input[name$="TOTAL_FORMS"]'), + newId = totalForms.val(); + newForm.find('div, input, select, li, label').each(function () { + var input = $(this); + if (input.attr("name")) { + input.attr('name', input.attr('name').replace('__prefix__', newId)); + } + if (input.attr("id")) { + input.attr('id', input.attr('id').replace('__prefix__', newId)); + } + if (input.attr("for")) { + input.attr('for', input.attr('for').replace('__prefix__', newId)); + } + }); + newForm.removeClass('empty-form').show(); + totalForms.val(parseInt(totalForms.val(), 10) + 1); + newForm.appendTo(emptyForm.parent()); +}; + + +ui.datepickerOptions = (function () { + 'use strict'; + var format = get_format('DATE_INPUT_FORMATS')[0], + // Python/Django format to Bootstrap Datepicker format... + mapping = { + '%d': 'dd', + '%m': 'mm', + '%Y': 'yyyy', + '%y': 'yy' + }, + capitalize = function (str) { + return str.charAt(0).toUpperCase() + str.substring(1); + }; + _.forEach(mapping, function (js, python) { + format = format.replace(python, js); + }); + jQuery.fn.datepicker.dates.current = { + days: [ + gettext('Sunday'), + gettext('Monday'), + gettext('Tuesday'), + gettext('Wednesday'), + gettext('Thursday'), + gettext('Friday'), + gettext('Saturday'), + gettext('Sunday') + ], + daysShort: [ + gettext('Sun'), + gettext('Mon'), + gettext('Tue'), + gettext('Wed'), + gettext('Thu'), + gettext('Fri'), + gettext('Sat'), + gettext('Sun') + ], + daysMin: [ + pgettext('weekday', 'Su'), + pgettext('weekday', 'Mo'), + pgettext('weekday', 'Tu'), + pgettext('weekday', 'We'), + pgettext('weekday', 'Th'), + pgettext('weekday', 'Fr'), + pgettext('weekday', 'Sa'), + pgettext('weekday', 'Su') + ], + months: [ + capitalize(gettext('January')), + capitalize(gettext('February')), + capitalize(gettext('March')), + capitalize(gettext('April')), + capitalize(gettext('May')), + capitalize(gettext('June')), + capitalize(gettext('July')), + capitalize(gettext('August')), + capitalize(gettext('September')), + capitalize(gettext('October')), + capitalize(gettext('November')), + capitalize(gettext('December')) + ], + monthsShort: [ + capitalize(gettext('jan')), + capitalize(gettext('feb')), + capitalize(gettext('mar')), + capitalize(gettext('apr')), + capitalize(gettext('may')), + capitalize(gettext('jun')), + capitalize(gettext('jul')), + capitalize(gettext('aug')), + capitalize(gettext('sep')), + capitalize(gettext('oct')), + capitalize(gettext('nov')), + capitalize(gettext('dec')) + ], + today: gettext('Today') + }; + return { + // from Django i18n + weekStart: parseInt(get_format('FIRST_DAY_OF_WEEK'), 10), + format: format, + autoclose: true, + language: 'current' + }; +}()); + +/* + target: A jquery object that should have the popup attached + options: A list of filters + contentLoader: A jquery object containing the contentLoader div +*/ +ui.popoverFilter = function (target, options, contentLoader) { + 'use strict'; + var popop = $('
'), + content, + listContent, + filterContent, + label, + count, + countChecked, + checkbox, + selected = [], + popover, + extra = contentLoader.data('extra'); + + if (extra !== undefined) { + try { + extra = JSON.parse(extra); + } catch (err) { + extra = {}; + } + } else { + extra = {}; + } + jQuery.each(options, function (index, filter) { + if (extra[filter.name] === undefined) { + extra[filter.name] = []; + } + }); + filterContent = function () { + jQuery.each(options, function (index, filter) { + if (extra[filter.name]) { + selected = extra[filter.name]; + } + count = filter.choices.length; + countChecked = 0; + content = $('
').attr('id', filter.name).addClass('filter'); + + $('

').addClass('popover-title').text(filter.verbose).appendTo(content); + listContent = $('
').addClass('popover-content').appendTo(content); + jQuery.each(filter.choices, function (index, choice) { + label = $('
').appendTo(listContent); + checkbox = $('').val(choice[0]).appendTo(label); + if (_.contains(selected, String(choice[0]))) { + checkbox.prop('checked', true); + countChecked += 1; + } + $('').text(' ' + choice[1]).appendTo(label); + }); + if (filter.allNone) { + label = $('
').prependTo(listContent); + checkbox = $('').addClass('check-all').appendTo(label); + $('').text(' ' + filter.allNoneVerbose).appendTo(label); + if (countChecked === count) { + checkbox.prop('checked', true); + } else if (countChecked) { + checkbox.prop('indeterminate', true); + } + } + popop.append(content); + }); + + return popop; + }; + $(document).on('change', '.popover .filter input.check-all', function (event) { + checkbox = $(event.target); + var isChecked = checkbox.prop('checked'), + filter = checkbox.closest('.filter'); + filter.find('input:not(.check-all)').prop('checked', isChecked); + filter.find('input:not(.check-all)').change(); + }); + $(document).on('change', '.popover .filter input:not(.check-all)', function (event) { + var filter = $(event.target).closest('.filter'), + ids = [], + anyChecked = false, + anyUnchecked = false; + filter.find('input:not(.check-all)').each(function () { + checkbox = $(this); + if (checkbox.prop('checked')) { + ids.push(checkbox.attr('value')); + anyChecked = true; + } else { + anyUnchecked = true; + } + }); + if (anyChecked && anyUnchecked) { + filter.find('.check-all').prop('checked', false); + filter.find('.check-all').prop('indeterminate', true); + } else { + // all checked or all unchecked + filter.find('.check-all').prop('indeterminate', false); + filter.find('.check-all').prop('checked', anyChecked); + } + extra[filter.attr('id')] = ids; + ui.loadContent(contentLoader, extra, contentLoader.closest('.box').find('.list-search input').val()); + }); + + // Content needs to be an empty space, else it doesn't get shown + // We set the real content futher down + target.popover({ + html: true, + placement: 'bottom', + content: ' ', + title: '' + }); + + popover = target.data('bs.popover'); + popover.setContent = function () { + var $tip = this.tip(); + if (!$tip.hasClass('filter')) { + $tip.html(filterContent()); + } + $tip.removeClass('fade top bottom left right in').addClass('filter'); + }; +}; + + +ui.getQuerystrings = function (url) { + 'use strict'; + var querystrings = {}, + match, + pl = /\+/g, + search = /([^&=]+)=?([^&]*)/g, + decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, + query = ""; + + if (url === undefined) { + query = window.location.search.substring(1); + } else { + if (url.indexOf('?') !== -1) { + query = url.split('?')[1]; + } + } + + while (match = search.exec(query)) { + querystrings[decode(match[1])] = decode(match[2]); + } + return querystrings; +}; + +ui.updateLocationHash = function (hashObject, override) { + 'use strict'; + var currentHash = window.location.hash.replace(/^#/, ''), + override = override || false, + currentObject = {}; + + if (currentHash !== "") { + currentObject = JSON.parse(decodeURIComponent(currentHash)); + if (!override) { + hashObject = jQuery.extend(currentObject, hashObject); + } + } + + window.location.hash = encodeURIComponent( + JSON.stringify(hashObject)); +}; + +ui.getHashValueFromKey = function (key) { + var currentHash = window.location.hash.replace(/^#/, ''), + hashObject = {} + result = ""; + + if (currentHash !== "") { + hashObject = JSON.parse(decodeURIComponent(currentHash)); + if (hashObject[key]) { + result = hashObject[key]; + } + } + return result; +}; + +ui.generateStringHash = function (string) { + // Found at http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery + var hash = 0, + i, + chr, + len; + if (string.length === 0) { + return hash; + } + for (i = 0, len = string.length; i < len; i++) { + chr = string.charCodeAt(i); + hash = ((hash << 5) - hash) + chr; + hash |= 0; // Convert to 32bit integer + } + return hash; +}, + + +ui.loadContent = function (selector, extra, query) { + 'use strict'; + var load, + storageId = function (url, setting) { + // remove pagination and similar parameters from storage key + var baseUrl = url.replace(/\?.*$/, ''); + return 'contentLoader-' + baseUrl + '-' + setting; + }, + saveOptions = function (contentLoader) { + var options = contentLoader.data(), + url = options.url; + localStorage.setItem(storageId(url, 'orderby'), options.orderby); + localStorage.setItem(storageId(url, 'direction'), options.direction); + }, + loadOptions = function (contentLoader) { + var url = contentLoader.data('url'), + orderBy = localStorage.getItem(storageId(url, 'orderby')), + direction = localStorage.getItem(storageId(url, 'direction')), + extra = localStorage.getItem(storageId(url, 'extra')); + if (orderBy) { + contentLoader.data('orderby', orderBy); + } + if (direction) { + contentLoader.data('direction', direction); + } + if (extra !== null) { + contentLoader.data('extra', extra); + } + }, + setUpSorting = function (contentLoader) { + var options = contentLoader.data(); + // First remove the old sorting direction indicator + contentLoader.find('th').removeClass('sorting_asc sorting_desc'); + // Then add the current one + contentLoader.find('th[data-orderby="' + options.orderby + '"]'). + addClass('sorting_' + (options.direction || 'asc')); + // Make every sortable th clickable. + contentLoader.find('th.sorting').click(function () { + var sorting = $(this), + orderBy = sorting.data('orderby'); + if (orderBy === options.orderby) { + if (options.direction === 'asc' || !options.direction) { + contentLoader.data('direction', 'desc'); + } else { + contentLoader.data('direction', 'asc'); + } + } + contentLoader.data('orderby', orderBy); + saveOptions(contentLoader); + load(contentLoader); + }); + }, + setUpPagination = function (contentLoader) { + contentLoader.find('.pagination a').click(function (event) { + event.preventDefault(); + event.stopPropagation(); + contentLoader.data('url', $(this).attr('href')); + load(contentLoader); + }); + }, + updateLocationHash = function (contentLoader) { + var options = contentLoader.data(), + hashObject = {}, + page = ui.getQuerystrings(options.url).page; + if (page) { + hashObject[options.urlHash] = page; + ui.updateLocationHash(hashObject); + } + }, + urlHashString = function (url) { + var location = url; + if (url.indexOf('?') !== -1) { + location = url.split('?')[0]; + } + return ui.generateStringHash(location); + }, + extractPageFromHash = function (contentLoader, page) { + var pageFromHash = ui.getHashValueFromKey(contentLoader.data('urlHash')); + if (pageFromHash) { + return pageFromHash; + } + return page; + }; + load = function (contentLoader) { + var options = contentLoader.data(), + urlHash = options.urlHash || undefined, + page; + if (!options.url) { + throw "You must specify an URL for the content loader!"; + } + contentLoader.html(''); + if (!options.urlHash) { + urlHash = urlHashString(options.url); + contentLoader.data('urlHash', urlHash); + } + updateLocationHash(contentLoader); + page = extractPageFromHash(contentLoader, ui.getQuerystrings(options.url).page); + jQuery.ajax(options.url, { + type: 'GET', + data: { + o: options.orderby, + ot: options.direction || 'asc', + extra: options.extra || undefined, + page: page, + q: query + } + }).done(function (data) { + contentLoader.empty(); // Kill spinner + // Hack: jquery only searches inside the outmost block, + // so we have to append a div around the atual data + if (contentLoader.hasClass('search-block') && $('.no-data', $('
').append(data)).length > 0) { + contentLoader.closest('.box').fadeOut(500, function () { + $(this).remove(); + }); + } else { + contentLoader.append(data); + } + // Enable rowlink + contentLoader.find('table[data-provides="rowlink"]').rowlink(); + setUpSorting(contentLoader); + setUpPagination(contentLoader); + contentLoader.trigger('contentloader.loaded'); + }).fail(function () { + contentLoader.empty(); // Kill spinner + // TODO: Report (connection?) error? + }); + }; + $(selector).each(function () { + var contentLoader = $(this), + url; + if (extra !== undefined) { + url = contentLoader.data('url'); + localStorage.setItem(storageId(url, 'extra'), JSON.stringify(extra)); + } + loadOptions(contentLoader); + load(contentLoader); + }); +}; + + +ui.initializeSearchField = function (selector) { + 'use strict'; + var field = $(selector), + input = field.find('input'); + input.keydown(function (event) { + if (event.keyCode === 13) { + window.location = field.data('url') + '?q=' + encodeURIComponent(input.val()); + } + }); +}; + +$(document).ready(function () { + 'use strict'; + var changed = false, + submit = false; + // NOTE: wrap stuff in something with class empty-form to *not* use chosen or multiselect --- should be done for empyt_form for JS-insert in particular + $('select').not('.empty-form select, [multiple=multiple]').chosen({enable_split_word_search: true, search_contains: true}); + + $('select[multiple=multiple]').not('.empty-form select').multiSelect({ + selectableHeader: "", + selectionHeader: "", + afterInit: function () { + var multiselect = this, + selectableSearch = multiselect.$selectableUl.prev(), + selectionSearch = multiselect.$selectionUl.prev(), + selectableSearchString = '#' + multiselect.$container.attr('id') + ' .ms-elem-selectable:not(.ms-selected)', + selectionSearchString = '#' + multiselect.$container.attr('id') + ' .ms-elem-selection.ms-selected'; + + multiselect.qs1 = selectableSearch.quicksearch(selectableSearchString); + multiselect.qs2 = selectionSearch.quicksearch(selectionSearchString); + }, + afterSelect: function () { + this.qs1.cache(); + this.qs2.cache(); + }, + afterDeselect: function () { + this.qs1.cache(); + this.qs2.cache(); + } + }); + + $('.dateinput, .date-picker').datepicker(ui.datepickerOptions); + + $('.list-datepicker i').click(function () { + $(this).parent().find('input.date-picker').datepicker().focus(); + }); + + // Makes it possible to click on the icon to show the datepicker + $('#customerfilter').quicksearch('#customer-select-modal .list-group a'); + + ui.loadContent('.content-loader'); + ui.initializeSearchField('#search'); + + $('body').on('click', '.popover .close', function () { + $(this).parent().hide(); + }); + + // It should not be possible to generate two POSTs in a row by mistake. For + // this reason buttons can be decorated with the "disable-on-click" class. + $('.disable-reenable-on-click').click(function () { + var button = $(this); + button.addClass('disabled'); + window.setTimeout(function () { + button.removeClass('disabled'); + }, 500); + }); + + //Disable form submit on Enter press + $('form').bind("keyup keypress", function (e) { + var code = e.keyCode || e.which; + if (code === 13 && e.target.nodeName !== "TEXTAREA") { + e.preventDefault(); + return false; + } + }); + + $('form :input').not('.ms-selectable .search-input').change(function () { + changed = true; + }); + + $("form button[type=submit], form input[type=submit]").click(function () { + submit = true; + }); + + + window.onbeforeunload = function () { + if (changed && !submit) { + submit = false; + return gettext('Your changes are not saved'); + } + }; + + $('.list-search input').each(function () { + var input = $(this), + oldQuery = ''; + input.on('keydown keyup change cut paste input', _.debounce(function () { + var query = input.val(), + contentLoader; + if (query !== oldQuery) { + oldQuery = query; + contentLoader = input.closest('.box').find('.content-loader'); + ui.loadContent(contentLoader, undefined, query); + } + }, 250)); + }); +}); diff --git a/gridplatform/bootstrap/static/bootstrap/bean.js b/gridplatform/bootstrap/static/bootstrap/bean.js new file mode 100644 index 0000000..6e6e3ef --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/bean.js @@ -0,0 +1,503 @@ +/*! + * bean.js - copyright Jacob Thornton 2011 + * https://github.com/fat/bean + * MIT License + * special thanks to: + * dean edwards: http://dean.edwards.name/ + * dperini: https://github.com/dperini/nwevents + * the entire mootools team: github.com/mootools/mootools-core + */ +/*global module:true, define:true*/ +!function (name, context, definition) { + if (typeof module !== 'undefined') module.exports = definition(name, context); + else if (typeof define === 'function' && typeof define.amd === 'object') define(definition); + else context[name] = definition(name, context); +}('bean', this, function (name, context) { + var win = window + , old = context[name] + , overOut = /over|out/ + , namespaceRegex = /[^\.]*(?=\..*)\.|.*/ + , nameRegex = /\..*/ + , addEvent = 'addEventListener' + , attachEvent = 'attachEvent' + , removeEvent = 'removeEventListener' + , detachEvent = 'detachEvent' + , doc = document || {} + , root = doc.documentElement || {} + , W3C_MODEL = root[addEvent] + , eventSupport = W3C_MODEL ? addEvent : attachEvent + , slice = Array.prototype.slice + , mouseTypeRegex = /click|mouse|menu|drag|drop/i + , touchTypeRegex = /^touch|^gesture/i + , ONE = { one: 1 } // singleton for quick matching making add() do one() + + , nativeEvents = (function (hash, events, i) { + for (i = 0; i < events.length; i++) + hash[events[i]] = 1 + return hash + })({}, ( + 'click dblclick mouseup mousedown contextmenu ' + // mouse buttons + 'mousewheel DOMMouseScroll ' + // mouse wheel + 'mouseover mouseout mousemove selectstart selectend ' + // mouse movement + 'keydown keypress keyup ' + // keyboard + 'orientationchange ' + // mobile + 'focus blur change reset select submit ' + // form elements + 'load unload beforeunload resize move DOMContentLoaded readystatechange ' + // window + 'error abort scroll ' + // misc + (W3C_MODEL ? // element.fireEvent('onXYZ'... is not forgiving if we try to fire an event + // that doesn't actually exist, so make sure we only do these on newer browsers + 'show ' + // mouse buttons + 'input invalid ' + // form elements + 'touchstart touchmove touchend touchcancel ' + // touch + 'gesturestart gesturechange gestureend ' + // gesture + 'message readystatechange pageshow pagehide popstate ' + // window + 'hashchange offline online ' + // window + 'afterprint beforeprint ' + // printing + 'dragstart dragenter dragover dragleave drag drop dragend ' + // dnd + 'loadstart progress suspend emptied stalled loadmetadata ' + // media + 'loadeddata canplay canplaythrough playing waiting seeking ' + // media + 'seeked ended durationchange timeupdate play pause ratechange ' + // media + 'volumechange cuechange ' + // media + 'checking noupdate downloading cached updateready obsolete ' + // appcache + '' : '') + ).split(' ') + ) + + , customEvents = (function () { + function isDescendant(parent, node) { + while ((node = node.parentNode) !== null) { + if (node === parent) return true + } + return false + } + + function check(event) { + var related = event.relatedTarget + if (!related) return related === null + return (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString()) && !isDescendant(this, related)) + } + + return { + mouseenter: { base: 'mouseover', condition: check } + , mouseleave: { base: 'mouseout', condition: check } + , mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' } + } + })() + + , fixEvent = (function () { + var commonProps = 'altKey attrChange attrName bubbles cancelable ctrlKey currentTarget detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey srcElement target timeStamp type view which'.split(' ') + , mouseProps = commonProps.concat('button buttons clientX clientY dataTransfer fromElement offsetX offsetY pageX pageY screenX screenY toElement'.split(' ')) + , keyProps = commonProps.concat('char charCode key keyCode'.split(' ')) + , touchProps = commonProps.concat('touches targetTouches changedTouches scale rotation'.split(' ')) + , preventDefault = 'preventDefault' + , createPreventDefault = function (event) { + return function () { + if (event[preventDefault]) + event[preventDefault]() + else + event.returnValue = false + } + } + , stopPropagation = 'stopPropagation' + , createStopPropagation = function (event) { + return function () { + if (event[stopPropagation]) + event[stopPropagation]() + else + event.cancelBubble = true + } + } + , createStop = function (synEvent) { + return function () { + synEvent[preventDefault]() + synEvent[stopPropagation]() + synEvent.stopped = true + } + } + , copyProps = function (event, result, props) { + var i, p + for (i = props.length; i--;) { + p = props[i] + if (!(p in result) && p in event) result[p] = event[p] + } + } + + return function (event, isNative) { + var result = { originalEvent: event, isNative: isNative } + if (!event) + return result + + var props + , type = event.type + , target = event.target || event.srcElement + + result[preventDefault] = createPreventDefault(event) + result[stopPropagation] = createStopPropagation(event) + result.stop = createStop(result) + result.target = target && target.nodeType === 3 ? target.parentNode : target + + if (isNative) { // we only need basic augmentation on custom events, the rest is too expensive + if (type.indexOf('key') !== -1) { + props = keyProps + result.keyCode = event.which || event.keyCode + } else if (mouseTypeRegex.test(type)) { + props = mouseProps + result.rightClick = event.which === 3 || event.button === 2 + result.pos = { x: 0, y: 0 } + if (event.pageX || event.pageY) { + result.clientX = event.pageX + result.clientY = event.pageY + } else if (event.clientX || event.clientY) { + result.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft + result.clientY = event.clientY + doc.body.scrollTop + root.scrollTop + } + if (overOut.test(type)) + result.relatedTarget = event.relatedTarget || event[(type === 'mouseover' ? 'from' : 'to') + 'Element'] + } else if (touchTypeRegex.test(type)) { + props = touchProps + } + copyProps(event, result, props || commonProps) + } + return result + } + })() + + // if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both + , targetElement = function (element, isNative) { + return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element + } + + // we use one of these per listener, of any type + , RegEntry = (function () { + function entry(element, type, handler, original, namespaces) { + this.element = element + this.type = type + this.handler = handler + this.original = original + this.namespaces = namespaces + this.custom = customEvents[type] + this.isNative = nativeEvents[type] && element[eventSupport] + this.eventType = W3C_MODEL || this.isNative ? type : 'propertychange' + this.customType = !W3C_MODEL && !this.isNative && type + this.target = targetElement(element, this.isNative) + this.eventSupport = this.target[eventSupport] + } + + entry.prototype = { + // given a list of namespaces, is our entry in any of them? + inNamespaces: function (checkNamespaces) { + var i, j + if (!checkNamespaces) + return true + if (!this.namespaces) + return false + for (i = checkNamespaces.length; i--;) { + for (j = this.namespaces.length; j--;) { + if (checkNamespaces[i] === this.namespaces[j]) + return true + } + } + return false + } + + // match by element, original fn (opt), handler fn (opt) + , matches: function (checkElement, checkOriginal, checkHandler) { + return this.element === checkElement && + (!checkOriginal || this.original === checkOriginal) && + (!checkHandler || this.handler === checkHandler) + } + } + + return entry + })() + + , registry = (function () { + // our map stores arrays by event type, just because it's better than storing + // everything in a single array. uses '$' as a prefix for the keys for safety + var map = {} + + // generic functional search of our registry for matching listeners, + // `fn` returns false to break out of the loop + , forAll = function (element, type, original, handler, fn) { + if (!type || type === '*') { + // search the whole registry + for (var t in map) { + if (t.charAt(0) === '$') + forAll(element, t.substr(1), original, handler, fn) + } + } else { + var i = 0, l, list = map['$' + type], all = element === '*' + if (!list) + return + for (l = list.length; i < l; i++) { + if (all || list[i].matches(element, original, handler)) + if (!fn(list[i], list, i, type)) + return + } + } + } + + , has = function (element, type, original) { + // we're not using forAll here simply because it's a bit slower and this + // needs to be fast + var i, list = map['$' + type] + if (list) { + for (i = list.length; i--;) { + if (list[i].matches(element, original, null)) + return true + } + } + return false + } + + , get = function (element, type, original) { + var entries = [] + forAll(element, type, original, null, function (entry) { return entries.push(entry) }) + return entries + } + + , put = function (entry) { + (map['$' + entry.type] || (map['$' + entry.type] = [])).push(entry) + return entry + } + + , del = function (entry) { + forAll(entry.element, entry.type, null, entry.handler, function (entry, list, i) { + list.splice(i, 1) + if (list.length === 0) + delete map['$' + entry.type] + return false + }) + } + + // dump all entries, used for onunload + , entries = function () { + var t, entries = [] + for (t in map) { + if (t.charAt(0) === '$') + entries = entries.concat(map[t]) + } + return entries + } + + return { has: has, get: get, put: put, del: del, entries: entries } + })() + + // add and remove listeners to DOM elements + , listener = W3C_MODEL ? function (element, type, fn, add) { + element[add ? addEvent : removeEvent](type, fn, false) + } : function (element, type, fn, add, custom) { + if (custom && add && element['_on' + custom] === null) + element['_on' + custom] = 0 + element[add ? attachEvent : detachEvent]('on' + type, fn) + } + + , nativeHandler = function (element, fn, args) { + return function (event) { + event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, true) + return fn.apply(element, [event].concat(args)) + } + } + + , customHandler = function (element, fn, type, condition, args, isNative) { + return function (event) { + if (condition ? condition.apply(this, arguments) : W3C_MODEL ? true : event && event.propertyName === '_on' + type || !event) { + if (event) + event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, isNative) + fn.apply(element, event && (!args || args.length === 0) ? arguments : slice.call(arguments, event ? 0 : 1).concat(args)) + } + } + } + + , once = function (rm, element, type, fn, originalFn) { + // wrap the handler in a handler that does a remove as well + return function () { + rm(element, type, originalFn) + fn.apply(this, arguments) + } + } + + , removeListener = function (element, orgType, handler, namespaces) { + var i, l, entry + , type = (orgType && orgType.replace(nameRegex, '')) + , handlers = registry.get(element, type, handler) + + for (i = 0, l = handlers.length; i < l; i++) { + if (handlers[i].inNamespaces(namespaces)) { + if ((entry = handlers[i]).eventSupport) + listener(entry.target, entry.eventType, entry.handler, false, entry.type) + // TODO: this is problematic, we have a registry.get() and registry.del() that + // both do registry searches so we waste cycles doing this. Needs to be rolled into + // a single registry.forAll(fn) that removes while finding, but the catch is that + // we'll be splicing the arrays that we're iterating over. Needs extra tests to + // make sure we don't screw it up. @rvagg + registry.del(entry) + } + } + } + + , addListener = function (element, orgType, fn, originalFn, args) { + var entry + , type = orgType.replace(nameRegex, '') + , namespaces = orgType.replace(namespaceRegex, '').split('.') + + if (registry.has(element, type, fn)) + return element // no dupe + if (type === 'unload') + fn = once(removeListener, element, type, fn, originalFn) // self clean-up + if (customEvents[type]) { + if (customEvents[type].condition) + fn = customHandler(element, fn, type, customEvents[type].condition, true) + type = customEvents[type].base || type + } + entry = registry.put(new RegEntry(element, type, fn, originalFn, namespaces[0] && namespaces)) + entry.handler = entry.isNative ? + nativeHandler(element, entry.handler, args) : + customHandler(element, entry.handler, type, false, args, false) + if (entry.eventSupport) + listener(entry.target, entry.eventType, entry.handler, true, entry.customType) + } + + , del = function (selector, fn, $) { + return function (e) { + var target, i, array = typeof selector === 'string' ? $(selector, this) : selector + for (target = e.target; target && target !== this; target = target.parentNode) { + for (i = array.length; i--;) { + if (array[i] === target) { + return fn.apply(target, arguments) + } + } + } + } + } + + , remove = function (element, typeSpec, fn) { + var k, m, type, namespaces, i + , rm = removeListener + , isString = typeSpec && typeof typeSpec === 'string' + + if (isString && typeSpec.indexOf(' ') > 0) { + // remove(el, 't1 t2 t3', fn) or remove(el, 't1 t2 t3') + typeSpec = typeSpec.split(' ') + for (i = typeSpec.length; i--;) + remove(element, typeSpec[i], fn) + return element + } + type = isString && typeSpec.replace(nameRegex, '') + if (type && customEvents[type]) + type = customEvents[type].type + if (!typeSpec || isString) { + // remove(el) or remove(el, t1.ns) or remove(el, .ns) or remove(el, .ns1.ns2.ns3) + if (namespaces = isString && typeSpec.replace(namespaceRegex, '')) + namespaces = namespaces.split('.') + rm(element, type, fn, namespaces) + } else if (typeof typeSpec === 'function') { + // remove(el, fn) + rm(element, null, typeSpec) + } else { + // remove(el, { t1: fn1, t2, fn2 }) + for (k in typeSpec) { + if (typeSpec.hasOwnProperty(k)) + remove(element, k, typeSpec[k]) + } + } + return element + } + + , add = function (element, events, fn, delfn, $) { + var type, types, i, args + , originalFn = fn + , isDel = fn && typeof fn === 'string' + + if (events && !fn && typeof events === 'object') { + for (type in events) { + if (events.hasOwnProperty(type)) + add.apply(this, [ element, type, events[type] ]) + } + } else { + args = arguments.length > 3 ? slice.call(arguments, 3) : [] + types = (isDel ? fn : events).split(' ') + isDel && (fn = del(events, (originalFn = delfn), $)) && (args = slice.call(args, 1)) + // special case for one() + this === ONE && (fn = once(remove, element, events, fn, originalFn)) + for (i = types.length; i--;) addListener(element, types[i], fn, originalFn, args) + } + return element + } + + , one = function () { + return add.apply(ONE, arguments) + } + + , fireListener = W3C_MODEL ? function (isNative, type, element) { + var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents') + evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1) + element.dispatchEvent(evt) + } : function (isNative, type, element) { + element = targetElement(element, isNative) + // if not-native then we're using onpropertychange so we just increment a custom property + isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++ + } + + , fire = function (element, type, args) { + var i, j, l, names, handlers + , types = type.split(' ') + + for (i = types.length; i--;) { + type = types[i].replace(nameRegex, '') + if (names = types[i].replace(namespaceRegex, '')) + names = names.split('.') + if (!names && !args && element[eventSupport]) { + fireListener(nativeEvents[type], type, element) + } else { + // non-native event, either because of a namespace, arguments or a non DOM element + // iterate over all listeners and manually 'fire' + handlers = registry.get(element, type) + args = [false].concat(args) + for (j = 0, l = handlers.length; j < l; j++) { + if (handlers[j].inNamespaces(names)) + handlers[j].handler.apply(element, args) + } + } + } + return element + } + + , clone = function (element, from, type) { + var i = 0 + , handlers = registry.get(from, type) + , l = handlers.length + + for (;i < l; i++) + handlers[i].original && add(element, handlers[i].type, handlers[i].original) + return element + } + + , bean = { + add: add + , one: one + , remove: remove + , clone: clone + , fire: fire + , noConflict: function () { + context[name] = old + return this + } + } + + if (win[attachEvent]) { + // for IE, clean up on unload to avoid leaks + var cleanup = function () { + var i, entries = registry.entries() + for (i in entries) { + if (entries[i].type && entries[i].type !== 'unload') + remove(entries[i].element, entries[i].type) + } + win[detachEvent]('onunload', cleanup) + win.CollectGarbage && win.CollectGarbage() + } + win[attachEvent]('onunload', cleanup) + } + + return bean +}); diff --git a/gridplatform/bootstrap/static/bootstrap/bootstrap-datepicker/bootstrap-datepicker.js b/gridplatform/bootstrap/static/bootstrap/bootstrap-datepicker/bootstrap-datepicker.js new file mode 100644 index 0000000..78c346c --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/bootstrap-datepicker/bootstrap-datepicker.js @@ -0,0 +1,1395 @@ +/* ========================================================= + * bootstrap-datepicker.js + * http://www.eyecon.ro/bootstrap-datepicker + * ========================================================= + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * + * 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. + * ========================================================= */ + +(function( $ ) { + + var $window = $(window); + + function UTCDate(){ + return new Date(Date.UTC.apply(Date, arguments)); + } + function UTCToday(){ + var today = new Date(); + return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()); + } + + + // Picker object + + var Datepicker = function(element, options) { + var that = this; + + this._process_options(options); + + this.element = $(element); + this.isInline = false; + this.isInput = this.element.is('input'); + this.component = this.element.is('.date') ? this.element.find('.add-on, .btn') : false; + this.hasInput = this.component && this.element.find('input').length; + if(this.component && this.component.length === 0) + this.component = false; + + this.picker = $(DPGlobal.template); + this._buildEvents(); + this._attachEvents(); + + if(this.isInline) { + this.picker.addClass('datepicker-inline').appendTo(this.element); + } else { + this.picker.addClass('datepicker-dropdown dropdown-menu'); + } + + if (this.o.rtl){ + this.picker.addClass('datepicker-rtl'); + this.picker.find('.prev i, .next i') + .toggleClass('icon-arrow-left icon-arrow-right'); + } + + + this.viewMode = this.o.startView; + + if (this.o.calendarWeeks) + this.picker.find('tfoot th.today') + .attr('colspan', function(i, val){ + return parseInt(val) + 1; + }); + + this._allow_update = false; + + this.setStartDate(this._o.startDate); + this.setEndDate(this._o.endDate); + this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled); + + this.fillDow(); + this.fillMonths(); + + this._allow_update = true; + + this.update(); + this.showMode(); + + if(this.isInline) { + this.show(); + } + }; + + Datepicker.prototype = { + constructor: Datepicker, + + _process_options: function(opts){ + // Store raw options for reference + this._o = $.extend({}, this._o, opts); + // Processed options + var o = this.o = $.extend({}, this._o); + + // Check if "de-DE" style date is available, if not language should + // fallback to 2 letter code eg "de" + var lang = o.language; + if (!dates[lang]) { + lang = lang.split('-')[0]; + if (!dates[lang]) + lang = defaults.language; + } + o.language = lang; + + switch(o.startView){ + case 2: + case 'decade': + o.startView = 2; + break; + case 1: + case 'year': + o.startView = 1; + break; + default: + o.startView = 0; + } + + switch (o.minViewMode) { + case 1: + case 'months': + o.minViewMode = 1; + break; + case 2: + case 'years': + o.minViewMode = 2; + break; + default: + o.minViewMode = 0; + } + + o.startView = Math.max(o.startView, o.minViewMode); + + o.weekStart %= 7; + o.weekEnd = ((o.weekStart + 6) % 7); + + var format = DPGlobal.parseFormat(o.format); + if (o.startDate !== -Infinity) { + if (!!o.startDate) { + if (o.startDate instanceof Date) + o.startDate = this._local_to_utc(this._zero_time(o.startDate)); + else + o.startDate = DPGlobal.parseDate(o.startDate, format, o.language); + } else { + o.startDate = -Infinity; + } + } + if (o.endDate !== Infinity) { + if (!!o.endDate) { + if (o.endDate instanceof Date) + o.endDate = this._local_to_utc(this._zero_time(o.endDate)); + else + o.endDate = DPGlobal.parseDate(o.endDate, format, o.language); + } else { + o.endDate = Infinity; + } + } + + o.daysOfWeekDisabled = o.daysOfWeekDisabled||[]; + if (!$.isArray(o.daysOfWeekDisabled)) + o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/); + o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function (d) { + return parseInt(d, 10); + }); + + var plc = String(o.orientation).toLowerCase().split(/\s+/g), + _plc = o.orientation.toLowerCase(); + plc = $.grep(plc, function(word){ + return (/^auto|left|right|top|bottom$/).test(word); + }); + o.orientation = {x: 'auto', y: 'auto'}; + if (!_plc || _plc === 'auto') + ; // no action + else if (plc.length === 1){ + switch(plc[0]){ + case 'top': + case 'bottom': + o.orientation.y = plc[0]; + break; + case 'left': + case 'right': + o.orientation.x = plc[0]; + break; + } + } + else { + _plc = $.grep(plc, function(word){ + return (/^left|right$/).test(word); + }); + o.orientation.x = _plc[0] || 'auto'; + + _plc = $.grep(plc, function(word){ + return (/^top|bottom$/).test(word); + }); + o.orientation.y = _plc[0] || 'auto'; + } + }, + _events: [], + _secondaryEvents: [], + _applyEvents: function(evs){ + for (var i=0, el, ev; i windowWidth) + left = windowWidth - calendarWidth - visualPadding; + } + + // auto y orientation is best-situation: top or bottom, no fudging, + // decision based on which shows more of the calendar + var yorient = this.o.orientation.y, + top_overflow, bottom_overflow; + if (yorient === 'auto') { + top_overflow = -scrollTop + offset.top - calendarHeight; + bottom_overflow = scrollTop + windowHeight - (offset.top + height + calendarHeight); + if (Math.max(top_overflow, bottom_overflow) === bottom_overflow) + yorient = 'top'; + else + yorient = 'bottom'; + } + this.picker.addClass('datepicker-orient-' + yorient); + if (yorient === 'top') + top += height; + else + top -= calendarHeight + parseInt(this.picker.css('padding-top')); + + this.picker.css({ + top: top, + left: left, + zIndex: zIndex + }); + }, + + _allow_update: true, + update: function(){ + if (!this._allow_update) return; + + var oldDate = new Date(this.date), + date, fromArgs = false; + if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) { + date = arguments[0]; + if (date instanceof Date) + date = this._local_to_utc(date); + fromArgs = true; + } else { + date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val(); + delete this.element.data().date; + } + + this.date = DPGlobal.parseDate(date, this.o.format, this.o.language); + + if (fromArgs) { + // setting date by clicking + this.setValue(); + } else if (date) { + // setting date by typing + if (oldDate.getTime() !== this.date.getTime()) + this._trigger('changeDate'); + } else { + // clearing date + this._trigger('clearDate'); + } + + if (this.date < this.o.startDate) { + this.viewDate = new Date(this.o.startDate); + this.date = new Date(this.o.startDate); + } else if (this.date > this.o.endDate) { + this.viewDate = new Date(this.o.endDate); + this.date = new Date(this.o.endDate); + } else { + this.viewDate = new Date(this.date); + this.date = new Date(this.date); + } + this.fill(); + }, + + fillDow: function(){ + var dowCnt = this.o.weekStart, + html = ''; + if(this.o.calendarWeeks){ + var cell = ' '; + html += cell; + this.picker.find('.datepicker-days thead tr:first-child').prepend(cell); + } + while (dowCnt < this.o.weekStart + 7) { + html += ''+dates[this.o.language].daysMin[(dowCnt++)%7]+''; + } + html += ''; + this.picker.find('.datepicker-days thead').append(html); + }, + + fillMonths: function(){ + var html = '', + i = 0; + while (i < 12) { + html += ''+dates[this.o.language].monthsShort[i++]+''; + } + this.picker.find('.datepicker-months td').html(html); + }, + + setRange: function(range){ + if (!range || !range.length) + delete this.range; + else + this.range = $.map(range, function(d){ return d.valueOf(); }); + this.fill(); + }, + + getClassNames: function(date){ + var cls = [], + year = this.viewDate.getUTCFullYear(), + month = this.viewDate.getUTCMonth(), + currentDate = this.date.valueOf(), + today = new Date(); + if (date.getUTCFullYear() < year || (date.getUTCFullYear() == year && date.getUTCMonth() < month)) { + cls.push('old'); + } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() == year && date.getUTCMonth() > month)) { + cls.push('new'); + } + // Compare internal UTC date with local today, not UTC today + if (this.o.todayHighlight && + date.getUTCFullYear() == today.getFullYear() && + date.getUTCMonth() == today.getMonth() && + date.getUTCDate() == today.getDate()) { + cls.push('today'); + } + if (currentDate && date.valueOf() == currentDate) { + cls.push('active'); + } + if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate || + $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1) { + cls.push('disabled'); + } + if (this.range){ + if (date > this.range[0] && date < this.range[this.range.length-1]){ + cls.push('range'); + } + if ($.inArray(date.valueOf(), this.range) != -1){ + cls.push('selected'); + } + } + return cls; + }, + + fill: function() { + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(), + startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity, + startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity, + endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity, + endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity, + currentDate = this.date && this.date.valueOf(), + tooltip; + this.picker.find('.datepicker-days thead th.datepicker-switch') + .text(dates[this.o.language].months[month]+' '+year); + this.picker.find('tfoot th.today') + .text(dates[this.o.language].today) + .toggle(this.o.todayBtn !== false); + this.picker.find('tfoot th.clear') + .text(dates[this.o.language].clear) + .toggle(this.o.clearBtn !== false); + this.updateNavArrows(); + this.fillMonths(); + var prevMonth = UTCDate(year, month-1, 28,0,0,0,0), + day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); + prevMonth.setUTCDate(day); + prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7); + var nextMonth = new Date(prevMonth); + nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); + nextMonth = nextMonth.valueOf(); + var html = []; + var clsName; + while(prevMonth.valueOf() < nextMonth) { + if (prevMonth.getUTCDay() == this.o.weekStart) { + html.push(''); + if(this.o.calendarWeeks){ + // ISO 8601: First week contains first thursday. + // ISO also states week starts on Monday, but we can be more abstract here. + var + // Start of current week: based on weekstart/current date + ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5), + // Thursday of this week + th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5), + // First Thursday of year, year from thursday + yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5), + // Calendar week: ms between thursdays, div ms per day, div 7 days + calWeek = (th - yth) / 864e5 / 7 + 1; + html.push(''+ calWeek +''); + + } + } + clsName = this.getClassNames(prevMonth); + clsName.push('day'); + + if (this.o.beforeShowDay !== $.noop){ + var before = this.o.beforeShowDay(this._utc_to_local(prevMonth)); + if (before === undefined) + before = {}; + else if (typeof(before) === 'boolean') + before = {enabled: before}; + else if (typeof(before) === 'string') + before = {classes: before}; + if (before.enabled === false) + clsName.push('disabled'); + if (before.classes) + clsName = clsName.concat(before.classes.split(/\s+/)); + if (before.tooltip) + tooltip = before.tooltip; + } + + clsName = $.unique(clsName); + html.push(''+prevMonth.getUTCDate() + ''); + if (prevMonth.getUTCDay() == this.o.weekEnd) { + html.push(''); + } + prevMonth.setUTCDate(prevMonth.getUTCDate()+1); + } + this.picker.find('.datepicker-days tbody').empty().append(html.join('')); + var currentYear = this.date && this.date.getUTCFullYear(); + + var months = this.picker.find('.datepicker-months') + .find('th:eq(1)') + .text(year) + .end() + .find('span').removeClass('active'); + if (currentYear && currentYear == year) { + months.eq(this.date.getUTCMonth()).addClass('active'); + } + if (year < startYear || year > endYear) { + months.addClass('disabled'); + } + if (year == startYear) { + months.slice(0, startMonth).addClass('disabled'); + } + if (year == endYear) { + months.slice(endMonth+1).addClass('disabled'); + } + + html = ''; + year = parseInt(year/10, 10) * 10; + var yearCont = this.picker.find('.datepicker-years') + .find('th:eq(1)') + .text(year + '-' + (year + 9)) + .end() + .find('td'); + year -= 1; + for (var i = -1; i < 11; i++) { + html += ''+year+''; + year += 1; + } + yearCont.html(html); + }, + + updateNavArrows: function() { + if (!this._allow_update) return; + + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(); + switch (this.viewMode) { + case 0: + if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + case 1: + case 2: + if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + } + }, + + click: function(e) { + e.preventDefault(); + var target = $(e.target).closest('span, td, th'); + if (target.length == 1) { + switch(target[0].nodeName.toLowerCase()) { + case 'th': + switch(target[0].className) { + case 'datepicker-switch': + this.showMode(1); + break; + case 'prev': + case 'next': + var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1); + switch(this.viewMode){ + case 0: + this.viewDate = this.moveMonth(this.viewDate, dir); + this._trigger('changeMonth', this.viewDate); + break; + case 1: + case 2: + this.viewDate = this.moveYear(this.viewDate, dir); + if (this.viewMode === 1) + this._trigger('changeYear', this.viewDate); + break; + } + this.fill(); + break; + case 'today': + var date = new Date(); + date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); + + this.showMode(-2); + var which = this.o.todayBtn == 'linked' ? null : 'view'; + this._setDate(date, which); + break; + case 'clear': + var element; + if (this.isInput) + element = this.element; + else if (this.component) + element = this.element.find('input'); + if (element) + element.val("").change(); + this._trigger('changeDate'); + this.update(); + if (this.o.autoclose) + this.hide(); + break; + } + break; + case 'span': + if (!target.is('.disabled')) { + this.viewDate.setUTCDate(1); + if (target.is('.month')) { + var day = 1; + var month = target.parent().find('span').index(target); + var year = this.viewDate.getUTCFullYear(); + this.viewDate.setUTCMonth(month); + this._trigger('changeMonth', this.viewDate); + if (this.o.minViewMode === 1) { + this._setDate(UTCDate(year, month, day,0,0,0,0)); + } + } else { + var year = parseInt(target.text(), 10)||0; + var day = 1; + var month = 0; + this.viewDate.setUTCFullYear(year); + this._trigger('changeYear', this.viewDate); + if (this.o.minViewMode === 2) { + this._setDate(UTCDate(year, month, day,0,0,0,0)); + } + } + this.showMode(-1); + this.fill(); + } + break; + case 'td': + if (target.is('.day') && !target.is('.disabled')){ + var day = parseInt(target.text(), 10)||1; + var year = this.viewDate.getUTCFullYear(), + month = this.viewDate.getUTCMonth(); + if (target.is('.old')) { + if (month === 0) { + month = 11; + year -= 1; + } else { + month -= 1; + } + } else if (target.is('.new')) { + if (month == 11) { + month = 0; + year += 1; + } else { + month += 1; + } + } + this._setDate(UTCDate(year, month, day,0,0,0,0)); + } + break; + } + } + }, + + _setDate: function(date, which){ + if (!which || which == 'date') + this.date = new Date(date); + if (!which || which == 'view') + this.viewDate = new Date(date); + this.fill(); + this.setValue(); + this._trigger('changeDate'); + var element; + if (this.isInput) { + element = this.element; + } else if (this.component){ + element = this.element.find('input'); + } + if (element) { + element.change(); + } + if (this.o.autoclose && (!which || which == 'date')) { + this.hide(); + } + }, + + moveMonth: function(date, dir){ + if (!dir) return date; + var new_date = new Date(date.valueOf()), + day = new_date.getUTCDate(), + month = new_date.getUTCMonth(), + mag = Math.abs(dir), + new_month, test; + dir = dir > 0 ? 1 : -1; + if (mag == 1){ + test = dir == -1 + // If going back one month, make sure month is not current month + // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) + ? function(){ return new_date.getUTCMonth() == month; } + // If going forward one month, make sure month is as expected + // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) + : function(){ return new_date.getUTCMonth() != new_month; }; + new_month = month + dir; + new_date.setUTCMonth(new_month); + // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 + if (new_month < 0 || new_month > 11) + new_month = (new_month + 12) % 12; + } else { + // For magnitudes >1, move one month at a time... + for (var i=0; i= this.o.startDate && date <= this.o.endDate; + }, + + keydown: function(e){ + if (this.picker.is(':not(:visible)')){ + if (e.keyCode == 27) // allow escape to hide and re-show picker + this.show(); + return; + } + var dateChanged = false, + dir, day, month, + newDate, newViewDate; + switch(e.keyCode){ + case 27: // escape + this.hide(); + e.preventDefault(); + break; + case 37: // left + case 39: // right + if (!this.o.keyboardNavigation) break; + dir = e.keyCode == 37 ? -1 : 1; + if (e.ctrlKey){ + newDate = this.moveYear(this.date, dir); + newViewDate = this.moveYear(this.viewDate, dir); + this._trigger('changeYear', this.viewDate); + } else if (e.shiftKey){ + newDate = this.moveMonth(this.date, dir); + newViewDate = this.moveMonth(this.viewDate, dir); + this._trigger('changeMonth', this.viewDate); + } else { + newDate = new Date(this.date); + newDate.setUTCDate(this.date.getUTCDate() + dir); + newViewDate = new Date(this.viewDate); + newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir); + } + if (this.dateWithinRange(newDate)){ + this.date = newDate; + this.viewDate = newViewDate; + this.setValue(); + this.update(); + e.preventDefault(); + dateChanged = true; + } + break; + case 38: // up + case 40: // down + if (!this.o.keyboardNavigation) break; + dir = e.keyCode == 38 ? -1 : 1; + if (e.ctrlKey){ + newDate = this.moveYear(this.date, dir); + newViewDate = this.moveYear(this.viewDate, dir); + this._trigger('changeYear', this.viewDate); + } else if (e.shiftKey){ + newDate = this.moveMonth(this.date, dir); + newViewDate = this.moveMonth(this.viewDate, dir); + this._trigger('changeMonth', this.viewDate); + } else { + newDate = new Date(this.date); + newDate.setUTCDate(this.date.getUTCDate() + dir * 7); + newViewDate = new Date(this.viewDate); + newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7); + } + if (this.dateWithinRange(newDate)){ + this.date = newDate; + this.viewDate = newViewDate; + this.setValue(); + this.update(); + e.preventDefault(); + dateChanged = true; + } + break; + case 13: // enter + this.hide(); + e.preventDefault(); + break; + case 9: // tab + this.hide(); + break; + } + if (dateChanged){ + this._trigger('changeDate'); + var element; + if (this.isInput) { + element = this.element; + } else if (this.component){ + element = this.element.find('input'); + } + if (element) { + element.change(); + } + } + }, + + showMode: function(dir) { + if (dir) { + this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir)); + } + /* + vitalets: fixing bug of very special conditions: + jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover. + Method show() does not set display css correctly and datepicker is not shown. + Changed to .css('display', 'block') solve the problem. + See https://github.com/vitalets/x-editable/issues/37 + + In jquery 1.7.2+ everything works fine. + */ + //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); + this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block'); + this.updateNavArrows(); + } + }; + + var DateRangePicker = function(element, options){ + this.element = $(element); + this.inputs = $.map(options.inputs, function(i){ return i.jquery ? i[0] : i; }); + delete options.inputs; + + $(this.inputs) + .datepicker(options) + .bind('changeDate', $.proxy(this.dateUpdated, this)); + + this.pickers = $.map(this.inputs, function(i){ return $(i).data('datepicker'); }); + this.updateDates(); + }; + DateRangePicker.prototype = { + updateDates: function(){ + this.dates = $.map(this.pickers, function(i){ return i.date; }); + this.updateRanges(); + }, + updateRanges: function(){ + var range = $.map(this.dates, function(d){ return d.valueOf(); }); + $.each(this.pickers, function(i, p){ + p.setRange(range); + }); + }, + dateUpdated: function(e){ + var dp = $(e.target).data('datepicker'), + new_date = dp.getUTCDate(), + i = $.inArray(e.target, this.inputs), + l = this.inputs.length; + if (i == -1) return; + + if (new_date < this.dates[i]){ + // Date being moved earlier/left + while (i>=0 && new_date < this.dates[i]){ + this.pickers[i--].setUTCDate(new_date); + } + } + else if (new_date > this.dates[i]){ + // Date being moved later/right + while (i this.dates[i]){ + this.pickers[i++].setUTCDate(new_date); + } + } + this.updateDates(); + }, + remove: function(){ + $.map(this.pickers, function(p){ p.remove(); }); + delete this.element.data().datepicker; + } + }; + + function opts_from_el(el, prefix){ + // Derive options from element data-attrs + var data = $(el).data(), + out = {}, inkey, + replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])'), + prefix = new RegExp('^' + prefix.toLowerCase()); + for (var key in data) + if (prefix.test(key)){ + inkey = key.replace(replace, function(_,a){ return a.toLowerCase(); }); + out[inkey] = data[key]; + } + return out; + } + + function opts_from_locale(lang){ + // Derive options from locale plugins + var out = {}; + // Check if "de-DE" style date is available, if not language should + // fallback to 2 letter code eg "de" + if (!dates[lang]) { + lang = lang.split('-')[0] + if (!dates[lang]) + return; + } + var d = dates[lang]; + $.each(locale_opts, function(i,k){ + if (k in d) + out[k] = d[k]; + }); + return out; + } + + var old = $.fn.datepicker; + $.fn.datepicker = function ( option ) { + var args = Array.apply(null, arguments); + args.shift(); + var internal_return, + this_return; + this.each(function () { + var $this = $(this), + data = $this.data('datepicker'), + options = typeof option == 'object' && option; + if (!data) { + var elopts = opts_from_el(this, 'date'), + // Preliminary otions + xopts = $.extend({}, defaults, elopts, options), + locopts = opts_from_locale(xopts.language), + // Options priority: js args, data-attrs, locales, defaults + opts = $.extend({}, defaults, locopts, elopts, options); + if ($this.is('.input-daterange') || opts.inputs){ + var ropts = { + inputs: opts.inputs || $this.find('input').toArray() + }; + $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts)))); + } + else{ + $this.data('datepicker', (data = new Datepicker(this, opts))); + } + } + if (typeof option == 'string' && typeof data[option] == 'function') { + internal_return = data[option].apply(data, args); + if (internal_return !== undefined) + return false; + } + }); + if (internal_return !== undefined) + return internal_return; + else + return this; + }; + + var defaults = $.fn.datepicker.defaults = { + autoclose: false, + beforeShowDay: $.noop, + calendarWeeks: false, + clearBtn: false, + daysOfWeekDisabled: [], + endDate: Infinity, + forceParse: true, + format: 'mm/dd/yyyy', + keyboardNavigation: true, + language: 'en', + minViewMode: 0, + orientation: "auto", + rtl: false, + startDate: -Infinity, + startView: 0, + todayBtn: false, + todayHighlight: false, + weekStart: 0 + }; + var locale_opts = $.fn.datepicker.locale_opts = [ + 'format', + 'rtl', + 'weekStart' + ]; + $.fn.datepicker.Constructor = Datepicker; + var dates = $.fn.datepicker.dates = { + en: { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + clear: "Clear" + } + }; + + var DPGlobal = { + modes: [ + { + clsName: 'days', + navFnc: 'Month', + navStep: 1 + }, + { + clsName: 'months', + navFnc: 'FullYear', + navStep: 1 + }, + { + clsName: 'years', + navFnc: 'FullYear', + navStep: 10 + }], + isLeapYear: function (year) { + return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); + }, + getDaysInMonth: function (year, month) { + return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; + }, + validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, + nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g, + parseFormat: function(format){ + // IE treats \0 as a string end in inputs (truncating the value), + // so it's a bad format delimiter, anyway + var separators = format.replace(this.validParts, '\0').split('\0'), + parts = format.match(this.validParts); + if (!separators || !separators.length || !parts || parts.length === 0){ + throw new Error("Invalid date format."); + } + return {separators: separators, parts: parts}; + }, + parseDate: function(date, format, language) { + if (date instanceof Date) return date; + if (typeof format === 'string') + format = DPGlobal.parseFormat(format); + if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) { + var part_re = /([\-+]\d+)([dmwy])/, + parts = date.match(/([\-+]\d+)([dmwy])/g), + part, dir; + date = new Date(); + for (var i=0; i'+ + ''+ + '«'+ + ''+ + '»'+ + ''+ + '', + contTemplate: '', + footTemplate: '' + }; + DPGlobal.template = '
'+ + '
'+ + ''+ + DPGlobal.headTemplate+ + ''+ + DPGlobal.footTemplate+ + '
'+ + '
'+ + '
'+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + DPGlobal.footTemplate+ + '
'+ + '
'+ + '
'+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + DPGlobal.footTemplate+ + '
'+ + '
'+ + '
'; + + $.fn.datepicker.DPGlobal = DPGlobal; + + + /* DATEPICKER NO CONFLICT + * =================== */ + + $.fn.datepicker.noConflict = function(){ + $.fn.datepicker = old; + return this; + }; + + + /* DATEPICKER DATA-API + * ================== */ + + $(document).on( + 'focus.datepicker.data-api click.datepicker.data-api', + '[data-provide="datepicker"]', + function(e){ + var $this = $(this); + if ($this.data('datepicker')) return; + e.preventDefault(); + // component click requires us to explicitly show it + $this.datepicker('show'); + } + ); + $(function(){ + $('[data-provide="datepicker-inline"]').datepicker(); + }); + +}( window.jQuery )); diff --git a/gridplatform/bootstrap/static/bootstrap/bootstrap-datepicker/datepicker.css b/gridplatform/bootstrap/static/bootstrap/bootstrap-datepicker/datepicker.css new file mode 100644 index 0000000..03bd90d --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/bootstrap-datepicker/datepicker.css @@ -0,0 +1,481 @@ +/*! + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.datepicker { + padding: 4px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + direction: ltr; + /*.dow { + border-top: 1px solid #ddd !important; + }*/ + +} +.datepicker-inline { + width: 220px; +} +.datepicker.datepicker-rtl { + direction: rtl; +} +.datepicker.datepicker-rtl table tr td span { + float: right; +} +.datepicker-dropdown { + top: 0; + left: 0; +} +.datepicker-dropdown:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-top: 0; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; +} +.datepicker-dropdown:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-top: 0; + position: absolute; +} +.datepicker-dropdown.datepicker-orient-left:before { + left: 6px; +} +.datepicker-dropdown.datepicker-orient-left:after { + left: 7px; +} +.datepicker-dropdown.datepicker-orient-right:before { + right: 6px; +} +.datepicker-dropdown.datepicker-orient-right:after { + right: 7px; +} +.datepicker-dropdown.datepicker-orient-top:before { + top: -7px; +} +.datepicker-dropdown.datepicker-orient-top:after { + top: -6px; +} +.datepicker-dropdown.datepicker-orient-bottom:before { + bottom: -7px; + border-bottom: 0; + border-top: 7px solid #999; +} +.datepicker-dropdown.datepicker-orient-bottom:after { + bottom: -6px; + border-bottom: 0; + border-top: 6px solid #ffffff; +} +.datepicker > div { + display: none; +} +.datepicker.days div.datepicker-days { + display: block; +} +.datepicker.months div.datepicker-months { + display: block; +} +.datepicker.years div.datepicker-years { + display: block; +} +.datepicker table { + margin: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.datepicker td, +.datepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border: none; +} +.table-striped .datepicker table tr td, +.table-striped .datepicker table tr th { + background-color: transparent; +} +.datepicker table tr td.day:hover { + background: #eeeeee; + cursor: pointer; +} +.datepicker table tr td.old, +.datepicker table tr td.new { + color: #999999; +} +.datepicker table tr td.disabled, +.datepicker table tr td.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td.today, +.datepicker table tr td.today:hover, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today.disabled:hover { + background-color: #fde19a; + background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); + background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); + background-image: linear-gradient(top, #fdd49a, #fdf59a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); + border-color: #fdf59a #fdf59a #fbed50; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #000; +} +.datepicker table tr td.today:hover, +.datepicker table tr td.today:hover:hover, +.datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today.disabled:hover:hover, +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today:hover.disabled, +.datepicker table tr td.today.disabled.disabled, +.datepicker table tr td.today.disabled:hover.disabled, +.datepicker table tr td.today[disabled], +.datepicker table tr td.today:hover[disabled], +.datepicker table tr td.today.disabled[disabled], +.datepicker table tr td.today.disabled:hover[disabled] { + background-color: #fdf59a; +} +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active { + background-color: #fbf069 \9; +} +.datepicker table tr td.today:hover:hover { + color: #000; +} +.datepicker table tr td.today.active:hover { + color: #fff; +} +.datepicker table tr td.range, +.datepicker table tr td.range:hover, +.datepicker table tr td.range.disabled, +.datepicker table tr td.range.disabled:hover { + background: #eeeeee; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.datepicker table tr td.range.today, +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today.disabled:hover { + background-color: #f3d17a; + background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a); + background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a)); + background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a); + background-image: -o-linear-gradient(top, #f3c17a, #f3e97a); + background-image: linear-gradient(top, #f3c17a, #f3e97a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0); + border-color: #f3e97a #f3e97a #edde34; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today:hover:hover, +.datepicker table tr td.range.today.disabled:hover, +.datepicker table tr td.range.today.disabled:hover:hover, +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active, +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today:hover.disabled, +.datepicker table tr td.range.today.disabled.disabled, +.datepicker table tr td.range.today.disabled:hover.disabled, +.datepicker table tr td.range.today[disabled], +.datepicker table tr td.range.today:hover[disabled], +.datepicker table tr td.range.today.disabled[disabled], +.datepicker table tr td.range.today.disabled:hover[disabled] { + background-color: #f3e97a; +} +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active { + background-color: #efe24b \9; +} +.datepicker table tr td.selected, +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected.disabled:hover { + background-color: #9e9e9e; + background-image: -moz-linear-gradient(top, #b3b3b3, #808080); + background-image: -ms-linear-gradient(top, #b3b3b3, #808080); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080)); + background-image: -webkit-linear-gradient(top, #b3b3b3, #808080); + background-image: -o-linear-gradient(top, #b3b3b3, #808080); + background-image: linear-gradient(top, #b3b3b3, #808080); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0); + border-color: #808080 #808080 #595959; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected:hover:hover, +.datepicker table tr td.selected.disabled:hover, +.datepicker table tr td.selected.disabled:hover:hover, +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active, +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected:hover.disabled, +.datepicker table tr td.selected.disabled.disabled, +.datepicker table tr td.selected.disabled:hover.disabled, +.datepicker table tr td.selected[disabled], +.datepicker table tr td.selected:hover[disabled], +.datepicker table tr td.selected.disabled[disabled], +.datepicker table tr td.selected.disabled:hover[disabled] { + background-color: #808080; +} +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active { + background-color: #666666 \9; +} +.datepicker table tr td.active, +.datepicker table tr td.active:hover, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.active:hover, +.datepicker table tr td.active:hover:hover, +.datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active.disabled:hover:hover, +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active:hover.disabled, +.datepicker table tr td.active.disabled.disabled, +.datepicker table tr td.active.disabled:hover.disabled, +.datepicker table tr td.active[disabled], +.datepicker table tr td.active:hover[disabled], +.datepicker table tr td.active.disabled[disabled], +.datepicker table tr td.active.disabled:hover[disabled] { + background-color: #0044cc; +} +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active { + background-color: #003399 \9; +} +.datepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.datepicker table tr td span:hover { + background: #eeeeee; +} +.datepicker table tr td span.disabled, +.datepicker table tr td span.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td span.active, +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active:hover:hover, +.datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active.disabled:hover:hover, +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active:hover.disabled, +.datepicker table tr td span.active.disabled.disabled, +.datepicker table tr td span.active.disabled:hover.disabled, +.datepicker table tr td span.active[disabled], +.datepicker table tr td span.active:hover[disabled], +.datepicker table tr td span.active.disabled[disabled], +.datepicker table tr td span.active.disabled:hover[disabled] { + background-color: #0044cc; +} +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active { + background-color: #003399 \9; +} +.datepicker table tr td span.old, +.datepicker table tr td span.new { + color: #999999; +} +.datepicker th.datepicker-switch { + width: 145px; +} +.datepicker thead tr:first-child th, +.datepicker tfoot tr th { + cursor: pointer; +} +.datepicker thead tr:first-child th:hover, +.datepicker tfoot tr th:hover { + background: #eeeeee; +} +.datepicker .cw { + font-size: 10px; + width: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; +} +.datepicker thead tr:first-child th.cw { + cursor: default; + background-color: transparent; +} +.input-append.date .add-on i, +.input-prepend.date .add-on i { + display: block; + cursor: pointer; + width: 16px; + height: 16px; +} +.input-daterange input { + text-align: center; +} +.input-daterange input:first-child { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-daterange input:last-child { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-daterange .add-on { + display: inline-block; + width: auto; + min-width: 16px; + height: 18px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + vertical-align: middle; + background-color: #eeeeee; + border: 1px solid #ccc; + margin-left: -5px; + margin-right: -5px; +} diff --git a/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.css b/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.css new file mode 100644 index 0000000..2afd81d --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.css @@ -0,0 +1,50 @@ +/*! + * Bootstrap v2.3.1-j6 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat, extended by @ArnoldDaniels. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, +.clearfix:after { + display: table; + content: ""; + line-height: 0; +} +.clearfix:after { + clear: both; +} +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +tr.rowlink td { + cursor: pointer; +} +tr.rowlink td.nolink { + cursor: auto; +} +.table tbody tr.rowlink:hover td { + background-color: #cfcfcf; +} +a.rowlink { + color: inherit; + font: inherit; + text-decoration: inherit; +} diff --git a/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.js b/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.js new file mode 100644 index 0000000..9180be0 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.js @@ -0,0 +1,71 @@ +/* ============================================================ + * bootstrap-rowlink.js j1 + * http://jasny.github.com/bootstrap/javascript.html#rowlink + * ============================================================ + * Copyright 2012 Jasny BV, Netherlands. + * + * 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. + * ============================================================ */ + +!function ($) { + + "use strict"; // jshint ;_; + + var Rowlink = function (element, options) { + options = $.extend({}, $.fn.rowlink.defaults, options) + var tr = element.nodeName.toLowerCase() == 'tr' ? $(element) : $(element).find('tr:has(td)') + + tr.each(function() { + var link = $(this).find(options.target).first() + if (!link.length) return + + var href = link.attr('href') + + $(this).find('td').not('.nolink').click(function() { + window.location = href; + }) + + $(this).addClass('rowlink') + link.replaceWith(link.html()) + }) + } + + + /* ROWLINK PLUGIN DEFINITION + * =========================== */ + + $.fn.rowlink = function (options) { + return this.each(function () { + var $this = $(this) + , data = $this.data('rowlink') + if (!data) $this.data('rowlink', (data = new Rowlink(this, options))) + }) + } + + $.fn.rowlink.defaults = { + target: "a" + } + + $.fn.rowlink.Constructor = Rowlink + + + /* ROWLINK DATA-API + * ================== */ + + $(function () { + $('[data-provide="rowlink"],[data-provides="rowlink"]').each(function () { + $(this).rowlink($(this).data()) + }) + }) + +}(window.jQuery); diff --git a/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.min.css b/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.min.css new file mode 100644 index 0000000..5bbad34 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.min.css @@ -0,0 +1,16 @@ +/*! + * Bootstrap v2.3.1-j6 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat, extended by @ArnoldDaniels. + */ +.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;} +.clearfix:after{clear:both;} +.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;} +.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} +tr.rowlink td{cursor:pointer;}tr.rowlink td.nolink{cursor:auto;} +.table tbody tr.rowlink:hover td{background-color:#cfcfcf;} +a.rowlink{color:inherit;font:inherit;text-decoration:inherit;} diff --git a/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.min.js b/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.min.js new file mode 100644 index 0000000..5c036f6 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/bootstrap-rowlink/bootstrap-rowlink.min.js @@ -0,0 +1,7 @@ +/** +* Bootstrap.js by @mdo and @fat, extended by @ArnoldDaniels. +* plugins: bootstrap-rowlink.js +* Copyright 2012 Twitter, Inc. +* http://www.apache.org/licenses/LICENSE-2.0.txt +*/ +!function(e){var t=function(t,n){n=e.extend({},e.fn.rowlink.defaults,n);var r=t.nodeName.toLowerCase()=="tr"?e(t):e(t).find("tr:has(td)");r.each(function(){var t=e(this).find(n.target).first();if(!t.length)return;var r=t.attr("href");e(this).find("td").not(".nolink").click(function(){window.location=r}),e(this).addClass("rowlink"),t.replaceWith(t.html())})};e.fn.rowlink=function(n){return this.each(function(){var r=e(this),i=r.data("rowlink");i||r.data("rowlink",i=new t(this,n))})},e.fn.rowlink.defaults={target:"a"},e.fn.rowlink.Constructor=t,e(function(){e('[data-provide="rowlink"],[data-provides="rowlink"]').each(function(){e(this).rowlink(e(this).data())})})}(window.jQuery) \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/.gitignore b/gridplatform/bootstrap/static/bootstrap/chart.js/.gitignore new file mode 100755 index 0000000..3969d0a --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/.gitignore @@ -0,0 +1,7 @@ + +.DS_Store + +node_modules/* +custom/* + +docs/index.md diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/Chart.js b/gridplatform/bootstrap/static/bootstrap/chart.js/Chart.js new file mode 100755 index 0000000..8e550f2 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/Chart.js @@ -0,0 +1,12749 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o lum2) { + return (lum1 + 0.05) / (lum2 + 0.05) + }; + return (lum2 + 0.05) / (lum1 + 0.05); + }, + + level: function(color2) { + var contrastRatio = this.contrast(color2); + return (contrastRatio >= 7.1) ? 'AAA' : (contrastRatio >= 4.5) ? 'AA' : ''; + }, + + dark: function() { + // YIQ equation from http://24ways.org/2010/calculating-color-contrast + var rgb = this.values.rgb, + yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000; + return yiq < 128; + }, + + light: function() { + return !this.dark(); + }, + + negate: function() { + var rgb = [] + for (var i = 0; i < 3; i++) { + rgb[i] = 255 - this.values.rgb[i]; + } + this.setValues("rgb", rgb); + return this; + }, + + lighten: function(ratio) { + this.values.hsl[2] += this.values.hsl[2] * ratio; + this.setValues("hsl", this.values.hsl); + return this; + }, + + darken: function(ratio) { + this.values.hsl[2] -= this.values.hsl[2] * ratio; + this.setValues("hsl", this.values.hsl); + return this; + }, + + saturate: function(ratio) { + this.values.hsl[1] += this.values.hsl[1] * ratio; + this.setValues("hsl", this.values.hsl); + return this; + }, + + desaturate: function(ratio) { + this.values.hsl[1] -= this.values.hsl[1] * ratio; + this.setValues("hsl", this.values.hsl); + return this; + }, + + whiten: function(ratio) { + this.values.hwb[1] += this.values.hwb[1] * ratio; + this.setValues("hwb", this.values.hwb); + return this; + }, + + blacken: function(ratio) { + this.values.hwb[2] += this.values.hwb[2] * ratio; + this.setValues("hwb", this.values.hwb); + return this; + }, + + greyscale: function() { + var rgb = this.values.rgb; + // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale + var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11; + this.setValues("rgb", [val, val, val]); + return this; + }, + + clearer: function(ratio) { + this.setValues("alpha", this.values.alpha - (this.values.alpha * ratio)); + return this; + }, + + opaquer: function(ratio) { + this.setValues("alpha", this.values.alpha + (this.values.alpha * ratio)); + return this; + }, + + rotate: function(degrees) { + var hue = this.values.hsl[0]; + hue = (hue + degrees) % 360; + hue = hue < 0 ? 360 + hue : hue; + this.values.hsl[0] = hue; + this.setValues("hsl", this.values.hsl); + return this; + }, + + mix: function(color2, weight) { + weight = 1 - (weight == null ? 0.5 : weight); + + // algorithm from Sass's mix(). Ratio of first color in mix is + // determined by the alphas of both colors and the weight + var t1 = weight * 2 - 1, + d = this.alpha() - color2.alpha(); + + var weight1 = (((t1 * d == -1) ? t1 : (t1 + d) / (1 + t1 * d)) + 1) / 2; + var weight2 = 1 - weight1; + + var rgb = this.rgbArray(); + var rgb2 = color2.rgbArray(); + + for (var i = 0; i < rgb.length; i++) { + rgb[i] = rgb[i] * weight1 + rgb2[i] * weight2; + } + this.setValues("rgb", rgb); + + var alpha = this.alpha() * weight + color2.alpha() * (1 - weight); + this.setValues("alpha", alpha); + + return this; + }, + + toJSON: function() { + return this.rgb(); + }, + + clone: function() { + return new Color(this.rgb()); + } +} + + +Color.prototype.getValues = function(space) { + var vals = {}; + for (var i = 0; i < space.length; i++) { + vals[space.charAt(i)] = this.values[space][i]; + } + if (this.values.alpha != 1) { + vals["a"] = this.values.alpha; + } + // {r: 255, g: 255, b: 255, a: 0.4} + return vals; +} + +Color.prototype.setValues = function(space, vals) { + var spaces = { + "rgb": ["red", "green", "blue"], + "hsl": ["hue", "saturation", "lightness"], + "hsv": ["hue", "saturation", "value"], + "hwb": ["hue", "whiteness", "blackness"], + "cmyk": ["cyan", "magenta", "yellow", "black"] + }; + + var maxes = { + "rgb": [255, 255, 255], + "hsl": [360, 100, 100], + "hsv": [360, 100, 100], + "hwb": [360, 100, 100], + "cmyk": [100, 100, 100, 100] + }; + + var alpha = 1; + if (space == "alpha") { + alpha = vals; + } else if (vals.length) { + // [10, 10, 10] + this.values[space] = vals.slice(0, space.length); + alpha = vals[space.length]; + } else if (vals[space.charAt(0)] !== undefined) { + // {r: 10, g: 10, b: 10} + for (var i = 0; i < space.length; i++) { + this.values[space][i] = vals[space.charAt(i)]; + } + alpha = vals.a; + } else if (vals[spaces[space][0]] !== undefined) { + // {red: 10, green: 10, blue: 10} + var chans = spaces[space]; + for (var i = 0; i < space.length; i++) { + this.values[space][i] = vals[chans[i]]; + } + alpha = vals.alpha; + } + this.values.alpha = Math.max(0, Math.min(1, (alpha !== undefined ? alpha : this.values.alpha))); + if (space == "alpha") { + return; + } + + // cap values of the space prior converting all values + for (var i = 0; i < space.length; i++) { + var capped = Math.max(0, Math.min(maxes[space][i], this.values[space][i])); + this.values[space][i] = Math.round(capped); + } + + // convert to all the other color spaces + for (var sname in spaces) { + if (sname != space) { + this.values[sname] = convert[space][sname](this.values[space]) + } + + // cap values + for (var i = 0; i < sname.length; i++) { + var capped = Math.max(0, Math.min(maxes[sname][i], this.values[sname][i])); + this.values[sname][i] = Math.round(capped); + } + } + return true; +} + +Color.prototype.setSpace = function(space, args) { + var vals = args[0]; + if (vals === undefined) { + // color.rgb() + return this.getValues(space); + } + // color.rgb(10, 10, 10) + if (typeof vals == "number") { + vals = Array.prototype.slice.call(args); + } + this.setValues(space, vals); + return this; +} + +Color.prototype.setChannel = function(space, index, val) { + if (val === undefined) { + // color.red() + return this.values[space][index]; + } + // color.red(100) + this.values[space][index] = val; + this.setValues(space, this.values[space]); + return this; +} + +window.Color = module.exports = Color + +},{"color-convert":3,"color-string":5}],2:[function(require,module,exports){ +/* MIT license */ + +module.exports = { + rgb2hsl: rgb2hsl, + rgb2hsv: rgb2hsv, + rgb2hwb: rgb2hwb, + rgb2cmyk: rgb2cmyk, + rgb2keyword: rgb2keyword, + rgb2xyz: rgb2xyz, + rgb2lab: rgb2lab, + rgb2lch: rgb2lch, + + hsl2rgb: hsl2rgb, + hsl2hsv: hsl2hsv, + hsl2hwb: hsl2hwb, + hsl2cmyk: hsl2cmyk, + hsl2keyword: hsl2keyword, + + hsv2rgb: hsv2rgb, + hsv2hsl: hsv2hsl, + hsv2hwb: hsv2hwb, + hsv2cmyk: hsv2cmyk, + hsv2keyword: hsv2keyword, + + hwb2rgb: hwb2rgb, + hwb2hsl: hwb2hsl, + hwb2hsv: hwb2hsv, + hwb2cmyk: hwb2cmyk, + hwb2keyword: hwb2keyword, + + cmyk2rgb: cmyk2rgb, + cmyk2hsl: cmyk2hsl, + cmyk2hsv: cmyk2hsv, + cmyk2hwb: cmyk2hwb, + cmyk2keyword: cmyk2keyword, + + keyword2rgb: keyword2rgb, + keyword2hsl: keyword2hsl, + keyword2hsv: keyword2hsv, + keyword2hwb: keyword2hwb, + keyword2cmyk: keyword2cmyk, + keyword2lab: keyword2lab, + keyword2xyz: keyword2xyz, + + xyz2rgb: xyz2rgb, + xyz2lab: xyz2lab, + xyz2lch: xyz2lch, + + lab2xyz: lab2xyz, + lab2rgb: lab2rgb, + lab2lch: lab2lch, + + lch2lab: lch2lab, + lch2xyz: lch2xyz, + lch2rgb: lch2rgb +} + + +function rgb2hsl(rgb) { + var r = rgb[0]/255, + g = rgb[1]/255, + b = rgb[2]/255, + min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s, 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]; +} + +function rgb2hsv(rgb) { + var r = rgb[0], + g = rgb[1], + b = rgb[2], + min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s, v; + + if (max == 0) + s = 0; + else + s = (delta/max * 1000)/10; + + 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; + + v = ((max / 255) * 1000) / 10; + + return [h, s, v]; +} + +function rgb2hwb(rgb) { + var r = rgb[0], + g = rgb[1], + b = rgb[2], + h = rgb2hsl(rgb)[0], + 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]; +} + +function rgb2cmyk(rgb) { + var r = rgb[0] / 255, + g = rgb[1] / 255, + b = rgb[2] / 255, + c, m, y, 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 rgb2keyword(rgb) { + return reverseKeywords[JSON.stringify(rgb)]; +} + +function rgb2xyz(rgb) { + var r = rgb[0] / 255, + g = rgb[1] / 255, + 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]; +} + +function rgb2lab(rgb) { + var xyz = rgb2xyz(rgb), + x = xyz[0], + y = xyz[1], + z = xyz[2], + l, a, 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]; +} + +function rgb2lch(args) { + return lab2lch(rgb2lab(args)); +} + +function hsl2rgb(hsl) { + var h = hsl[0] / 360, + s = hsl[1] / 100, + l = hsl[2] / 100, + t1, t2, t3, rgb, 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); + t3 < 0 && t3++; + 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; +} + +function hsl2hsv(hsl) { + var h = hsl[0], + s = hsl[1] / 100, + l = hsl[2] / 100, + sv, v; + + if(l === 0) { + // no need to do calc on black + // also avoids divide by 0 error + return [0, 0, 0]; + } + + l *= 2; + s *= (l <= 1) ? l : 2 - l; + v = (l + s) / 2; + sv = (2 * s) / (l + s); + return [h, sv * 100, v * 100]; +} + +function hsl2hwb(args) { + return rgb2hwb(hsl2rgb(args)); +} + +function hsl2cmyk(args) { + return rgb2cmyk(hsl2rgb(args)); +} + +function hsl2keyword(args) { + return rgb2keyword(hsl2rgb(args)); +} + + +function hsv2rgb(hsv) { + var h = hsv[0] / 60, + s = hsv[1] / 100, + v = hsv[2] / 100, + hi = Math.floor(h) % 6; + + var f = h - Math.floor(h), + p = 255 * v * (1 - s), + q = 255 * v * (1 - (s * f)), + t = 255 * v * (1 - (s * (1 - f))), + v = 255 * v; + + 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]; + } +} + +function hsv2hsl(hsv) { + var h = hsv[0], + s = hsv[1] / 100, + v = hsv[2] / 100, + sl, l; + + l = (2 - s) * v; + sl = s * v; + sl /= (l <= 1) ? l : 2 - l; + sl = sl || 0; + l /= 2; + return [h, sl * 100, l * 100]; +} + +function hsv2hwb(args) { + return rgb2hwb(hsv2rgb(args)) +} + +function hsv2cmyk(args) { + return rgb2cmyk(hsv2rgb(args)); +} + +function hsv2keyword(args) { + return rgb2keyword(hsv2rgb(args)); +} + +// http://dev.w3.org/csswg/css-color/#hwb-to-rgb +function hwb2rgb(hwb) { + var h = hwb[0] / 360, + wh = hwb[1] / 100, + bl = hwb[2] / 100, + ratio = wh + bl, + i, v, f, 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 + + 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]; +} + +function hwb2hsl(args) { + return rgb2hsl(hwb2rgb(args)); +} + +function hwb2hsv(args) { + return rgb2hsv(hwb2rgb(args)); +} + +function hwb2cmyk(args) { + return rgb2cmyk(hwb2rgb(args)); +} + +function hwb2keyword(args) { + return rgb2keyword(hwb2rgb(args)); +} + +function cmyk2rgb(cmyk) { + var c = cmyk[0] / 100, + m = cmyk[1] / 100, + y = cmyk[2] / 100, + k = cmyk[3] / 100, + r, g, 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]; +} + +function cmyk2hsl(args) { + return rgb2hsl(cmyk2rgb(args)); +} + +function cmyk2hsv(args) { + return rgb2hsv(cmyk2rgb(args)); +} + +function cmyk2hwb(args) { + return rgb2hwb(cmyk2rgb(args)); +} + +function cmyk2keyword(args) { + return rgb2keyword(cmyk2rgb(args)); +} + + +function xyz2rgb(xyz) { + var x = xyz[0] / 100, + y = xyz[1] / 100, + z = xyz[2] / 100, + r, g, 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 = (r * 12.92); + + g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055) + : g = (g * 12.92); + + b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055) + : b = (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]; +} + +function xyz2lab(xyz) { + var x = xyz[0], + y = xyz[1], + z = xyz[2], + l, a, 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]; +} + +function xyz2lch(args) { + return lab2lch(xyz2lab(args)); +} + +function lab2xyz(lab) { + var l = lab[0], + a = lab[1], + b = lab[2], + x, y, z, y2; + + if (l <= 8) { + y = (l * 100) / 903.3; + y2 = (7.787 * (y / 100)) + (16 / 116); + } else { + y = 100 * Math.pow((l + 16) / 116, 3); + y2 = Math.pow(y / 100, 1/3); + } + + x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3); + + z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3); + + return [x, y, z]; +} + +function lab2lch(lab) { + var l = lab[0], + a = lab[1], + b = lab[2], + hr, h, 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]; +} + +function lab2rgb(args) { + return xyz2rgb(lab2xyz(args)); +} + +function lch2lab(lch) { + var l = lch[0], + c = lch[1], + h = lch[2], + a, b, hr; + + hr = h / 360 * 2 * Math.PI; + a = c * Math.cos(hr); + b = c * Math.sin(hr); + return [l, a, b]; +} + +function lch2xyz(args) { + return lab2xyz(lch2lab(args)); +} + +function lch2rgb(args) { + return lab2rgb(lch2lab(args)); +} + +function keyword2rgb(keyword) { + return cssKeywords[keyword]; +} + +function keyword2hsl(args) { + return rgb2hsl(keyword2rgb(args)); +} + +function keyword2hsv(args) { + return rgb2hsv(keyword2rgb(args)); +} + +function keyword2hwb(args) { + return rgb2hwb(keyword2rgb(args)); +} + +function keyword2cmyk(args) { + return rgb2cmyk(keyword2rgb(args)); +} + +function keyword2lab(args) { + return rgb2lab(keyword2rgb(args)); +} + +function keyword2xyz(args) { + return rgb2xyz(keyword2rgb(args)); +} + +var cssKeywords = { + 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] +}; + +var reverseKeywords = {}; +for (var key in cssKeywords) { + reverseKeywords[JSON.stringify(cssKeywords[key])] = key; +} + +},{}],3:[function(require,module,exports){ +var conversions = require("./conversions"); + +var convert = function() { + return new Converter(); +} + +for (var func in conversions) { + // export Raw versions + convert[func + "Raw"] = (function(func) { + // accept array or plain args + return function(arg) { + if (typeof arg == "number") + arg = Array.prototype.slice.call(arguments); + return conversions[func](arg); + } + })(func); + + var pair = /(\w+)2(\w+)/.exec(func), + from = pair[1], + to = pair[2]; + + // export rgb2hsl and ["rgb"]["hsl"] + convert[from] = convert[from] || {}; + + convert[from][to] = convert[func] = (function(func) { + return function(arg) { + if (typeof arg == "number") + arg = Array.prototype.slice.call(arguments); + + var val = conversions[func](arg); + if (typeof val == "string" || val === undefined) + return val; // keyword + + for (var i = 0; i < val.length; i++) + val[i] = Math.round(val[i]); + return val; + } + })(func); +} + + +/* Converter does lazy conversion and caching */ +var Converter = function() { + this.convs = {}; +}; + +/* Either get the values for a space or + set the values for a space, depending on args */ +Converter.prototype.routeSpace = function(space, args) { + var values = args[0]; + if (values === undefined) { + // color.rgb() + return this.getValues(space); + } + // color.rgb(10, 10, 10) + if (typeof values == "number") { + values = Array.prototype.slice.call(args); + } + + return this.setValues(space, values); +}; + +/* Set the values for a space, invalidating cache */ +Converter.prototype.setValues = function(space, values) { + this.space = space; + this.convs = {}; + this.convs[space] = values; + return this; +}; + +/* Get the values for a space. If there's already + a conversion for the space, fetch it, otherwise + compute it */ +Converter.prototype.getValues = function(space) { + var vals = this.convs[space]; + if (!vals) { + var fspace = this.space, + from = this.convs[fspace]; + vals = convert[fspace][space](from); + + this.convs[space] = vals; + } + return vals; +}; + +["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) { + Converter.prototype[space] = function(vals) { + return this.routeSpace(space, arguments); + } +}); + +module.exports = convert; +},{"./conversions":2}],4:[function(require,module,exports){ +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] +}; +},{}],5:[function(require,module,exports){ +/* MIT license */ +var colorNames = require('color-name'); + +module.exports = { + getRgba: getRgba, + getHsla: getHsla, + getRgb: getRgb, + getHsl: getHsl, + getHwb: getHwb, + getAlpha: getAlpha, + + hexString: hexString, + rgbString: rgbString, + rgbaString: rgbaString, + percentString: percentString, + percentaString: percentaString, + hslString: hslString, + hslaString: hslaString, + hwbString: hwbString, + keyword: keyword +} + +function getRgba(string) { + if (!string) { + return; + } + var abbr = /^#([a-fA-F0-9]{3})$/, + hex = /^#([a-fA-F0-9]{6})$/, + rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/, + per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/, + keyword = /(\w+)/; + + var rgb = [0, 0, 0], + a = 1, + match = string.match(abbr); + if (match) { + match = match[1]; + for (var i = 0; i < rgb.length; i++) { + rgb[i] = parseInt(match[i] + match[i], 16); + } + } + else if (match = string.match(hex)) { + match = match[1]; + for (var i = 0; i < rgb.length; i++) { + rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16); + } + } + else if (match = string.match(rgba)) { + for (var i = 0; i < rgb.length; i++) { + rgb[i] = parseInt(match[i + 1]); + } + a = parseFloat(match[4]); + } + else if (match = string.match(per)) { + for (var i = 0; i < rgb.length; i++) { + rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55); + } + a = 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; + } + } + + for (var i = 0; i < rgb.length; i++) { + rgb[i] = scale(rgb[i], 0, 255); + } + if (!a && a != 0) { + a = 1; + } + else { + a = scale(a, 0, 1); + } + rgb[3] = a; + return rgb; +} + +function getHsla(string) { + if (!string) { + return; + } + var hsl = /^hsla?\(\s*([+-]?\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 = scale(parseInt(match[1]), 0, 360), + s = scale(parseFloat(match[2]), 0, 100), + l = scale(parseFloat(match[3]), 0, 100), + a = scale(isNaN(alpha) ? 1 : alpha, 0, 1); + return [h, s, l, a]; + } +} + +function getHwb(string) { + if (!string) { + return; + } + var hwb = /^hwb\(\s*([+-]?\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 = scale(parseInt(match[1]), 0, 360), + w = scale(parseFloat(match[2]), 0, 100), + b = scale(parseFloat(match[3]), 0, 100), + a = scale(isNaN(alpha) ? 1 : alpha, 0, 1); + return [h, w, b, a]; + } +} + +function getRgb(string) { + var rgba = getRgba(string); + return rgba && rgba.slice(0, 3); +} + +function getHsl(string) { + var hsla = getHsla(string); + return hsla && hsla.slice(0, 3); +} + +function getAlpha(string) { + var vals = getRgba(string); + if (vals) { + return vals[3]; + } + else if (vals = getHsla(string)) { + return vals[3]; + } + else if (vals = getHwb(string)) { + return vals[3]; + } +} + +// generators +function hexString(rgb) { + return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1]) + + hexDouble(rgb[2]); +} + +function rgbString(rgba, alpha) { + if (alpha < 1 || (rgba[3] && rgba[3] < 1)) { + return rgbaString(rgba, alpha); + } + return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")"; +} + +function rgbaString(rgba, alpha) { + if (alpha === undefined) { + alpha = (rgba[3] !== undefined ? rgba[3] : 1); + } + return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + + ", " + alpha + ")"; +} + +function percentString(rgba, alpha) { + if (alpha < 1 || (rgba[3] && rgba[3] < 1)) { + return percentaString(rgba, alpha); + } + var r = Math.round(rgba[0]/255 * 100), + g = Math.round(rgba[1]/255 * 100), + b = Math.round(rgba[2]/255 * 100); + + return "rgb(" + r + "%, " + g + "%, " + b + "%)"; +} + +function percentaString(rgba, alpha) { + var r = Math.round(rgba[0]/255 * 100), + g = Math.round(rgba[1]/255 * 100), + b = Math.round(rgba[2]/255 * 100); + return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")"; +} + +function hslString(hsla, alpha) { + if (alpha < 1 || (hsla[3] && hsla[3] < 1)) { + return hslaString(hsla, alpha); + } + return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)"; +} + +function hslaString(hsla, alpha) { + if (alpha === undefined) { + alpha = (hsla[3] !== undefined ? hsla[3] : 1); + } + return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " + + alpha + ")"; +} + +// 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) +function hwbString(hwb, alpha) { + if (alpha === undefined) { + alpha = (hwb[3] !== undefined ? hwb[3] : 1); + } + return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%" + + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")"; +} + +function keyword(rgb) { + return reverseNames[rgb.slice(0, 3)]; +} + +// helpers +function scale(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; +} + + +//create a list of reverse color names +var reverseNames = {}; +for (var name in colorNames) { + reverseNames[colorNames[name]] = name; +} + +},{"color-name":4}],6:[function(require,module,exports){ +//! moment.js +//! version : 2.11.2 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + global.moment = factory() +}(this, function () { 'use strict'; + + var hookCallback; + + function utils_hooks__hooks () { + return hookCallback.apply(null, arguments); + } + + // This is done to register the method called with moment() + // without creating circular dependencies. + function setHookCallback (callback) { + hookCallback = callback; + } + + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + function isDate(input) { + return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]'; + } + + function map(arr, fn) { + var res = [], i; + for (i = 0; i < arr.length; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } + + function hasOwnProp(a, b) { + return Object.prototype.hasOwnProperty.call(a, b); + } + + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } + + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } + + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } + + return a; + } + + function create_utc__createUTC (input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, true).utc(); + } + + function defaultParsingFlags() { + // We need to deep clone this object. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso : false + }; + } + + function getParsingFlags(m) { + if (m._pf == null) { + m._pf = defaultParsingFlags(); + } + return m._pf; + } + + function valid__isValid(m) { + if (m._isValid == null) { + var flags = getParsingFlags(m); + m._isValid = !isNaN(m._d.getTime()) && + flags.overflow < 0 && + !flags.empty && + !flags.invalidMonth && + !flags.invalidWeekday && + !flags.nullInput && + !flags.invalidFormat && + !flags.userInvalidated; + + if (m._strict) { + m._isValid = m._isValid && + flags.charsLeftOver === 0 && + flags.unusedTokens.length === 0 && + flags.bigHour === undefined; + } + } + return m._isValid; + } + + function valid__createInvalid (flags) { + var m = create_utc__createUTC(NaN); + if (flags != null) { + extend(getParsingFlags(m), flags); + } + else { + getParsingFlags(m).userInvalidated = true; + } + + return m; + } + + function isUndefined(input) { + return input === void 0; + } + + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + var momentProperties = utils_hooks__hooks.momentProperties = []; + + function copyConfig(to, from) { + var i, prop, val; + + if (!isUndefined(from._isAMomentObject)) { + to._isAMomentObject = from._isAMomentObject; + } + if (!isUndefined(from._i)) { + to._i = from._i; + } + if (!isUndefined(from._f)) { + to._f = from._f; + } + if (!isUndefined(from._l)) { + to._l = from._l; + } + if (!isUndefined(from._strict)) { + to._strict = from._strict; + } + if (!isUndefined(from._tzm)) { + to._tzm = from._tzm; + } + if (!isUndefined(from._isUTC)) { + to._isUTC = from._isUTC; + } + if (!isUndefined(from._offset)) { + to._offset = from._offset; + } + if (!isUndefined(from._pf)) { + to._pf = getParsingFlags(from); + } + if (!isUndefined(from._locale)) { + to._locale = from._locale; + } + + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (!isUndefined(val)) { + to[prop] = val; + } + } + } + + return to; + } + + var updateInProgress = false; + + // Moment prototype object + function Moment(config) { + copyConfig(this, config); + this._d = new Date(config._d != null ? config._d.getTime() : NaN); + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + utils_hooks__hooks.updateOffset(this); + updateInProgress = false; + } + } + + function isMoment (obj) { + return obj instanceof Moment || (obj != null && obj._isAMomentObject != null); + } + + function absFloor (number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + value = absFloor(coercedNumber); + } + + return value; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } + + function Locale() { + } + + // internal storage for locale config files + var locales = {}; + var globalLocale; + + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // pick the locale from the array + // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + function chooseLocale(names) { + var i = 0, j, next, locale, split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return null; + } + + function loadLocale(name) { + var oldLocale = null; + // TODO: Find a better way to register and load all the locales in Node + if (!locales[name] && (typeof module !== 'undefined') && + module && module.exports) { + try { + oldLocale = globalLocale._abbr; + require('./locale/' + name); + // because defineLocale currently also sets the global locale, we + // want to undo that for lazy loaded locales + locale_locales__getSetGlobalLocale(oldLocale); + } catch (e) { } + } + return locales[name]; + } + + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // locale key. + function locale_locales__getSetGlobalLocale (key, values) { + var data; + if (key) { + if (isUndefined(values)) { + data = locale_locales__getLocale(key); + } + else { + data = defineLocale(key, values); + } + + if (data) { + // moment.duration._locale = moment._locale = data; + globalLocale = data; + } + } + + return globalLocale._abbr; + } + + function defineLocale (name, values) { + if (values !== null) { + values.abbr = name; + locales[name] = locales[name] || new Locale(); + locales[name].set(values); + + // backwards compat for now: also set the locale + locale_locales__getSetGlobalLocale(name); + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + } + + // returns locale data + function locale_locales__getLocale (key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return globalLocale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); + } + + var aliases = {}; + + function addUnitAlias (unit, shorthand) { + var lowerCase = unit.toLowerCase(); + aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; + } + + function normalizeUnits(units) { + return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + function isFunction(input) { + return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]'; + } + + function makeGetSet (unit, keepTime) { + return function (value) { + if (value != null) { + get_set__set(this, unit, value); + utils_hooks__hooks.updateOffset(this, keepTime); + return this; + } else { + return get_set__get(this, unit); + } + }; + } + + function get_set__get (mom, unit) { + return mom.isValid() ? + mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN; + } + + function get_set__set (mom, unit, value) { + if (mom.isValid()) { + mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } + + // MOMENTS + + function getSet (units, value) { + var unit; + if (typeof units === 'object') { + for (unit in units) { + this.set(unit, units[unit]); + } + } else { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](value); + } + } + return this; + } + + function zeroFill(number, targetLength, forceSign) { + var absNumber = '' + Math.abs(number), + zerosToFill = targetLength - absNumber.length, + sign = number >= 0; + return (sign ? (forceSign ? '+' : '') : '-') + + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber; + } + + var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g; + + var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g; + + var formatFunctions = {}; + + var formatTokenFunctions = {}; + + // token: 'M' + // padded: ['MM', 2] + // ordinal: 'Mo' + // callback: function () { this.month() + 1 } + function addFormatToken (token, padded, ordinal, callback) { + var func = callback; + if (typeof callback === 'string') { + func = function () { + return this[callback](); + }; + } + if (token) { + formatTokenFunctions[token] = func; + } + if (padded) { + formatTokenFunctions[padded[0]] = function () { + return zeroFill(func.apply(this, arguments), padded[1], padded[2]); + }; + } + if (ordinal) { + formatTokenFunctions[ordinal] = function () { + return this.localeData().ordinal(func.apply(this, arguments), token); + }; + } + } + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ''; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + + format = expandFormat(format, m.localeData()); + formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format); + + return formatFunctions[format](m); + } + + function expandFormat(format, locale) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + var match1 = /\d/; // 0 - 9 + var match2 = /\d\d/; // 00 - 99 + var match3 = /\d{3}/; // 000 - 999 + var match4 = /\d{4}/; // 0000 - 9999 + var match6 = /[+-]?\d{6}/; // -999999 - 999999 + var match1to2 = /\d\d?/; // 0 - 99 + var match3to4 = /\d\d\d\d?/; // 999 - 9999 + var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999 + var match1to3 = /\d{1,3}/; // 0 - 999 + var match1to4 = /\d{1,4}/; // 0 - 9999 + var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999 + + var matchUnsigned = /\d+/; // 0 - inf + var matchSigned = /[+-]?\d+/; // -inf - inf + + var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z + var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z + + var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123 + + // any word (or two) characters or numbers including two/three word month in arabic. + // includes scottish gaelic two word and hyphenated months + var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i; + + + var regexes = {}; + + function addRegexToken (token, regex, strictRegex) { + regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) { + return (isStrict && strictRegex) ? strictRegex : regex; + }; + } + + function getParseRegexForToken (token, config) { + if (!hasOwnProp(regexes, token)) { + return new RegExp(unescapeFormat(token)); + } + + return regexes[token](config._strict, config._locale); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function unescapeFormat(s) { + return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + })); + } + + function regexEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + var tokens = {}; + + function addParseToken (token, callback) { + var i, func = callback; + if (typeof token === 'string') { + token = [token]; + } + if (typeof callback === 'number') { + func = function (input, array) { + array[callback] = toInt(input); + }; + } + for (i = 0; i < token.length; i++) { + tokens[token[i]] = func; + } + } + + function addWeekParseToken (token, callback) { + addParseToken(token, function (input, array, config, token) { + config._w = config._w || {}; + callback(input, config._w, config, token); + }); + } + + function addTimeToArrayFromToken(token, input, config) { + if (input != null && hasOwnProp(tokens, token)) { + tokens[token](input, config._a, config, token); + } + } + + var YEAR = 0; + var MONTH = 1; + var DATE = 2; + var HOUR = 3; + var MINUTE = 4; + var SECOND = 5; + var MILLISECOND = 6; + var WEEK = 7; + var WEEKDAY = 8; + + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } + + // FORMATTING + + addFormatToken('M', ['MM', 2], 'Mo', function () { + return this.month() + 1; + }); + + addFormatToken('MMM', 0, 0, function (format) { + return this.localeData().monthsShort(this, format); + }); + + addFormatToken('MMMM', 0, 0, function (format) { + return this.localeData().months(this, format); + }); + + // ALIASES + + addUnitAlias('month', 'M'); + + // PARSING + + addRegexToken('M', match1to2); + addRegexToken('MM', match1to2, match2); + addRegexToken('MMM', function (isStrict, locale) { + return locale.monthsShortRegex(isStrict); + }); + addRegexToken('MMMM', function (isStrict, locale) { + return locale.monthsRegex(isStrict); + }); + + addParseToken(['M', 'MM'], function (input, array) { + array[MONTH] = toInt(input) - 1; + }); + + addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { + var month = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (month != null) { + array[MONTH] = month; + } else { + getParsingFlags(config).invalidMonth = input; + } + }); + + // LOCALES + + var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/; + var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'); + function localeMonths (m, format) { + return isArray(this._months) ? this._months[m.month()] : + this._months[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()]; + } + + var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'); + function localeMonthsShort (m, format) { + return isArray(this._monthsShort) ? this._monthsShort[m.month()] : + this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()]; + } + + function localeMonthsParse (monthName, format, strict) { + var i, mom, regex; + + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } + + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = create_utc__createUTC([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); + this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); + } + if (!strict && !this._monthsParse[i]) { + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { + return i; + } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + } + + // MOMENTS + + function setMonth (mom, value) { + var dayOfMonth; + + if (!mom.isValid()) { + // No op + return mom; + } + + // TODO: Move this out of here! + if (typeof value === 'string') { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (typeof value !== 'number') { + return mom; + } + } + + dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; + } + + function getSetMonth (value) { + if (value != null) { + setMonth(this, value); + utils_hooks__hooks.updateOffset(this, true); + return this; + } else { + return get_set__get(this, 'Month'); + } + } + + function getDaysInMonth () { + return daysInMonth(this.year(), this.month()); + } + + var defaultMonthsShortRegex = matchWord; + function monthsShortRegex (isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsShortStrictRegex; + } else { + return this._monthsShortRegex; + } + } else { + return this._monthsShortStrictRegex && isStrict ? + this._monthsShortStrictRegex : this._monthsShortRegex; + } + } + + var defaultMonthsRegex = matchWord; + function monthsRegex (isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsStrictRegex; + } else { + return this._monthsRegex; + } + } else { + return this._monthsStrictRegex && isStrict ? + this._monthsStrictRegex : this._monthsRegex; + } + } + + function computeMonthsParse () { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var shortPieces = [], longPieces = [], mixedPieces = [], + i, mom; + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = create_utc__createUTC([2000, i]); + shortPieces.push(this.monthsShort(mom, '')); + longPieces.push(this.months(mom, '')); + mixedPieces.push(this.months(mom, '')); + mixedPieces.push(this.monthsShort(mom, '')); + } + // Sorting makes sure if one month (or abbr) is a prefix of another it + // will match the longer piece. + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + for (i = 0; i < 12; i++) { + shortPieces[i] = regexEscape(shortPieces[i]); + longPieces[i] = regexEscape(longPieces[i]); + mixedPieces[i] = regexEscape(mixedPieces[i]); + } + + this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._monthsShortRegex = this._monthsRegex; + this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')$', 'i'); + this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')$', 'i'); + } + + function checkOverflow (m) { + var overflow; + var a = m._a; + + if (a && getParsingFlags(m).overflow === -2) { + overflow = + a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : + a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE : + a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR : + a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE : + a[SECOND] < 0 || a[SECOND] > 59 ? SECOND : + a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + if (getParsingFlags(m)._overflowWeeks && overflow === -1) { + overflow = WEEK; + } + if (getParsingFlags(m)._overflowWeekday && overflow === -1) { + overflow = WEEKDAY; + } + + getParsingFlags(m).overflow = overflow; + } + + return m; + } + + function warn(msg) { + if (utils_hooks__hooks.suppressDeprecationWarnings === false && + (typeof console !== 'undefined') && console.warn) { + console.warn('Deprecation warning: ' + msg); + } + } + + function deprecate(msg, fn) { + var firstTime = true; + + return extend(function () { + if (firstTime) { + warn(msg + '\nArguments: ' + Array.prototype.slice.call(arguments).join(', ') + '\n' + (new Error()).stack); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } + + var deprecations = {}; + + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + warn(msg); + deprecations[name] = true; + } + } + + utils_hooks__hooks.suppressDeprecationWarnings = false; + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/; + var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/; + + var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/; + + var isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], + ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], + ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], + ['GGGG-[W]WW', /\d{4}-W\d\d/, false], + ['YYYY-DDD', /\d{4}-\d{3}/], + ['YYYY-MM', /\d{4}-\d\d/, false], + ['YYYYYYMMDD', /[+-]\d{10}/], + ['YYYYMMDD', /\d{8}/], + // YYYYMM is NOT allowed by the standard + ['GGGG[W]WWE', /\d{4}W\d{3}/], + ['GGGG[W]WW', /\d{4}W\d{2}/, false], + ['YYYYDDD', /\d{7}/] + ]; + + // iso time formats and regexes + var isoTimes = [ + ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], + ['HH:mm:ss', /\d\d:\d\d:\d\d/], + ['HH:mm', /\d\d:\d\d/], + ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], + ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], + ['HHmmss', /\d\d\d\d\d\d/], + ['HHmm', /\d\d\d\d/], + ['HH', /\d\d/] + ]; + + var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; + + // date from iso format + function configFromISO(config) { + var i, l, + string = config._i, + match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), + allowTime, dateFormat, timeFormat, tzFormat; + + if (match) { + getParsingFlags(config).iso = true; + + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(match[1])) { + dateFormat = isoDates[i][0]; + allowTime = isoDates[i][2] !== false; + break; + } + } + if (dateFormat == null) { + config._isValid = false; + return; + } + if (match[3]) { + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(match[3])) { + // match[2] should be 'T' or space + timeFormat = (match[2] || ' ') + isoTimes[i][0]; + break; + } + } + if (timeFormat == null) { + config._isValid = false; + return; + } + } + if (!allowTime && timeFormat != null) { + config._isValid = false; + return; + } + if (match[4]) { + if (tzRegex.exec(match[4])) { + tzFormat = 'Z'; + } else { + config._isValid = false; + return; + } + } + config._f = dateFormat + (timeFormat || '') + (tzFormat || ''); + configFromStringAndFormat(config); + } else { + config._isValid = false; + } + } + + // date from iso format or fallback + function configFromString(config) { + var matched = aspNetJsonRegex.exec(config._i); + + if (matched !== null) { + config._d = new Date(+matched[1]); + return; + } + + configFromISO(config); + if (config._isValid === false) { + delete config._isValid; + utils_hooks__hooks.createFromInputFallback(config); + } + } + + utils_hooks__hooks.createFromInputFallback = deprecate( + 'moment construction falls back to js Date. This is ' + + 'discouraged and will be removed in upcoming major ' + + 'release. Please refer to ' + + 'https://github.com/moment/moment/issues/1407 for more info.', + function (config) { + config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); + } + ); + + function createDate (y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); + + //the date constructor remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0 && isFinite(date.getFullYear())) { + date.setFullYear(y); + } + return date; + } + + function createUTCDate (y) { + var date = new Date(Date.UTC.apply(null, arguments)); + + //the Date.UTC function remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) { + date.setUTCFullYear(y); + } + return date; + } + + // FORMATTING + + addFormatToken('Y', 0, 0, function () { + var y = this.year(); + return y <= 9999 ? '' + y : '+' + y; + }); + + addFormatToken(0, ['YY', 2], 0, function () { + return this.year() % 100; + }); + + addFormatToken(0, ['YYYY', 4], 0, 'year'); + addFormatToken(0, ['YYYYY', 5], 0, 'year'); + addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); + + // ALIASES + + addUnitAlias('year', 'y'); + + // PARSING + + addRegexToken('Y', matchSigned); + addRegexToken('YY', match1to2, match2); + addRegexToken('YYYY', match1to4, match4); + addRegexToken('YYYYY', match1to6, match6); + addRegexToken('YYYYYY', match1to6, match6); + + addParseToken(['YYYYY', 'YYYYYY'], YEAR); + addParseToken('YYYY', function (input, array) { + array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input); + }); + addParseToken('YY', function (input, array) { + array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input); + }); + addParseToken('Y', function (input, array) { + array[YEAR] = parseInt(input, 10); + }); + + // HELPERS + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + // HOOKS + + utils_hooks__hooks.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + + // MOMENTS + + var getSetYear = makeGetSet('FullYear', false); + + function getIsLeapYear () { + return isLeapYear(this.year()); + } + + // start-of-first-week - start-of-year + function firstWeekOffset(year, dow, doy) { + var // first-week day -- which january is always in the first week (4 for iso, 1 for other) + fwd = 7 + dow - doy, + // first-week day local weekday -- which local weekday is fwd + fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7; + + return -fwdlw + fwd - 1; + } + + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, dow, doy) { + var localWeekday = (7 + weekday - dow) % 7, + weekOffset = firstWeekOffset(year, dow, doy), + dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, + resYear, resDayOfYear; + + if (dayOfYear <= 0) { + resYear = year - 1; + resDayOfYear = daysInYear(resYear) + dayOfYear; + } else if (dayOfYear > daysInYear(year)) { + resYear = year + 1; + resDayOfYear = dayOfYear - daysInYear(year); + } else { + resYear = year; + resDayOfYear = dayOfYear; + } + + return { + year: resYear, + dayOfYear: resDayOfYear + }; + } + + function weekOfYear(mom, dow, doy) { + var weekOffset = firstWeekOffset(mom.year(), dow, doy), + week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, + resWeek, resYear; + + if (week < 1) { + resYear = mom.year() - 1; + resWeek = week + weeksInYear(resYear, dow, doy); + } else if (week > weeksInYear(mom.year(), dow, doy)) { + resWeek = week - weeksInYear(mom.year(), dow, doy); + resYear = mom.year() + 1; + } else { + resYear = mom.year(); + resWeek = week; + } + + return { + week: resWeek, + year: resYear + }; + } + + function weeksInYear(year, dow, doy) { + var weekOffset = firstWeekOffset(year, dow, doy), + weekOffsetNext = firstWeekOffset(year + 1, dow, doy); + return (daysInYear(year) - weekOffset + weekOffsetNext) / 7; + } + + // Pick the first defined of two or three arguments. + function defaults(a, b, c) { + if (a != null) { + return a; + } + if (b != null) { + return b; + } + return c; + } + + function currentDateArray(config) { + // hooks is actually the exported moment object + var nowValue = new Date(utils_hooks__hooks.now()); + if (config._useUTC) { + return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()]; + } + return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()]; + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function configFromArray (config) { + var i, date, input = [], currentDate, yearToUse; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); + + if (config._dayOfYear > daysInYear(yearToUse)) { + getParsingFlags(config)._overflowDayOfYear = true; + } + + date = createUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // Check for 24:00:00.000 + if (config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0) { + config._nextDay = true; + config._a[HOUR] = 0; + } + + config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input); + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } + + if (config._nextDay) { + config._a[HOUR] = 24; + } + } + + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year); + week = defaults(w.W, 1); + weekday = defaults(w.E, 1); + if (weekday < 1 || weekday > 7) { + weekdayOverflow = true; + } + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; + + weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year); + week = defaults(w.w, 1); + + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < 0 || weekday > 6) { + weekdayOverflow = true; + } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; + if (w.e < 0 || w.e > 6) { + weekdayOverflow = true; + } + } else { + // default to begining of week + weekday = dow; + } + } + if (week < 1 || week > weeksInYear(weekYear, dow, doy)) { + getParsingFlags(config)._overflowWeeks = true; + } else if (weekdayOverflow != null) { + getParsingFlags(config)._overflowWeekday = true; + } else { + temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy); + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + } + + // constant that refers to the ISO standard + utils_hooks__hooks.ISO_8601 = function () {}; + + // date from string and format string + function configFromStringAndFormat(config) { + // TODO: Move this to another part of the creation flow to prevent circular deps + if (config._f === utils_hooks__hooks.ISO_8601) { + configFromISO(config); + return; + } + + config._a = []; + getParsingFlags(config).empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + // console.log('token', token, 'parsedInput', parsedInput, + // 'regex', getParseRegexForToken(token, config)); + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + getParsingFlags(config).unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + getParsingFlags(config).empty = false; + } + else { + getParsingFlags(config).unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + getParsingFlags(config).unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + getParsingFlags(config).unusedInput.push(string); + } + + // clear _12h flag if hour is <= 12 + if (getParsingFlags(config).bigHour === true && + config._a[HOUR] <= 12 && + config._a[HOUR] > 0) { + getParsingFlags(config).bigHour = undefined; + } + // handle meridiem + config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem); + + configFromArray(config); + checkOverflow(config); + } + + + function meridiemFixWrap (locale, hour, meridiem) { + var isPm; + + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // this is not supposed to happen + return hour; + } + } + + // date from string and array of format strings + function configFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + getParsingFlags(config).invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._f = config._f[i]; + configFromStringAndFormat(tempConfig); + + if (!valid__isValid(tempConfig)) { + continue; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += getParsingFlags(tempConfig).charsLeftOver; + + //or tokens + currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; + + getParsingFlags(tempConfig).score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + + extend(config, bestMoment || tempConfig); + } + + function configFromObject(config) { + if (config._d) { + return; + } + + var i = normalizeObjectUnits(config._i); + config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) { + return obj && parseInt(obj, 10); + }); + + configFromArray(config); + } + + function createFromConfig (config) { + var res = new Moment(checkOverflow(prepareConfig(config))); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } + + return res; + } + + function prepareConfig (config) { + var input = config._i, + format = config._f; + + config._locale = config._locale || locale_locales__getLocale(config._l); + + if (input === null || (format === undefined && input === '')) { + return valid__createInvalid({nullInput: true}); + } + + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + + if (isMoment(input)) { + return new Moment(checkOverflow(input)); + } else if (isArray(format)) { + configFromStringAndArray(config); + } else if (format) { + configFromStringAndFormat(config); + } else if (isDate(input)) { + config._d = input; + } else { + configFromInput(config); + } + + if (!valid__isValid(config)) { + config._d = null; + } + + return config; + } + + function configFromInput(config) { + var input = config._i; + if (input === undefined) { + config._d = new Date(utils_hooks__hooks.now()); + } else if (isDate(input)) { + config._d = new Date(+input); + } else if (typeof input === 'string') { + configFromString(config); + } else if (isArray(input)) { + config._a = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + configFromArray(config); + } else if (typeof(input) === 'object') { + configFromObject(config); + } else if (typeof(input) === 'number') { + // from milliseconds + config._d = new Date(input); + } else { + utils_hooks__hooks.createFromInputFallback(config); + } + } + + function createLocalOrUTC (input, format, locale, strict, isUTC) { + var c = {}; + + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c._isAMomentObject = true; + c._useUTC = c._isUTC = isUTC; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + + return createFromConfig(c); + } + + function local__createLocal (input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, false); + } + + var prototypeMin = deprecate( + 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', + function () { + var other = local__createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other < this ? this : other; + } else { + return valid__createInvalid(); + } + } + ); + + var prototypeMax = deprecate( + 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', + function () { + var other = local__createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other > this ? this : other; + } else { + return valid__createInvalid(); + } + } + ); + + // Pick a moment m from moments so that m[fn](other) is true for all + // other. This relies on the function fn to be transitive. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return local__createLocal(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (!moments[i].isValid() || moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } + + // TODO: Use [].sort instead? + function min () { + var args = [].slice.call(arguments, 0); + + return pickBy('isBefore', args); + } + + function max () { + var args = [].slice.call(arguments, 0); + + return pickBy('isAfter', args); + } + + var now = function () { + return Date.now ? Date.now() : +(new Date()); + }; + + function Duration (duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; + + this._data = {}; + + this._locale = locale_locales__getLocale(); + + this._bubble(); + } + + function isDuration (obj) { + return obj instanceof Duration; + } + + // FORMATTING + + function offset (token, separator) { + addFormatToken(token, 0, 0, function () { + var offset = this.utcOffset(); + var sign = '+'; + if (offset < 0) { + offset = -offset; + sign = '-'; + } + return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2); + }); + } + + offset('Z', ':'); + offset('ZZ', ''); + + // PARSING + + addRegexToken('Z', matchShortOffset); + addRegexToken('ZZ', matchShortOffset); + addParseToken(['Z', 'ZZ'], function (input, array, config) { + config._useUTC = true; + config._tzm = offsetFromString(matchShortOffset, input); + }); + + // HELPERS + + // timezone chunker + // '+10:00' > ['10', '00'] + // '-1530' > ['-15', '30'] + var chunkOffset = /([\+\-]|\d\d)/gi; + + function offsetFromString(matcher, string) { + var matches = ((string || '').match(matcher) || []); + var chunk = matches[matches.length - 1] || []; + var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; + var minutes = +(parts[1] * 60) + toInt(parts[2]); + + return parts[0] === '+' ? minutes : -minutes; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function cloneWithOffset(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = (isMoment(input) || isDate(input) ? +input : +local__createLocal(input)) - (+res); + // Use low-level api, because this fn is low-level api. + res._d.setTime(+res._d + diff); + utils_hooks__hooks.updateOffset(res, false); + return res; + } else { + return local__createLocal(input).local(); + } + } + + function getDateOffset (m) { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(m._d.getTimezoneOffset() / 15) * 15; + } + + // HOOKS + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + utils_hooks__hooks.updateOffset = function () {}; + + // MOMENTS + + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +0200, so we adjust the time as needed, to be valid. + // + // Keeping the time actually adds/subtracts (one hour) + // from the actual represented time. That is why we call updateOffset + // a second time. In case it wants us to change the offset again + // _changeInProgress == true case, then we have to adjust, because + // there is no such time in the given timezone. + function getSetOffset (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; + if (!this.isValid()) { + return input != null ? this : NaN; + } + if (input != null) { + if (typeof input === 'string') { + input = offsetFromString(matchShortOffset, input); + } else if (Math.abs(input) < 16) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = getDateOffset(this); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + add_subtract__addSubtract(this, create__createDuration(input - offset, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + utils_hooks__hooks.updateOffset(this, true); + this._changeInProgress = null; + } + } + return this; + } else { + return this._isUTC ? offset : getDateOffset(this); + } + } + + function getSetZone (input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } + + this.utcOffset(input, keepLocalTime); + + return this; + } else { + return -this.utcOffset(); + } + } + + function setOffsetToUTC (keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + } + + function setOffsetToLocal (keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.subtract(getDateOffset(this), 'm'); + } + } + return this; + } + + function setOffsetToParsedOffset () { + if (this._tzm) { + this.utcOffset(this._tzm); + } else if (typeof this._i === 'string') { + this.utcOffset(offsetFromString(matchOffset, this._i)); + } + return this; + } + + function hasAlignedHourOffset (input) { + if (!this.isValid()) { + return false; + } + input = input ? local__createLocal(input).utcOffset() : 0; + + return (this.utcOffset() - input) % 60 === 0; + } + + function isDaylightSavingTime () { + return ( + this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset() + ); + } + + function isDaylightSavingTimeShifted () { + if (!isUndefined(this._isDSTShifted)) { + return this._isDSTShifted; + } + + var c = {}; + + copyConfig(c, this); + c = prepareConfig(c); + + if (c._a) { + var other = c._isUTC ? create_utc__createUTC(c._a) : local__createLocal(c._a); + this._isDSTShifted = this.isValid() && + compareArrays(c._a, other.toArray()) > 0; + } else { + this._isDSTShifted = false; + } + + return this._isDSTShifted; + } + + function isLocal () { + return this.isValid() ? !this._isUTC : false; + } + + function isUtcOffset () { + return this.isValid() ? this._isUTC : false; + } + + function isUtc () { + return this.isValid() ? this._isUTC && this._offset === 0 : false; + } + + // ASP.NET json date format regex + var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/; + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + var isoRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/; + + function create__createDuration (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + diffRes; + + if (isDuration(input)) { + duration = { + ms : input._milliseconds, + d : input._days, + M : input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y : 0, + d : toInt(match[DATE]) * sign, + h : toInt(match[HOUR]) * sign, + m : toInt(match[MINUTE]) * sign, + s : toInt(match[SECOND]) * sign, + ms : toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y : parseIso(match[2], sign), + M : parseIso(match[3], sign), + d : parseIso(match[4], sign), + h : parseIso(match[5], sign), + m : parseIso(match[6], sign), + s : parseIso(match[7], sign), + w : parseIso(match[8], sign) + }; + } else if (duration == null) {// checks for null or undefined + duration = {}; + } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to)); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } + + ret = new Duration(duration); + + if (isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } + + return ret; + } + + create__createDuration.fn = Duration.prototype; + + function parseIso (inp, sign) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + } + + function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; + + res.months = other.month() - base.month() + + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +(base.clone().add(res.months, 'M')); + + return res; + } + + function momentsDifference(base, other) { + var res; + if (!(base.isValid() && other.isValid())) { + return {milliseconds: 0, months: 0}; + } + + other = cloneWithOffset(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; + } + + // TODO: remove 'name' arg after deprecation is removed + function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).'); + tmp = val; val = period; period = tmp; + } + + val = typeof val === 'string' ? +val : val; + dur = create__createDuration(val, period); + add_subtract__addSubtract(this, dur, direction); + return this; + }; + } + + function add_subtract__addSubtract (mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months; + + if (!mom.isValid()) { + // No op + return; + } + + updateOffset = updateOffset == null ? true : updateOffset; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + if (days) { + get_set__set(mom, 'Date', get_set__get(mom, 'Date') + days * isAdding); + } + if (months) { + setMonth(mom, get_set__get(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + utils_hooks__hooks.updateOffset(mom, days || months); + } + } + + var add_subtract__add = createAdder(1, 'add'); + var add_subtract__subtract = createAdder(-1, 'subtract'); + + function moment_calendar__calendar (time, formats) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're local/utc/offset or not. + var now = time || local__createLocal(), + sod = cloneWithOffset(now, this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + + var output = formats && (isFunction(formats[format]) ? formats[format]() : formats[format]); + + return this.format(output || this.localeData().calendar(format, this, local__createLocal(now))); + } + + function clone () { + return new Moment(this); + } + + function isAfter (input, units) { + var localInput = isMoment(input) ? input : local__createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(!isUndefined(units) ? units : 'millisecond'); + if (units === 'millisecond') { + return +this > +localInput; + } else { + return +localInput < +this.clone().startOf(units); + } + } + + function isBefore (input, units) { + var localInput = isMoment(input) ? input : local__createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(!isUndefined(units) ? units : 'millisecond'); + if (units === 'millisecond') { + return +this < +localInput; + } else { + return +this.clone().endOf(units) < +localInput; + } + } + + function isBetween (from, to, units) { + return this.isAfter(from, units) && this.isBefore(to, units); + } + + function isSame (input, units) { + var localInput = isMoment(input) ? input : local__createLocal(input), + inputMs; + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units || 'millisecond'); + if (units === 'millisecond') { + return +this === +localInput; + } else { + inputMs = +localInput; + return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); + } + } + + function isSameOrAfter (input, units) { + return this.isSame(input, units) || this.isAfter(input,units); + } + + function isSameOrBefore (input, units) { + return this.isSame(input, units) || this.isBefore(input,units); + } + + function diff (input, units, asFloat) { + var that, + zoneDelta, + delta, output; + + if (!this.isValid()) { + return NaN; + } + + that = cloneWithOffset(input, this); + + if (!that.isValid()) { + return NaN; + } + + zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4; + + units = normalizeUnits(units); + + if (units === 'year' || units === 'month' || units === 'quarter') { + output = monthDiff(this, that); + if (units === 'quarter') { + output = output / 3; + } else if (units === 'year') { + output = output / 12; + } + } else { + delta = this - that; + output = units === 'second' ? delta / 1e3 : // 1000 + units === 'minute' ? delta / 6e4 : // 1000 * 60 + units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + delta; + } + return asFloat ? output : absFloor(output); + } + + function monthDiff (a, b) { + // difference in months + var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, adjust; + + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } + + return -(wholeMonthDiff + adjust); + } + + utils_hooks__hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; + + function toString () { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + } + + function moment_format__toISOString () { + var m = this.clone().utc(); + if (0 < m.year() && m.year() <= 9999) { + if (isFunction(Date.prototype.toISOString)) { + // native implementation is ~50x faster, use it when we can + return this.toDate().toISOString(); + } else { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } + + function format (inputString) { + var output = formatMoment(this, inputString || utils_hooks__hooks.defaultFormat); + return this.localeData().postformat(output); + } + + function from (time, withoutSuffix) { + if (this.isValid() && + ((isMoment(time) && time.isValid()) || + local__createLocal(time).isValid())) { + return create__createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function fromNow (withoutSuffix) { + return this.from(local__createLocal(), withoutSuffix); + } + + function to (time, withoutSuffix) { + if (this.isValid() && + ((isMoment(time) && time.isValid()) || + local__createLocal(time).isValid())) { + return create__createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function toNow (withoutSuffix) { + return this.to(local__createLocal(), withoutSuffix); + } + + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + function locale (key) { + var newLocaleData; + + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = locale_locales__getLocale(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + } + + var lang = deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ); + + function localeData () { + return this._locale; + } + + function startOf (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + } + + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } + if (units === 'isoWeek') { + this.isoWeekday(1); + } + + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } + + return this; + } + + function endOf (units) { + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond') { + return this; + } + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); + } + + function to_type__valueOf () { + return +this._d - ((this._offset || 0) * 60000); + } + + function unix () { + return Math.floor(+this / 1000); + } + + function toDate () { + return this._offset ? new Date(+this) : this._d; + } + + function toArray () { + var m = this; + return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()]; + } + + function toObject () { + var m = this; + return { + years: m.year(), + months: m.month(), + date: m.date(), + hours: m.hours(), + minutes: m.minutes(), + seconds: m.seconds(), + milliseconds: m.milliseconds() + }; + } + + function toJSON () { + // JSON.stringify(new Date(NaN)) === 'null' + return this.isValid() ? this.toISOString() : 'null'; + } + + function moment_valid__isValid () { + return valid__isValid(this); + } + + function parsingFlags () { + return extend({}, getParsingFlags(this)); + } + + function invalidAt () { + return getParsingFlags(this).overflow; + } + + function creationData() { + return { + input: this._i, + format: this._f, + locale: this._locale, + isUTC: this._isUTC, + strict: this._strict + }; + } + + // FORMATTING + + addFormatToken(0, ['gg', 2], 0, function () { + return this.weekYear() % 100; + }); + + addFormatToken(0, ['GG', 2], 0, function () { + return this.isoWeekYear() % 100; + }); + + function addWeekYearFormatToken (token, getter) { + addFormatToken(0, [token, token.length], 0, getter); + } + + addWeekYearFormatToken('gggg', 'weekYear'); + addWeekYearFormatToken('ggggg', 'weekYear'); + addWeekYearFormatToken('GGGG', 'isoWeekYear'); + addWeekYearFormatToken('GGGGG', 'isoWeekYear'); + + // ALIASES + + addUnitAlias('weekYear', 'gg'); + addUnitAlias('isoWeekYear', 'GG'); + + // PARSING + + addRegexToken('G', matchSigned); + addRegexToken('g', matchSigned); + addRegexToken('GG', match1to2, match2); + addRegexToken('gg', match1to2, match2); + addRegexToken('GGGG', match1to4, match4); + addRegexToken('gggg', match1to4, match4); + addRegexToken('GGGGG', match1to6, match6); + addRegexToken('ggggg', match1to6, match6); + + addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) { + week[token.substr(0, 2)] = toInt(input); + }); + + addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { + week[token] = utils_hooks__hooks.parseTwoDigitYear(input); + }); + + // MOMENTS + + function getSetWeekYear (input) { + return getSetWeekYearHelper.call(this, + input, + this.week(), + this.weekday(), + this.localeData()._week.dow, + this.localeData()._week.doy); + } + + function getSetISOWeekYear (input) { + return getSetWeekYearHelper.call(this, + input, this.isoWeek(), this.isoWeekday(), 1, 4); + } + + function getISOWeeksInYear () { + return weeksInYear(this.year(), 1, 4); + } + + function getWeeksInYear () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + } + + function getSetWeekYearHelper(input, week, weekday, dow, doy) { + var weeksTarget; + if (input == null) { + return weekOfYear(this, dow, doy).year; + } else { + weeksTarget = weeksInYear(input, dow, doy); + if (week > weeksTarget) { + week = weeksTarget; + } + return setWeekAll.call(this, input, week, weekday, dow, doy); + } + } + + function setWeekAll(weekYear, week, weekday, dow, doy) { + var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), + date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear); + + // console.log("got", weekYear, week, weekday, "set", date.toISOString()); + this.year(date.getUTCFullYear()); + this.month(date.getUTCMonth()); + this.date(date.getUTCDate()); + return this; + } + + // FORMATTING + + addFormatToken('Q', 0, 'Qo', 'quarter'); + + // ALIASES + + addUnitAlias('quarter', 'Q'); + + // PARSING + + addRegexToken('Q', match1); + addParseToken('Q', function (input, array) { + array[MONTH] = (toInt(input) - 1) * 3; + }); + + // MOMENTS + + function getSetQuarter (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); + } + + // FORMATTING + + addFormatToken('w', ['ww', 2], 'wo', 'week'); + addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); + + // ALIASES + + addUnitAlias('week', 'w'); + addUnitAlias('isoWeek', 'W'); + + // PARSING + + addRegexToken('w', match1to2); + addRegexToken('ww', match1to2, match2); + addRegexToken('W', match1to2); + addRegexToken('WW', match1to2, match2); + + addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) { + week[token.substr(0, 1)] = toInt(input); + }); + + // HELPERS + + // LOCALES + + function localeWeek (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + } + + var defaultLocaleWeek = { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }; + + function localeFirstDayOfWeek () { + return this._week.dow; + } + + function localeFirstDayOfYear () { + return this._week.doy; + } + + // MOMENTS + + function getSetWeek (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + function getSetISOWeek (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + // FORMATTING + + addFormatToken('D', ['DD', 2], 'Do', 'date'); + + // ALIASES + + addUnitAlias('date', 'D'); + + // PARSING + + addRegexToken('D', match1to2); + addRegexToken('DD', match1to2, match2); + addRegexToken('Do', function (isStrict, locale) { + return isStrict ? locale._ordinalParse : locale._ordinalParseLenient; + }); + + addParseToken(['D', 'DD'], DATE); + addParseToken('Do', function (input, array) { + array[DATE] = toInt(input.match(match1to2)[0], 10); + }); + + // MOMENTS + + var getSetDayOfMonth = makeGetSet('Date', true); + + // FORMATTING + + addFormatToken('d', 0, 'do', 'day'); + + addFormatToken('dd', 0, 0, function (format) { + return this.localeData().weekdaysMin(this, format); + }); + + addFormatToken('ddd', 0, 0, function (format) { + return this.localeData().weekdaysShort(this, format); + }); + + addFormatToken('dddd', 0, 0, function (format) { + return this.localeData().weekdays(this, format); + }); + + addFormatToken('e', 0, 0, 'weekday'); + addFormatToken('E', 0, 0, 'isoWeekday'); + + // ALIASES + + addUnitAlias('day', 'd'); + addUnitAlias('weekday', 'e'); + addUnitAlias('isoWeekday', 'E'); + + // PARSING + + addRegexToken('d', match1to2); + addRegexToken('e', match1to2); + addRegexToken('E', match1to2); + addRegexToken('dd', matchWord); + addRegexToken('ddd', matchWord); + addRegexToken('dddd', matchWord); + + addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) { + var weekday = config._locale.weekdaysParse(input, token, config._strict); + // if we didn't get a weekday name, mark the date as invalid + if (weekday != null) { + week.d = weekday; + } else { + getParsingFlags(config).invalidWeekday = input; + } + }); + + addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { + week[token] = toInt(input); + }); + + // HELPERS + + function parseWeekday(input, locale) { + if (typeof input !== 'string') { + return input; + } + + if (!isNaN(input)) { + return parseInt(input, 10); + } + + input = locale.weekdaysParse(input); + if (typeof input === 'number') { + return input; + } + + return null; + } + + // LOCALES + + var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'); + function localeWeekdays (m, format) { + return isArray(this._weekdays) ? this._weekdays[m.day()] : + this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()]; + } + + var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'); + function localeWeekdaysShort (m) { + return this._weekdaysShort[m.day()]; + } + + var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'); + function localeWeekdaysMin (m) { + return this._weekdaysMin[m.day()]; + } + + function localeWeekdaysParse (weekdayName, format, strict) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._minWeekdaysParse = []; + this._shortWeekdaysParse = []; + this._fullWeekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + + mom = local__createLocal([2000, 1]).day(i); + if (strict && !this._fullWeekdaysParse[i]) { + this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i'); + this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i'); + this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i'); + } + if (!this._weekdaysParse[i]) { + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) { + return i; + } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) { + return i; + } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) { + return i; + } else if (!strict && this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + } + + // MOMENTS + + function getSetDayOfWeek (input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + } + + function getSetLocaleDayOfWeek (input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + } + + function getSetISODayOfWeek (input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + } + + // FORMATTING + + addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); + + // ALIASES + + addUnitAlias('dayOfYear', 'DDD'); + + // PARSING + + addRegexToken('DDD', match1to3); + addRegexToken('DDDD', match3); + addParseToken(['DDD', 'DDDD'], function (input, array, config) { + config._dayOfYear = toInt(input); + }); + + // HELPERS + + // MOMENTS + + function getSetDayOfYear (input) { + var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); + } + + // FORMATTING + + function hFormat() { + return this.hours() % 12 || 12; + } + + addFormatToken('H', ['HH', 2], 0, 'hour'); + addFormatToken('h', ['hh', 2], 0, hFormat); + + addFormatToken('hmm', 0, 0, function () { + return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2); + }); + + addFormatToken('hmmss', 0, 0, function () { + return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2); + }); + + addFormatToken('Hmm', 0, 0, function () { + return '' + this.hours() + zeroFill(this.minutes(), 2); + }); + + addFormatToken('Hmmss', 0, 0, function () { + return '' + this.hours() + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2); + }); + + function meridiem (token, lowercase) { + addFormatToken(token, 0, 0, function () { + return this.localeData().meridiem(this.hours(), this.minutes(), lowercase); + }); + } + + meridiem('a', true); + meridiem('A', false); + + // ALIASES + + addUnitAlias('hour', 'h'); + + // PARSING + + function matchMeridiem (isStrict, locale) { + return locale._meridiemParse; + } + + addRegexToken('a', matchMeridiem); + addRegexToken('A', matchMeridiem); + addRegexToken('H', match1to2); + addRegexToken('h', match1to2); + addRegexToken('HH', match1to2, match2); + addRegexToken('hh', match1to2, match2); + + addRegexToken('hmm', match3to4); + addRegexToken('hmmss', match5to6); + addRegexToken('Hmm', match3to4); + addRegexToken('Hmmss', match5to6); + + addParseToken(['H', 'HH'], HOUR); + addParseToken(['a', 'A'], function (input, array, config) { + config._isPm = config._locale.isPM(input); + config._meridiem = input; + }); + addParseToken(['h', 'hh'], function (input, array, config) { + array[HOUR] = toInt(input); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmmss', function (input, array, config) { + var pos1 = input.length - 4; + var pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('Hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + }); + addParseToken('Hmmss', function (input, array, config) { + var pos1 = input.length - 4; + var pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + }); + + // LOCALES + + function localeIsPM (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + } + + var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i; + function localeMeridiem (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + } + + + // MOMENTS + + // Setting the hour should keep the time, because the user explicitly + // specified which hour he wants. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + var getSetHour = makeGetSet('Hours', true); + + // FORMATTING + + addFormatToken('m', ['mm', 2], 0, 'minute'); + + // ALIASES + + addUnitAlias('minute', 'm'); + + // PARSING + + addRegexToken('m', match1to2); + addRegexToken('mm', match1to2, match2); + addParseToken(['m', 'mm'], MINUTE); + + // MOMENTS + + var getSetMinute = makeGetSet('Minutes', false); + + // FORMATTING + + addFormatToken('s', ['ss', 2], 0, 'second'); + + // ALIASES + + addUnitAlias('second', 's'); + + // PARSING + + addRegexToken('s', match1to2); + addRegexToken('ss', match1to2, match2); + addParseToken(['s', 'ss'], SECOND); + + // MOMENTS + + var getSetSecond = makeGetSet('Seconds', false); + + // FORMATTING + + addFormatToken('S', 0, 0, function () { + return ~~(this.millisecond() / 100); + }); + + addFormatToken(0, ['SS', 2], 0, function () { + return ~~(this.millisecond() / 10); + }); + + addFormatToken(0, ['SSS', 3], 0, 'millisecond'); + addFormatToken(0, ['SSSS', 4], 0, function () { + return this.millisecond() * 10; + }); + addFormatToken(0, ['SSSSS', 5], 0, function () { + return this.millisecond() * 100; + }); + addFormatToken(0, ['SSSSSS', 6], 0, function () { + return this.millisecond() * 1000; + }); + addFormatToken(0, ['SSSSSSS', 7], 0, function () { + return this.millisecond() * 10000; + }); + addFormatToken(0, ['SSSSSSSS', 8], 0, function () { + return this.millisecond() * 100000; + }); + addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { + return this.millisecond() * 1000000; + }); + + + // ALIASES + + addUnitAlias('millisecond', 'ms'); + + // PARSING + + addRegexToken('S', match1to3, match1); + addRegexToken('SS', match1to3, match2); + addRegexToken('SSS', match1to3, match3); + + var token; + for (token = 'SSSS'; token.length <= 9; token += 'S') { + addRegexToken(token, matchUnsigned); + } + + function parseMs(input, array) { + array[MILLISECOND] = toInt(('0.' + input) * 1000); + } + + for (token = 'S'; token.length <= 9; token += 'S') { + addParseToken(token, parseMs); + } + // MOMENTS + + var getSetMillisecond = makeGetSet('Milliseconds', false); + + // FORMATTING + + addFormatToken('z', 0, 0, 'zoneAbbr'); + addFormatToken('zz', 0, 0, 'zoneName'); + + // MOMENTS + + function getZoneAbbr () { + return this._isUTC ? 'UTC' : ''; + } + + function getZoneName () { + return this._isUTC ? 'Coordinated Universal Time' : ''; + } + + var momentPrototype__proto = Moment.prototype; + + momentPrototype__proto.add = add_subtract__add; + momentPrototype__proto.calendar = moment_calendar__calendar; + momentPrototype__proto.clone = clone; + momentPrototype__proto.diff = diff; + momentPrototype__proto.endOf = endOf; + momentPrototype__proto.format = format; + momentPrototype__proto.from = from; + momentPrototype__proto.fromNow = fromNow; + momentPrototype__proto.to = to; + momentPrototype__proto.toNow = toNow; + momentPrototype__proto.get = getSet; + momentPrototype__proto.invalidAt = invalidAt; + momentPrototype__proto.isAfter = isAfter; + momentPrototype__proto.isBefore = isBefore; + momentPrototype__proto.isBetween = isBetween; + momentPrototype__proto.isSame = isSame; + momentPrototype__proto.isSameOrAfter = isSameOrAfter; + momentPrototype__proto.isSameOrBefore = isSameOrBefore; + momentPrototype__proto.isValid = moment_valid__isValid; + momentPrototype__proto.lang = lang; + momentPrototype__proto.locale = locale; + momentPrototype__proto.localeData = localeData; + momentPrototype__proto.max = prototypeMax; + momentPrototype__proto.min = prototypeMin; + momentPrototype__proto.parsingFlags = parsingFlags; + momentPrototype__proto.set = getSet; + momentPrototype__proto.startOf = startOf; + momentPrototype__proto.subtract = add_subtract__subtract; + momentPrototype__proto.toArray = toArray; + momentPrototype__proto.toObject = toObject; + momentPrototype__proto.toDate = toDate; + momentPrototype__proto.toISOString = moment_format__toISOString; + momentPrototype__proto.toJSON = toJSON; + momentPrototype__proto.toString = toString; + momentPrototype__proto.unix = unix; + momentPrototype__proto.valueOf = to_type__valueOf; + momentPrototype__proto.creationData = creationData; + + // Year + momentPrototype__proto.year = getSetYear; + momentPrototype__proto.isLeapYear = getIsLeapYear; + + // Week Year + momentPrototype__proto.weekYear = getSetWeekYear; + momentPrototype__proto.isoWeekYear = getSetISOWeekYear; + + // Quarter + momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter; + + // Month + momentPrototype__proto.month = getSetMonth; + momentPrototype__proto.daysInMonth = getDaysInMonth; + + // Week + momentPrototype__proto.week = momentPrototype__proto.weeks = getSetWeek; + momentPrototype__proto.isoWeek = momentPrototype__proto.isoWeeks = getSetISOWeek; + momentPrototype__proto.weeksInYear = getWeeksInYear; + momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear; + + // Day + momentPrototype__proto.date = getSetDayOfMonth; + momentPrototype__proto.day = momentPrototype__proto.days = getSetDayOfWeek; + momentPrototype__proto.weekday = getSetLocaleDayOfWeek; + momentPrototype__proto.isoWeekday = getSetISODayOfWeek; + momentPrototype__proto.dayOfYear = getSetDayOfYear; + + // Hour + momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour; + + // Minute + momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute; + + // Second + momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond; + + // Millisecond + momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond; + + // Offset + momentPrototype__proto.utcOffset = getSetOffset; + momentPrototype__proto.utc = setOffsetToUTC; + momentPrototype__proto.local = setOffsetToLocal; + momentPrototype__proto.parseZone = setOffsetToParsedOffset; + momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset; + momentPrototype__proto.isDST = isDaylightSavingTime; + momentPrototype__proto.isDSTShifted = isDaylightSavingTimeShifted; + momentPrototype__proto.isLocal = isLocal; + momentPrototype__proto.isUtcOffset = isUtcOffset; + momentPrototype__proto.isUtc = isUtc; + momentPrototype__proto.isUTC = isUtc; + + // Timezone + momentPrototype__proto.zoneAbbr = getZoneAbbr; + momentPrototype__proto.zoneName = getZoneName; + + // Deprecations + momentPrototype__proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth); + momentPrototype__proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth); + momentPrototype__proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear); + momentPrototype__proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779', getSetZone); + + var momentPrototype = momentPrototype__proto; + + function moment__createUnix (input) { + return local__createLocal(input * 1000); + } + + function moment__createInZone () { + return local__createLocal.apply(null, arguments).parseZone(); + } + + var defaultCalendar = { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }; + + function locale_calendar__calendar (key, mom, now) { + var output = this._calendar[key]; + return isFunction(output) ? output.call(mom, now) : output; + } + + var defaultLongDateFormat = { + LTS : 'h:mm:ss A', + LT : 'h:mm A', + L : 'MM/DD/YYYY', + LL : 'MMMM D, YYYY', + LLL : 'MMMM D, YYYY h:mm A', + LLLL : 'dddd, MMMM D, YYYY h:mm A' + }; + + function longDateFormat (key) { + var format = this._longDateFormat[key], + formatUpper = this._longDateFormat[key.toUpperCase()]; + + if (format || !formatUpper) { + return format; + } + + this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + + return this._longDateFormat[key]; + } + + var defaultInvalidDate = 'Invalid date'; + + function invalidDate () { + return this._invalidDate; + } + + var defaultOrdinal = '%d'; + var defaultOrdinalParse = /\d{1,2}/; + + function ordinal (number) { + return this._ordinal.replace('%d', number); + } + + function preParsePostFormat (string) { + return string; + } + + var defaultRelativeTime = { + future : 'in %s', + past : '%s ago', + s : 'a few seconds', + m : 'a minute', + mm : '%d minutes', + h : 'an hour', + hh : '%d hours', + d : 'a day', + dd : '%d days', + M : 'a month', + MM : '%d months', + y : 'a year', + yy : '%d years' + }; + + function relative__relativeTime (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (isFunction(output)) ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); + } + + function pastFuture (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return isFunction(format) ? format(output) : format.replace(/%s/i, output); + } + + function locale_set__set (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (isFunction(prop)) { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _ordinalParseLenient. + this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source); + } + + var prototype__proto = Locale.prototype; + + prototype__proto._calendar = defaultCalendar; + prototype__proto.calendar = locale_calendar__calendar; + prototype__proto._longDateFormat = defaultLongDateFormat; + prototype__proto.longDateFormat = longDateFormat; + prototype__proto._invalidDate = defaultInvalidDate; + prototype__proto.invalidDate = invalidDate; + prototype__proto._ordinal = defaultOrdinal; + prototype__proto.ordinal = ordinal; + prototype__proto._ordinalParse = defaultOrdinalParse; + prototype__proto.preparse = preParsePostFormat; + prototype__proto.postformat = preParsePostFormat; + prototype__proto._relativeTime = defaultRelativeTime; + prototype__proto.relativeTime = relative__relativeTime; + prototype__proto.pastFuture = pastFuture; + prototype__proto.set = locale_set__set; + + // Month + prototype__proto.months = localeMonths; + prototype__proto._months = defaultLocaleMonths; + prototype__proto.monthsShort = localeMonthsShort; + prototype__proto._monthsShort = defaultLocaleMonthsShort; + prototype__proto.monthsParse = localeMonthsParse; + prototype__proto._monthsRegex = defaultMonthsRegex; + prototype__proto.monthsRegex = monthsRegex; + prototype__proto._monthsShortRegex = defaultMonthsShortRegex; + prototype__proto.monthsShortRegex = monthsShortRegex; + + // Week + prototype__proto.week = localeWeek; + prototype__proto._week = defaultLocaleWeek; + prototype__proto.firstDayOfYear = localeFirstDayOfYear; + prototype__proto.firstDayOfWeek = localeFirstDayOfWeek; + + // Day of Week + prototype__proto.weekdays = localeWeekdays; + prototype__proto._weekdays = defaultLocaleWeekdays; + prototype__proto.weekdaysMin = localeWeekdaysMin; + prototype__proto._weekdaysMin = defaultLocaleWeekdaysMin; + prototype__proto.weekdaysShort = localeWeekdaysShort; + prototype__proto._weekdaysShort = defaultLocaleWeekdaysShort; + prototype__proto.weekdaysParse = localeWeekdaysParse; + + // Hours + prototype__proto.isPM = localeIsPM; + prototype__proto._meridiemParse = defaultLocaleMeridiemParse; + prototype__proto.meridiem = localeMeridiem; + + function lists__get (format, index, field, setter) { + var locale = locale_locales__getLocale(); + var utc = create_utc__createUTC().set(setter, index); + return locale[field](utc, format); + } + + function list (format, index, field, count, setter) { + if (typeof format === 'number') { + index = format; + format = undefined; + } + + format = format || ''; + + if (index != null) { + return lists__get(format, index, field, setter); + } + + var i; + var out = []; + for (i = 0; i < count; i++) { + out[i] = lists__get(format, i, field, setter); + } + return out; + } + + function lists__listMonths (format, index) { + return list(format, index, 'months', 12, 'month'); + } + + function lists__listMonthsShort (format, index) { + return list(format, index, 'monthsShort', 12, 'month'); + } + + function lists__listWeekdays (format, index) { + return list(format, index, 'weekdays', 7, 'day'); + } + + function lists__listWeekdaysShort (format, index) { + return list(format, index, 'weekdaysShort', 7, 'day'); + } + + function lists__listWeekdaysMin (format, index) { + return list(format, index, 'weekdaysMin', 7, 'day'); + } + + locale_locales__getSetGlobalLocale('en', { + ordinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + // Side effect imports + utils_hooks__hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', locale_locales__getSetGlobalLocale); + utils_hooks__hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', locale_locales__getLocale); + + var mathAbs = Math.abs; + + function duration_abs__abs () { + var data = this._data; + + this._milliseconds = mathAbs(this._milliseconds); + this._days = mathAbs(this._days); + this._months = mathAbs(this._months); + + data.milliseconds = mathAbs(data.milliseconds); + data.seconds = mathAbs(data.seconds); + data.minutes = mathAbs(data.minutes); + data.hours = mathAbs(data.hours); + data.months = mathAbs(data.months); + data.years = mathAbs(data.years); + + return this; + } + + function duration_add_subtract__addSubtract (duration, input, value, direction) { + var other = create__createDuration(input, value); + + duration._milliseconds += direction * other._milliseconds; + duration._days += direction * other._days; + duration._months += direction * other._months; + + return duration._bubble(); + } + + // supports only 2.0-style add(1, 's') or add(duration) + function duration_add_subtract__add (input, value) { + return duration_add_subtract__addSubtract(this, input, value, 1); + } + + // supports only 2.0-style subtract(1, 's') or subtract(duration) + function duration_add_subtract__subtract (input, value) { + return duration_add_subtract__addSubtract(this, input, value, -1); + } + + function absCeil (number) { + if (number < 0) { + return Math.floor(number); + } else { + return Math.ceil(number); + } + } + + function bubble () { + var milliseconds = this._milliseconds; + var days = this._days; + var months = this._months; + var data = this._data; + var seconds, minutes, hours, years, monthsFromDays; + + // if we have a mix of positive and negative values, bubble down first + // check: https://github.com/moment/moment/issues/2166 + if (!((milliseconds >= 0 && days >= 0 && months >= 0) || + (milliseconds <= 0 && days <= 0 && months <= 0))) { + milliseconds += absCeil(monthsToDays(months) + days) * 864e5; + days = 0; + months = 0; + } + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absFloor(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absFloor(seconds / 60); + data.minutes = minutes % 60; + + hours = absFloor(minutes / 60); + data.hours = hours % 24; + + days += absFloor(hours / 24); + + // convert days to months + monthsFromDays = absFloor(daysToMonths(days)); + months += monthsFromDays; + days -= absCeil(monthsToDays(monthsFromDays)); + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + data.days = days; + data.months = months; + data.years = years; + + return this; + } + + function daysToMonths (days) { + // 400 years have 146097 days (taking into account leap year rules) + // 400 years have 12 months === 4800 + return days * 4800 / 146097; + } + + function monthsToDays (months) { + // the reverse of daysToMonths + return months * 146097 / 4800; + } + + function as (units) { + var days; + var months; + var milliseconds = this._milliseconds; + + units = normalizeUnits(units); + + if (units === 'month' || units === 'year') { + days = this._days + milliseconds / 864e5; + months = this._months + daysToMonths(days); + return units === 'month' ? months : months / 12; + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(monthsToDays(this._months)); + switch (units) { + case 'week' : return days / 7 + milliseconds / 6048e5; + case 'day' : return days + milliseconds / 864e5; + case 'hour' : return days * 24 + milliseconds / 36e5; + case 'minute' : return days * 1440 + milliseconds / 6e4; + case 'second' : return days * 86400 + milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': return Math.floor(days * 864e5) + milliseconds; + default: throw new Error('Unknown unit ' + units); + } + } + } + + // TODO: Use this.as('ms')? + function duration_as__valueOf () { + return ( + this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6 + ); + } + + function makeAs (alias) { + return function () { + return this.as(alias); + }; + } + + var asMilliseconds = makeAs('ms'); + var asSeconds = makeAs('s'); + var asMinutes = makeAs('m'); + var asHours = makeAs('h'); + var asDays = makeAs('d'); + var asWeeks = makeAs('w'); + var asMonths = makeAs('M'); + var asYears = makeAs('y'); + + function duration_get__get (units) { + units = normalizeUnits(units); + return this[units + 's'](); + } + + function makeGetter(name) { + return function () { + return this._data[name]; + }; + } + + var milliseconds = makeGetter('milliseconds'); + var seconds = makeGetter('seconds'); + var minutes = makeGetter('minutes'); + var hours = makeGetter('hours'); + var days = makeGetter('days'); + var months = makeGetter('months'); + var years = makeGetter('years'); + + function weeks () { + return absFloor(this.days() / 7); + } + + var round = Math.round; + var thresholds = { + s: 45, // seconds to minute + m: 45, // minutes to hour + h: 22, // hours to day + d: 26, // days to month + M: 11 // months to year + }; + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function duration_humanize__relativeTime (posNegDuration, withoutSuffix, locale) { + var duration = create__createDuration(posNegDuration).abs(); + var seconds = round(duration.as('s')); + var minutes = round(duration.as('m')); + var hours = round(duration.as('h')); + var days = round(duration.as('d')); + var months = round(duration.as('M')); + var years = round(duration.as('y')); + + var a = seconds < thresholds.s && ['s', seconds] || + minutes <= 1 && ['m'] || + minutes < thresholds.m && ['mm', minutes] || + hours <= 1 && ['h'] || + hours < thresholds.h && ['hh', hours] || + days <= 1 && ['d'] || + days < thresholds.d && ['dd', days] || + months <= 1 && ['M'] || + months < thresholds.M && ['MM', months] || + years <= 1 && ['y'] || ['yy', years]; + + a[2] = withoutSuffix; + a[3] = +posNegDuration > 0; + a[4] = locale; + return substituteTimeAgo.apply(null, a); + } + + // This function allows you to set a threshold for relative time strings + function duration_humanize__getSetRelativeTimeThreshold (threshold, limit) { + if (thresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return thresholds[threshold]; + } + thresholds[threshold] = limit; + return true; + } + + function humanize (withSuffix) { + var locale = this.localeData(); + var output = duration_humanize__relativeTime(this, !withSuffix, locale); + + if (withSuffix) { + output = locale.pastFuture(+this, output); + } + + return locale.postformat(output); + } + + var iso_string__abs = Math.abs; + + function iso_string__toISOString() { + // for ISO strings we do not use the normal bubbling rules: + // * milliseconds bubble up until they become hours + // * days do not bubble at all + // * months bubble up until they become years + // This is because there is no context-free conversion between hours and days + // (think of clock changes) + // and also not between days and months (28-31 days per month) + var seconds = iso_string__abs(this._milliseconds) / 1000; + var days = iso_string__abs(this._days); + var months = iso_string__abs(this._months); + var minutes, hours, years; + + // 3600 seconds -> 60 minutes -> 1 hour + minutes = absFloor(seconds / 60); + hours = absFloor(minutes / 60); + seconds %= 60; + minutes %= 60; + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var Y = years; + var M = months; + var D = days; + var h = hours; + var m = minutes; + var s = seconds; + var total = this.asSeconds(); + + if (!total) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + return (total < 0 ? '-' : '') + + 'P' + + (Y ? Y + 'Y' : '') + + (M ? M + 'M' : '') + + (D ? D + 'D' : '') + + ((h || m || s) ? 'T' : '') + + (h ? h + 'H' : '') + + (m ? m + 'M' : '') + + (s ? s + 'S' : ''); + } + + var duration_prototype__proto = Duration.prototype; + + duration_prototype__proto.abs = duration_abs__abs; + duration_prototype__proto.add = duration_add_subtract__add; + duration_prototype__proto.subtract = duration_add_subtract__subtract; + duration_prototype__proto.as = as; + duration_prototype__proto.asMilliseconds = asMilliseconds; + duration_prototype__proto.asSeconds = asSeconds; + duration_prototype__proto.asMinutes = asMinutes; + duration_prototype__proto.asHours = asHours; + duration_prototype__proto.asDays = asDays; + duration_prototype__proto.asWeeks = asWeeks; + duration_prototype__proto.asMonths = asMonths; + duration_prototype__proto.asYears = asYears; + duration_prototype__proto.valueOf = duration_as__valueOf; + duration_prototype__proto._bubble = bubble; + duration_prototype__proto.get = duration_get__get; + duration_prototype__proto.milliseconds = milliseconds; + duration_prototype__proto.seconds = seconds; + duration_prototype__proto.minutes = minutes; + duration_prototype__proto.hours = hours; + duration_prototype__proto.days = days; + duration_prototype__proto.weeks = weeks; + duration_prototype__proto.months = months; + duration_prototype__proto.years = years; + duration_prototype__proto.humanize = humanize; + duration_prototype__proto.toISOString = iso_string__toISOString; + duration_prototype__proto.toString = iso_string__toISOString; + duration_prototype__proto.toJSON = iso_string__toISOString; + duration_prototype__proto.locale = locale; + duration_prototype__proto.localeData = localeData; + + // Deprecations + duration_prototype__proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', iso_string__toISOString); + duration_prototype__proto.lang = lang; + + // Side effect imports + + // FORMATTING + + addFormatToken('X', 0, 0, 'unix'); + addFormatToken('x', 0, 0, 'valueOf'); + + // PARSING + + addRegexToken('x', matchSigned); + addRegexToken('X', matchTimestamp); + addParseToken('X', function (input, array, config) { + config._d = new Date(parseFloat(input, 10) * 1000); + }); + addParseToken('x', function (input, array, config) { + config._d = new Date(toInt(input)); + }); + + // Side effect imports + + + utils_hooks__hooks.version = '2.11.2'; + + setHookCallback(local__createLocal); + + utils_hooks__hooks.fn = momentPrototype; + utils_hooks__hooks.min = min; + utils_hooks__hooks.max = max; + utils_hooks__hooks.now = now; + utils_hooks__hooks.utc = create_utc__createUTC; + utils_hooks__hooks.unix = moment__createUnix; + utils_hooks__hooks.months = lists__listMonths; + utils_hooks__hooks.isDate = isDate; + utils_hooks__hooks.locale = locale_locales__getSetGlobalLocale; + utils_hooks__hooks.invalid = valid__createInvalid; + utils_hooks__hooks.duration = create__createDuration; + utils_hooks__hooks.isMoment = isMoment; + utils_hooks__hooks.weekdays = lists__listWeekdays; + utils_hooks__hooks.parseZone = moment__createInZone; + utils_hooks__hooks.localeData = locale_locales__getLocale; + utils_hooks__hooks.isDuration = isDuration; + utils_hooks__hooks.monthsShort = lists__listMonthsShort; + utils_hooks__hooks.weekdaysMin = lists__listWeekdaysMin; + utils_hooks__hooks.defineLocale = defineLocale; + utils_hooks__hooks.weekdaysShort = lists__listWeekdaysShort; + utils_hooks__hooks.normalizeUnits = normalizeUnits; + utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold; + utils_hooks__hooks.prototype = momentPrototype; + + var _moment = utils_hooks__hooks; + + return _moment; + +})); +},{}],7:[function(require,module,exports){ +/*! + * Chart.js + * http://chartjs.org/ + * Version: 2.0.0-beta2 + * + * Copyright 2015 Nick Downie + * Released under the MIT license + * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md + */ + + +var Chart = require('./core/core.js')(); + +require('./core/core.helpers')(Chart); +require('./core/core.element')(Chart); +require('./core/core.animation')(Chart); +require('./core/core.controller')(Chart); +require('./core/core.datasetController')(Chart); +require('./core/core.layoutService')(Chart); +require('./core/core.legend')(Chart); +require('./core/core.scale')(Chart); +require('./core/core.scaleService')(Chart); +require('./core/core.title')(Chart); +require('./core/core.tooltip')(Chart); + +require('./controllers/controller.bar')(Chart); +require('./controllers/controller.bubble')(Chart); +require('./controllers/controller.doughnut')(Chart); +require('./controllers/controller.line')(Chart); +require('./controllers/controller.polarArea')(Chart); +require('./controllers/controller.radar')(Chart); + +require('./scales/scale.category')(Chart); +require('./scales/scale.linear')(Chart); +require('./scales/scale.logarithmic')(Chart); +require('./scales/scale.radialLinear')(Chart); +require('./scales/scale.time')(Chart); + +require('./elements/element.arc')(Chart); +require('./elements/element.line')(Chart); +require('./elements/element.point')(Chart); +require('./elements/element.rectangle')(Chart); + +require('./charts/Chart.Bar')(Chart); +require('./charts/Chart.Bubble')(Chart); +require('./charts/Chart.Doughnut')(Chart); +require('./charts/Chart.Line')(Chart); +require('./charts/Chart.PolarArea')(Chart); +require('./charts/Chart.Radar')(Chart); +require('./charts/Chart.Scatter')(Chart); + +window.Chart = module.exports = Chart; + +},{"./charts/Chart.Bar":8,"./charts/Chart.Bubble":9,"./charts/Chart.Doughnut":10,"./charts/Chart.Line":11,"./charts/Chart.PolarArea":12,"./charts/Chart.Radar":13,"./charts/Chart.Scatter":14,"./controllers/controller.bar":15,"./controllers/controller.bubble":16,"./controllers/controller.doughnut":17,"./controllers/controller.line":18,"./controllers/controller.polarArea":19,"./controllers/controller.radar":20,"./core/core.animation":21,"./core/core.controller":22,"./core/core.datasetController":23,"./core/core.element":24,"./core/core.helpers":25,"./core/core.js":26,"./core/core.layoutService":27,"./core/core.legend":28,"./core/core.scale":29,"./core/core.scaleService":30,"./core/core.title":31,"./core/core.tooltip":32,"./elements/element.arc":33,"./elements/element.line":34,"./elements/element.point":35,"./elements/element.rectangle":36,"./scales/scale.category":37,"./scales/scale.linear":38,"./scales/scale.logarithmic":39,"./scales/scale.radialLinear":40,"./scales/scale.time":41}],8:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + Chart.Bar = function(context, config) { + config.type = 'bar'; + + return new Chart(context, config); + }; + +}; +},{}],9:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + Chart.Bubble = function(context, config) { + config.type = 'bubble'; + return new Chart(context, config); + }; + +}; +},{}],10:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + Chart.Doughnut = function(context, config) { + config.type = 'doughnut'; + + return new Chart(context, config); + }; + +}; +},{}],11:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + Chart.Line = function(context, config) { + config.type = 'line'; + + return new Chart(context, config); + }; + +}; +},{}],12:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + Chart.PolarArea = function(context, config) { + config.type = 'polarArea'; + + return new Chart(context, config); + }; + +}; +},{}],13:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + var defaultConfig = { + aspectRatio: 1 + }; + + Chart.Radar = function(context, config) { + config.options = helpers.configMerge(defaultConfig, config.options); + config.type = 'radar'; + + return new Chart(context, config); + }; + +}; + +},{}],14:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var defaultConfig = { + hover: { + mode: 'single' + }, + + scales: { + xAxes: [{ + type: "linear", // scatter should not use a category axis + position: "bottom", + id: "x-axis-1" // need an ID so datasets can reference the scale + }], + yAxes: [{ + type: "linear", + position: "left", + id: "y-axis-1" + }] + }, + + tooltips: { + callbacks: { + title: function(tooltipItems, data) { + // Title doesn't make sense for scatter since we format the data as a point + return ''; + }, + label: function(tooltipItem, data) { + return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')'; + } + } + } + }; + + // Register the default config for this type + Chart.defaults.scatter = defaultConfig; + + // Scatter charts use line controllers + Chart.controllers.scatter = Chart.controllers.line; + + Chart.Scatter = function(context, config) { + config.type = 'scatter'; + return new Chart(context, config); + }; + +}; +},{}],15:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.bar = { + hover: { + mode: "label" + }, + + scales: { + xAxes: [{ + type: "category", + + // Specific to Bar Controller + categoryPercentage: 0.8, + barPercentage: 0.9, + + // grid line settings + gridLines: { + offsetGridLines: true + } + }], + yAxes: [{ + type: "linear" + }] + } + }; + + Chart.controllers.bar = Chart.DatasetController.extend({ + initialize: function(chart, datasetIndex) { + Chart.DatasetController.prototype.initialize.call(this, chart, datasetIndex); + + // Use this to indicate that this is a bar dataset. + this.getDataset().bar = true; + }, + // Get the number of datasets that display bars. We use this to correctly calculate the bar width + getBarCount: function getBarCount() { + var barCount = 0; + helpers.each(this.chart.data.datasets, function(dataset) { + if (helpers.isDatasetVisible(dataset) && dataset.bar) { + ++barCount; + } + }); + return barCount; + }, + + addElements: function() { + this.getDataset().metaData = this.getDataset().metaData || []; + helpers.each(this.getDataset().data, function(value, index) { + this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Rectangle({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + }, this); + }, + addElementAndReset: function(index) { + this.getDataset().metaData = this.getDataset().metaData || []; + var rectangle = new Chart.elements.Rectangle({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + + var numBars = this.getBarCount(); + + this.updateElement(rectangle, index, true, numBars); + this.getDataset().metaData.splice(index, 0, rectangle); + }, + + update: function update(reset) { + var numBars = this.getBarCount(); + + helpers.each(this.getDataset().metaData, function(rectangle, index) { + this.updateElement(rectangle, index, reset, numBars); + }, this); + }, + + updateElement: function updateElement(rectangle, index, reset, numBars) { + + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var yScale = this.getScaleForId(this.getDataset().yAxisID); + + var yScalePoint; + + if (yScale.min < 0 && yScale.max < 0) { + // all less than 0. use the top + yScalePoint = yScale.getPixelForValue(yScale.max); + } else if (yScale.min > 0 && yScale.max > 0) { + yScalePoint = yScale.getPixelForValue(yScale.min); + } else { + yScalePoint = yScale.getPixelForValue(0); + } + + helpers.extend(rectangle, { + // Utility + _chart: this.chart.chart, + _xScale: xScale, + _yScale: yScale, + _datasetIndex: this.index, + _index: index, + + + // Desired view properties + _model: { + x: this.calculateBarX(index, this.index), + y: reset ? yScalePoint : this.calculateBarY(index, this.index), + + // Tooltip + label: this.chart.data.labels[index], + datasetLabel: this.getDataset().label, + + // Appearance + base: reset ? yScalePoint : this.calculateBarBase(this.index, index), + width: this.calculateBarWidth(numBars), + backgroundColor: rectangle.custom && rectangle.custom.backgroundColor ? rectangle.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.rectangle.backgroundColor), + borderSkipped: rectangle.custom && rectangle.custom.borderSkipped ? rectangle.custom.borderSkipped : this.chart.options.elements.rectangle.borderSkipped, + borderColor: rectangle.custom && rectangle.custom.borderColor ? rectangle.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.rectangle.borderColor), + borderWidth: rectangle.custom && rectangle.custom.borderWidth ? rectangle.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.rectangle.borderWidth) + } + }); + rectangle.pivot(); + }, + + calculateBarBase: function(datasetIndex, index) { + + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var yScale = this.getScaleForId(this.getDataset().yAxisID); + + var base = 0; + + if (yScale.options.stacked) { + + var value = this.chart.data.datasets[datasetIndex].data[index]; + + if (value < 0) { + for (var i = 0; i < datasetIndex; i++) { + var negDS = this.chart.data.datasets[i]; + if (helpers.isDatasetVisible(negDS) && negDS.yAxisID === yScale.id && negDS.bar) { + base += negDS.data[index] < 0 ? negDS.data[index] : 0; + } + } + } else { + for (var j = 0; j < datasetIndex; j++) { + var posDS = this.chart.data.datasets[j]; + if (helpers.isDatasetVisible(posDS) && posDS.yAxisID === yScale.id && posDS.bar) { + base += posDS.data[index] > 0 ? posDS.data[index] : 0; + } + } + } + + return yScale.getPixelForValue(base); + } + + base = yScale.getPixelForValue(yScale.min); + + if (yScale.beginAtZero || ((yScale.min <= 0 && yScale.max >= 0) || (yScale.min >= 0 && yScale.max <= 0))) { + base = yScale.getPixelForValue(0, 0); + //base += yScale.options.gridLines.lineWidth; + } else if (yScale.min < 0 && yScale.max < 0) { + // All values are negative. Use the top as the base + base = yScale.getPixelForValue(yScale.max); + } + + return base; + + }, + + getRuler: function() { + + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var yScale = this.getScaleForId(this.getDataset().yAxisID); + var datasetCount = this.getBarCount(); + + var tickWidth = (function() { + var min = xScale.getPixelForTick(1) - xScale.getPixelForTick(0); + for (var i = 2; i < this.getDataset().data.length; i++) { + min = Math.min(xScale.getPixelForTick(i) - xScale.getPixelForTick(i - 1), min); + } + return min; + }).call(this); + var categoryWidth = tickWidth * xScale.options.categoryPercentage; + var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2; + var fullBarWidth = categoryWidth / datasetCount; + var barWidth = fullBarWidth * xScale.options.barPercentage; + var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage); + + return { + datasetCount: datasetCount, + tickWidth: tickWidth, + categoryWidth: categoryWidth, + categorySpacing: categorySpacing, + fullBarWidth: fullBarWidth, + barWidth: barWidth, + barSpacing: barSpacing + }; + }, + + calculateBarWidth: function() { + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var ruler = this.getRuler(); + return xScale.options.stacked ? ruler.categoryWidth : ruler.barWidth; + }, + + // Get bar index from the given dataset index accounting for the fact that not all bars are visible + getBarIndex: function(datasetIndex) { + var barIndex = 0; + + for (var j = 0; j < datasetIndex; ++j) { + if (helpers.isDatasetVisible(this.chart.data.datasets[j]) && this.chart.data.datasets[j].bar) { + ++barIndex; + } + } + + return barIndex; + }, + + calculateBarX: function(index, datasetIndex) { + + var yScale = this.getScaleForId(this.getDataset().yAxisID); + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var barIndex = this.getBarIndex(datasetIndex); + + var ruler = this.getRuler(); + var leftTick = xScale.getPixelForValue(null, index, datasetIndex, this.chart.isCombo); + leftTick -= this.chart.isCombo ? (ruler.tickWidth / 2) : 0; + + if (xScale.options.stacked) { + return leftTick + (ruler.categoryWidth / 2) + ruler.categorySpacing; + } + + return leftTick + + (ruler.barWidth / 2) + + ruler.categorySpacing + + (ruler.barWidth * barIndex) + + (ruler.barSpacing / 2) + + (ruler.barSpacing * barIndex); + }, + + calculateBarY: function(index, datasetIndex) { + + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var yScale = this.getScaleForId(this.getDataset().yAxisID); + + var value = this.getDataset().data[index]; + + if (yScale.options.stacked) { + + var sumPos = 0, + sumNeg = 0; + + for (var i = 0; i < datasetIndex; i++) { + var ds = this.chart.data.datasets[i]; + if (helpers.isDatasetVisible(ds) && ds.bar && ds.yAxisID === yScale.id) { + if (ds.data[index] < 0) { + sumNeg += ds.data[index] || 0; + } else { + sumPos += ds.data[index] || 0; + } + } + } + + if (value < 0) { + return yScale.getPixelForValue(sumNeg + value); + } else { + return yScale.getPixelForValue(sumPos + value); + } + + return yScale.getPixelForValue(value); + } + + return yScale.getPixelForValue(value); + }, + + draw: function(ease) { + var easingDecimal = ease || 1; + helpers.each(this.getDataset().metaData, function(rectangle, index) { + var d = this.getDataset().data[index]; + if (d !== null && d !== undefined && !isNaN(d)) { + rectangle.transition(easingDecimal).draw(); + } + }, this); + }, + + setHoverStyle: function(rectangle) { + var dataset = this.chart.data.datasets[rectangle._datasetIndex]; + var index = rectangle._index; + + rectangle._model.backgroundColor = rectangle.custom && rectangle.custom.hoverBackgroundColor ? rectangle.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(rectangle._model.backgroundColor).saturate(0.5).darken(0.1).rgbString()); + rectangle._model.borderColor = rectangle.custom && rectangle.custom.hoverBorderColor ? rectangle.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(rectangle._model.borderColor).saturate(0.5).darken(0.1).rgbString()); + rectangle._model.borderWidth = rectangle.custom && rectangle.custom.hoverBorderWidth ? rectangle.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, rectangle._model.borderWidth); + }, + + removeHoverStyle: function(rectangle) { + var dataset = this.chart.data.datasets[rectangle._datasetIndex]; + var index = rectangle._index; + + rectangle._model.backgroundColor = rectangle.custom && rectangle.custom.backgroundColor ? rectangle.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.rectangle.backgroundColor); + rectangle._model.borderColor = rectangle.custom && rectangle.custom.borderColor ? rectangle.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.rectangle.borderColor); + rectangle._model.borderWidth = rectangle.custom && rectangle.custom.borderWidth ? rectangle.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.rectangle.borderWidth); + } + + }); +}; + +},{}],16:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.bubble = { + hover: { + mode: "single" + }, + + scales: { + xAxes: [{ + type: "linear", // bubble should probably use a linear scale by default + position: "bottom", + id: "x-axis-0" // need an ID so datasets can reference the scale + }], + yAxes: [{ + type: "linear", + position: "left", + id: "y-axis-0" + }] + }, + + tooltips: { + callbacks: { + title: function(tooltipItems, data) { + // Title doesn't make sense for scatter since we format the data as a point + return ''; + }, + label: function(tooltipItem, data) { + var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || ''; + var dataPoint = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; + return datasetLabel + ': (' + dataPoint.x + ', ' + dataPoint.y + ', ' + dataPoint.r + ')'; + } + } + } + }; + + + Chart.controllers.bubble = Chart.DatasetController.extend({ + addElements: function() { + + this.getDataset().metaData = this.getDataset().metaData || []; + + helpers.each(this.getDataset().data, function(value, index) { + this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + }, this); + }, + addElementAndReset: function(index) { + this.getDataset().metaData = this.getDataset().metaData || []; + var point = new Chart.elements.Point({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + + // Reset the point + this.updateElement(point, index, true); + + // Add to the points array + this.getDataset().metaData.splice(index, 0, point); + }, + + update: function update(reset) { + var points = this.getDataset().metaData; + + var yScale = this.getScaleForId(this.getDataset().yAxisID); + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var scaleBase; + + if (yScale.min < 0 && yScale.max < 0) { + scaleBase = yScale.getPixelForValue(yScale.max); + } else if (yScale.min > 0 && yScale.max > 0) { + scaleBase = yScale.getPixelForValue(yScale.min); + } else { + scaleBase = yScale.getPixelForValue(0); + } + + // Update Points + helpers.each(points, function(point, index) { + this.updateElement(point, index, reset); + }, this); + + }, + + updateElement: function(point, index, reset) { + var yScale = this.getScaleForId(this.getDataset().yAxisID); + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var scaleBase; + + if (yScale.min < 0 && yScale.max < 0) { + scaleBase = yScale.getPixelForValue(yScale.max); + } else if (yScale.min > 0 && yScale.max > 0) { + scaleBase = yScale.getPixelForValue(yScale.min); + } else { + scaleBase = yScale.getPixelForValue(0); + } + + helpers.extend(point, { + // Utility + _chart: this.chart.chart, + _xScale: xScale, + _yScale: yScale, + _datasetIndex: this.index, + _index: index, + + // Desired view properties + _model: { + x: reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(this.getDataset().data[index], index, this.index, this.chart.isCombo), + y: reset ? scaleBase : yScale.getPixelForValue(this.getDataset().data[index], index, this.index), + // Appearance + radius: reset ? 0 : point.custom && point.custom.radius ? point.custom.radius : this.getRadius(this.getDataset().data[index]), + backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.point.backgroundColor), + borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.point.borderColor), + borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.point.borderWidth), + + // Tooltip + hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius) + } + }); + + point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y)); + + point.pivot(); + }, + + getRadius: function(value) { + return value.r || this.chart.options.elements.point.radius; + }, + + draw: function(ease) { + var easingDecimal = ease || 1; + + // Transition and Draw the Points + helpers.each(this.getDataset().metaData, function(point, index) { + point.transition(easingDecimal); + point.draw(); + }); + + }, + + setHoverStyle: function(point) { + // Point + var dataset = this.chart.data.datasets[point._datasetIndex]; + var index = point._index; + + point._model.radius = point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : (helpers.getValueAtIndexOrDefault(dataset.hoverRadius, index, this.chart.options.elements.point.hoverRadius)) + this.getRadius(this.getDataset().data[point._index]); + point._model.backgroundColor = point.custom && point.custom.hoverBackgroundColor ? point.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(point._model.backgroundColor).saturate(0.5).darken(0.1).rgbString()); + point._model.borderColor = point.custom && point.custom.hoverBorderColor ? point.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(point._model.borderColor).saturate(0.5).darken(0.1).rgbString()); + point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, point._model.borderWidth); + }, + + removeHoverStyle: function(point) { + var dataset = this.chart.data.datasets[point._datasetIndex]; + var index = point._index; + + point._model.radius = point.custom && point.custom.radius ? point.custom.radius : this.getRadius(this.getDataset().data[point._index]); + point._model.backgroundColor = point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.point.backgroundColor); + point._model.borderColor = point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.point.borderColor); + point._model.borderWidth = point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.point.borderWidth); + } + }); +}; +},{}],17:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.doughnut = { + animation: { + //Boolean - Whether we animate the rotation of the Doughnut + animateRotate: true, + //Boolean - Whether we animate scaling the Doughnut from the centre + animateScale: false + }, + aspectRatio: 1, + hover: { + mode: 'single' + }, + legendCallback: function(chart) { + var text = []; + text.push('
    '); + + if (chart.data.datasets.length) { + for (var i = 0; i < chart.data.datasets[0].data.length; ++i) { + text.push('
  • '); + if (chart.data.labels[i]) { + text.push(chart.data.labels[i]); + } + text.push('
  • '); + } + } + + text.push('
'); + return text.join(""); + }, + legend: { + labels: { + generateLabels: function(data) { + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + return { + text: label, + fillStyle: data.datasets[0].backgroundColor[i], + hidden: isNaN(data.datasets[0].data[i]), + + // Extra data used for toggling the correct item + index: i + }; + }); + } else { + return []; + } + } + }, + onClick: function(e, legendItem) { + helpers.each(this.chart.data.datasets, function(dataset) { + dataset.metaHiddenData = dataset.metaHiddenData || []; + var idx = legendItem.index; + + if (!isNaN(dataset.data[idx])) { + dataset.metaHiddenData[idx] = dataset.data[idx]; + dataset.data[idx] = NaN; + } else if (!isNaN(dataset.metaHiddenData[idx])) { + dataset.data[idx] = dataset.metaHiddenData[idx]; + } + }); + + this.chart.update(); + } + }, + + //The percentage of the chart that we cut out of the middle. + cutoutPercentage: 50, + + // Need to override these to give a nice default + tooltips: { + callbacks: { + title: function() { + return ''; + }, + label: function(tooltipItem, data) { + return data.labels[tooltipItem.index] + ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; + } + } + } + }; + + Chart.defaults.pie = helpers.clone(Chart.defaults.doughnut); + helpers.extend(Chart.defaults.pie, { + cutoutPercentage: 0 + }); + + + Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({ + linkScales: function() { + // no scales for doughnut + }, + + addElements: function() { + this.getDataset().metaData = this.getDataset().metaData || []; + helpers.each(this.getDataset().data, function(value, index) { + this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + }, this); + }, + addElementAndReset: function(index, colorForNewElement) { + this.getDataset().metaData = this.getDataset().metaData || []; + var arc = new Chart.elements.Arc({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + + if (colorForNewElement && helpers.isArray(this.getDataset().backgroundColor)) { + this.getDataset().backgroundColor.splice(index, 0, colorForNewElement); + } + + // Reset the point + this.updateElement(arc, index, true); + + // Add to the points array + this.getDataset().metaData.splice(index, 0, arc); + }, + + getVisibleDatasetCount: function getVisibleDatasetCount() { + return helpers.where(this.chart.data.datasets, function(ds) { + return helpers.isDatasetVisible(ds); + }).length; + }, + + // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly + getRingIndex: function getRingIndex(datasetIndex) { + var ringIndex = 0; + + for (var j = 0; j < datasetIndex; ++j) { + if (helpers.isDatasetVisible(this.chart.data.datasets[j])) { + ++ringIndex; + } + } + + return ringIndex; + }, + + update: function update(reset) { + var minSize = Math.min(this.chart.chartArea.right - this.chart.chartArea.left, this.chart.chartArea.bottom - this.chart.chartArea.top); + + this.chart.outerRadius = Math.max((minSize / 2) - this.chart.options.elements.arc.borderWidth / 2, 0); + this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0); + this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount(); + + this.getDataset().total = 0; + helpers.each(this.getDataset().data, function(value) { + if (!isNaN(value)) { + this.getDataset().total += Math.abs(value); + } + }, this); + + this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.getRingIndex(this.index)); + this.innerRadius = this.outerRadius - this.chart.radiusLength; + + helpers.each(this.getDataset().metaData, function(arc, index) { + this.updateElement(arc, index, reset); + }, this); + }, + updateElement: function(arc, index, reset) { + var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2; + var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2; + var startAngle = Math.PI * -0.5; // non reset case handled later + var endAngle = Math.PI * -0.5; // non reset case handled later + var circumference = reset && this.chart.options.animation.animateRotate ? 0 : this.calculateCircumference(this.getDataset().data[index]); + var innerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.innerRadius; + var outerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.outerRadius; + + helpers.extend(arc, { + // Utility + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index, + + // Desired view properties + _model: { + x: centerX, + y: centerY, + startAngle: startAngle, + endAngle: endAngle, + circumference: circumference, + outerRadius: outerRadius, + innerRadius: innerRadius, + + backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor), + hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor), + borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth), + borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor), + + label: helpers.getValueAtIndexOrDefault(this.getDataset().label, index, this.chart.data.labels[index]) + } + }); + + // Set correct angles if not resetting + if (!reset) { + + if (index === 0) { + arc._model.startAngle = Math.PI * -0.5; // use - PI / 2 instead of 3PI / 2 to make animations better. It means that we never deal with overflow during the transition function + } else { + arc._model.startAngle = this.getDataset().metaData[index - 1]._model.endAngle; + } + + arc._model.endAngle = arc._model.startAngle + arc._model.circumference; + } + + arc.pivot(); + }, + + draw: function(ease) { + var easingDecimal = ease || 1; + helpers.each(this.getDataset().metaData, function(arc, index) { + arc.transition(easingDecimal).draw(); + }); + }, + + setHoverStyle: function(arc) { + var dataset = this.chart.data.datasets[arc._datasetIndex]; + var index = arc._index; + + arc._model.backgroundColor = arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(arc._model.backgroundColor).saturate(0.5).darken(0.1).rgbString()); + arc._model.borderColor = arc.custom && arc.custom.hoverBorderColor ? arc.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(arc._model.borderColor).saturate(0.5).darken(0.1).rgbString()); + arc._model.borderWidth = arc.custom && arc.custom.hoverBorderWidth ? arc.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, arc._model.borderWidth); + }, + + removeHoverStyle: function(arc) { + var dataset = this.chart.data.datasets[arc._datasetIndex]; + var index = arc._index; + + arc._model.backgroundColor = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor); + arc._model.borderColor = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor); + arc._model.borderWidth = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth); + }, + + calculateCircumference: function(value) { + if (this.getDataset().total > 0 && !isNaN(value)) { + return (Math.PI * 1.999999) * (value / this.getDataset().total); + } else { + return 0; + } + } + }); +}; +},{}],18:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.line = { + showLines: true, + + hover: { + mode: "label" + }, + + scales: { + xAxes: [{ + type: "category", + id: 'x-axis-0' + }], + yAxes: [{ + type: "linear", + id: 'y-axis-0' + }] + } + }; + + + Chart.controllers.line = Chart.DatasetController.extend({ + addElements: function() { + + this.getDataset().metaData = this.getDataset().metaData || []; + + this.getDataset().metaDataset = this.getDataset().metaDataset || new Chart.elements.Line({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _points: this.getDataset().metaData + }); + + helpers.each(this.getDataset().data, function(value, index) { + this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + }, this); + }, + addElementAndReset: function(index) { + this.getDataset().metaData = this.getDataset().metaData || []; + var point = new Chart.elements.Point({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + + // Reset the point + this.updateElement(point, index, true); + + // Add to the points array + this.getDataset().metaData.splice(index, 0, point); + + // Make sure bezier control points are updated + if (this.chart.options.showLines && this.chart.options.elements.line.tension !== 0) + this.updateBezierControlPoints(); + }, + + update: function update(reset) { + var line = this.getDataset().metaDataset; + var points = this.getDataset().metaData; + + var yScale = this.getScaleForId(this.getDataset().yAxisID); + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var scaleBase; + + if (yScale.min < 0 && yScale.max < 0) { + scaleBase = yScale.getPixelForValue(yScale.max); + } else if (yScale.min > 0 && yScale.max > 0) { + scaleBase = yScale.getPixelForValue(yScale.min); + } else { + scaleBase = yScale.getPixelForValue(0); + } + + // Update Line + if (this.chart.options.showLines) { + // Utility + line._scale = yScale; + line._datasetIndex = this.index; + // Data + line._children = points; + // Model + line._model = { + // Appearance + tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension), + backgroundColor: line.custom && line.custom.backgroundColor ? line.custom.backgroundColor : (this.getDataset().backgroundColor || this.chart.options.elements.line.backgroundColor), + borderWidth: line.custom && line.custom.borderWidth ? line.custom.borderWidth : (this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth), + borderColor: line.custom && line.custom.borderColor ? line.custom.borderColor : (this.getDataset().borderColor || this.chart.options.elements.line.borderColor), + borderCapStyle: line.custom && line.custom.borderCapStyle ? line.custom.borderCapStyle : (this.getDataset().borderCapStyle || this.chart.options.elements.line.borderCapStyle), + borderDash: line.custom && line.custom.borderDash ? line.custom.borderDash : (this.getDataset().borderDash || this.chart.options.elements.line.borderDash), + borderDashOffset: line.custom && line.custom.borderDashOffset ? line.custom.borderDashOffset : (this.getDataset().borderDashOffset || this.chart.options.elements.line.borderDashOffset), + borderJoinStyle: line.custom && line.custom.borderJoinStyle ? line.custom.borderJoinStyle : (this.getDataset().borderJoinStyle || this.chart.options.elements.line.borderJoinStyle), + fill: line.custom && line.custom.fill ? line.custom.fill : (this.getDataset().fill !== undefined ? this.getDataset().fill : this.chart.options.elements.line.fill), + // Scale + scaleTop: yScale.top, + scaleBottom: yScale.bottom, + scaleZero: scaleBase + }; + line.pivot(); + } + + // Update Points + helpers.each(points, function(point, index) { + this.updateElement(point, index, reset); + }, this); + + if (this.chart.options.showLines && this.chart.options.elements.line.tension !== 0) + this.updateBezierControlPoints(); + }, + + getPointBackgroundColor: function(point, index) { + var backgroundColor = this.chart.options.elements.point.backgroundColor; + var dataset = this.getDataset(); + + if (point.custom && point.custom.backgroundColor) { + backgroundColor = point.custom.backgroundColor; + } else if (dataset.pointBackgroundColor) { + backgroundColor = helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor); + } else if (dataset.backgroundColor) { + backgroundColor = dataset.backgroundColor; + } + + return backgroundColor; + }, + getPointBorderColor: function(point, index) { + var borderColor = this.chart.options.elements.point.borderColor; + var dataset = this.getDataset(); + + if (point.custom && point.custom.borderColor) { + borderColor = point.custom.borderColor; + } else if (dataset.pointBorderColor) { + borderColor = helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, borderColor); + } else if (dataset.borderColor) { + borderColor = dataset.borderColor; + } + + return borderColor; + }, + getPointBorderWidth: function(point, index) { + var borderWidth = this.chart.options.elements.point.borderWidth; + var dataset = this.getDataset(); + + if (point.custom && point.custom.borderWidth !== undefined) { + borderWidth = point.custom.borderWidth; + } else if (dataset.pointBorderWidth !== undefined) { + borderWidth = helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth); + } else if (dataset.borderWidth !== undefined) { + borderWidth = dataset.borderWidth; + } + + return borderWidth; + }, + + updateElement: function(point, index, reset) { + var yScale = this.getScaleForId(this.getDataset().yAxisID); + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var scaleBase; + + if (yScale.min < 0 && yScale.max < 0) { + scaleBase = yScale.getPixelForValue(yScale.max); + } else if (yScale.min > 0 && yScale.max > 0) { + scaleBase = yScale.getPixelForValue(yScale.min); + } else { + scaleBase = yScale.getPixelForValue(0); + } + + // Utility + point._chart = this.chart.chart; + point._xScale = xScale; + point._yScale = yScale; + point._datasetIndex = this.index; + point._index = index; + + // Desired view properties + point._model = { + x: xScale.getPixelForValue(this.getDataset().data[index], index, this.index, this.chart.isCombo), + y: reset ? scaleBase : this.calculatePointY(this.getDataset().data[index], index, this.index, this.chart.isCombo), + // Appearance + tension: point.custom && point.custom.tension ? point.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension), + radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius), + pointStyle: point.custom && point.custom.pointStyle ? point.custom.pointStyle : helpers.getValueAtIndexOrDefault(this.getDataset().pointStyle, index, this.chart.options.elements.point.pointStyle), + backgroundColor: this.getPointBackgroundColor(point, index), + borderColor: this.getPointBorderColor(point, index), + borderWidth: this.getPointBorderWidth(point, index), + // Tooltip + hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius) + }; + + point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y)); + }, + + calculatePointY: function(value, index, datasetIndex, isCombo) { + + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var yScale = this.getScaleForId(this.getDataset().yAxisID); + + if (yScale.options.stacked) { + + var sumPos = 0, + sumNeg = 0; + + for (var i = 0; i < datasetIndex; i++) { + var ds = this.chart.data.datasets[i]; + if (ds.type === 'line' && helpers.isDatasetVisible(ds)) { + if (ds.data[index] < 0) { + sumNeg += ds.data[index] || 0; + } else { + sumPos += ds.data[index] || 0; + } + } + } + + if (value < 0) { + return yScale.getPixelForValue(sumNeg + value); + } else { + return yScale.getPixelForValue(sumPos + value); + } + } + + return yScale.getPixelForValue(value); + }, + + updateBezierControlPoints: function() { + // Update bezier control points + helpers.each(this.getDataset().metaData, function(point, index) { + var controlPoints = helpers.splineCurve( + helpers.previousItem(this.getDataset().metaData, index)._model, + point._model, + helpers.nextItem(this.getDataset().metaData, index)._model, + point._model.tension + ); + + // Prevent the bezier going outside of the bounds of the graph + point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left); + point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.top); + + point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left); + point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top); + + // Now pivot the point for animation + point.pivot(); + }, this); + }, + + draw: function(ease) { + var easingDecimal = ease || 1; + + // Transition Point Locations + helpers.each(this.getDataset().metaData, function(point) { + point.transition(easingDecimal); + }); + + // Transition and Draw the line + if (this.chart.options.showLines) + this.getDataset().metaDataset.transition(easingDecimal).draw(); + + // Draw the points + helpers.each(this.getDataset().metaData, function(point) { + point.draw(); + }); + }, + + setHoverStyle: function(point) { + // Point + var dataset = this.chart.data.datasets[point._datasetIndex]; + var index = point._index; + + point._model.radius = point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius); + point._model.backgroundColor = point.custom && point.custom.hoverBackgroundColor ? point.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(point._model.backgroundColor).saturate(0.5).darken(0.1).rgbString()); + point._model.borderColor = point.custom && point.custom.hoverBorderColor ? point.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(point._model.borderColor).saturate(0.5).darken(0.1).rgbString()); + point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, point._model.borderWidth); + }, + + removeHoverStyle: function(point) { + var dataset = this.chart.data.datasets[point._datasetIndex]; + var index = point._index; + + point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius); + point._model.backgroundColor = this.getPointBackgroundColor(point, index); + point._model.borderColor = this.getPointBorderColor(point, index); + point._model.borderWidth = this.getPointBorderWidth(point, index); + } + }); +}; + +},{}],19:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.polarArea = { + + scale: { + type: "radialLinear", + lineArc: true // so that lines are circular + }, + + //Boolean - Whether to animate the rotation of the chart + animateRotate: true, + animateScale: true, + + aspectRatio: 1, + legendCallback: function(chart) { + var text = []; + text.push('
    '); + + if (chart.data.datasets.length) { + for (var i = 0; i < chart.data.datasets[0].data.length; ++i) { + text.push('
  • '); + if (chart.data.labels[i]) { + text.push(chart.data.labels[i]); + } + text.push('
  • '); + } + } + + text.push('
'); + return text.join(""); + }, + legend: { + labels: { + generateLabels: function(data) { + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + return { + text: label, + fillStyle: data.datasets[0].backgroundColor[i], + hidden: isNaN(data.datasets[0].data[i]), + + // Extra data used for toggling the correct item + index: i + }; + }); + } else { + return []; + } + } + }, + onClick: function(e, legendItem) { + helpers.each(this.chart.data.datasets, function(dataset) { + dataset.metaHiddenData = dataset.metaHiddenData || []; + var idx = legendItem.index; + + if (!isNaN(dataset.data[idx])) { + dataset.metaHiddenData[idx] = dataset.data[idx]; + dataset.data[idx] = NaN; + } else if (!isNaN(dataset.metaHiddenData[idx])) { + dataset.data[idx] = dataset.metaHiddenData[idx]; + } + }); + + this.chart.update(); + } + }, + + // Need to override these to give a nice default + tooltips: { + callbacks: { + title: function() { + return ''; + }, + label: function(tooltipItem, data) { + return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel; + } + } + } + }; + + Chart.controllers.polarArea = Chart.DatasetController.extend({ + linkScales: function() { + // no scales for doughnut + }, + addElements: function() { + this.getDataset().metaData = this.getDataset().metaData || []; + helpers.each(this.getDataset().data, function(value, index) { + this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + }, this); + }, + addElementAndReset: function(index) { + this.getDataset().metaData = this.getDataset().metaData || []; + var arc = new Chart.elements.Arc({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + + // Reset the point + this.updateElement(arc, index, true); + + // Add to the points array + this.getDataset().metaData.splice(index, 0, arc); + }, + getVisibleDatasetCount: function getVisibleDatasetCount() { + return helpers.where(this.chart.data.datasets, function(ds) { + return helpers.isDatasetVisible(ds); + }).length; + }, + + update: function update(reset) { + var minSize = Math.min(this.chart.chartArea.right - this.chart.chartArea.left, this.chart.chartArea.bottom - this.chart.chartArea.top); + this.chart.outerRadius = Math.max((minSize - this.chart.options.elements.arc.borderWidth / 2) / 2, 0); + this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0); + this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount(); + + this.getDataset().total = 0; + helpers.each(this.getDataset().data, function(value) { + this.getDataset().total += Math.abs(value); + }, this); + + this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.index); + this.innerRadius = this.outerRadius - this.chart.radiusLength; + + helpers.each(this.getDataset().metaData, function(arc, index) { + this.updateElement(arc, index, reset); + }, this); + }, + + updateElement: function(arc, index, reset) { + var circumference = this.calculateCircumference(this.getDataset().data[index]); + var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2; + var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2; + + // If there is NaN data before us, we need to calculate the starting angle correctly. + // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data + var notNullIndex = 0; + for (var i = 0; i < index; ++i) { + if (!isNaN(this.getDataset().data[i])) { + ++notNullIndex; + } + } + + var startAngle = (-0.5 * Math.PI) + (circumference * notNullIndex); + var endAngle = startAngle + circumference; + + var resetModel = { + x: centerX, + y: centerY, + innerRadius: 0, + outerRadius: this.chart.options.animateScale ? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]), + startAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : startAngle, + endAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : endAngle, + + backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor), + borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth), + borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor), + + label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index]) + }; + + helpers.extend(arc, { + // Utility + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index, + _scale: this.chart.scale, + + // Desired view properties + _model: reset ? resetModel : { + x: centerX, + y: centerY, + innerRadius: 0, + outerRadius: this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]), + startAngle: startAngle, + endAngle: endAngle, + + backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor), + borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth), + borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor), + + label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index]) + } + }); + + arc.pivot(); + }, + + draw: function(ease) { + var easingDecimal = ease || 1; + helpers.each(this.getDataset().metaData, function(arc, index) { + arc.transition(easingDecimal).draw(); + }); + }, + + setHoverStyle: function(arc) { + var dataset = this.chart.data.datasets[arc._datasetIndex]; + var index = arc._index; + + arc._model.backgroundColor = arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(arc._model.backgroundColor).saturate(0.5).darken(0.1).rgbString()); + arc._model.borderColor = arc.custom && arc.custom.hoverBorderColor ? arc.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(arc._model.borderColor).saturate(0.5).darken(0.1).rgbString()); + arc._model.borderWidth = arc.custom && arc.custom.hoverBorderWidth ? arc.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, arc._model.borderWidth); + }, + + removeHoverStyle: function(arc) { + var dataset = this.chart.data.datasets[arc._datasetIndex]; + var index = arc._index; + + arc._model.backgroundColor = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor); + arc._model.borderColor = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor); + arc._model.borderWidth = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth); + }, + + calculateCircumference: function(value) { + if (isNaN(value)) { + return 0; + } else { + // Count the number of NaN values + var numNaN = helpers.where(this.getDataset().data, function(data) { + return isNaN(data); + }).length; + + return (2 * Math.PI) / (this.getDataset().data.length - numNaN); + } + } + }); + +}; +},{}],20:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + + Chart.defaults.radar = { + scale: { + type: "radialLinear" + }, + elements: { + line: { + tension: 0 // no bezier in radar + } + } + }; + + Chart.controllers.radar = Chart.DatasetController.extend({ + linkScales: function() { + // No need. Single scale only + }, + + addElements: function() { + + this.getDataset().metaData = this.getDataset().metaData || []; + + this.getDataset().metaDataset = this.getDataset().metaDataset || new Chart.elements.Line({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _points: this.getDataset().metaData, + _loop: true + }); + + helpers.each(this.getDataset().data, function(value, index) { + this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index, + _model: { + x: 0, //xScale.getPixelForValue(null, index, true), + y: 0 //this.chartArea.bottom, + } + }); + }, this); + }, + addElementAndReset: function(index) { + this.getDataset().metaData = this.getDataset().metaData || []; + var point = new Chart.elements.Point({ + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index + }); + + // Reset the point + this.updateElement(point, index, true); + + // Add to the points array + this.getDataset().metaData.splice(index, 0, point); + + // Make sure bezier control points are updated + this.updateBezierControlPoints(); + }, + + update: function update(reset) { + + var line = this.getDataset().metaDataset; + var points = this.getDataset().metaData; + + var scale = this.chart.scale; + var scaleBase; + + if (scale.min < 0 && scale.max < 0) { + scaleBase = scale.getPointPositionForValue(0, scale.max); + } else if (scale.min > 0 && scale.max > 0) { + scaleBase = scale.getPointPositionForValue(0, scale.min); + } else { + scaleBase = scale.getPointPositionForValue(0, 0); + } + + helpers.extend(this.getDataset().metaDataset, { + // Utility + _datasetIndex: this.index, + // Data + _children: this.getDataset().metaData, + // Model + _model: { + // Appearance + tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension), + backgroundColor: line.custom && line.custom.backgroundColor ? line.custom.backgroundColor : (this.getDataset().backgroundColor || this.chart.options.elements.line.backgroundColor), + borderWidth: line.custom && line.custom.borderWidth ? line.custom.borderWidth : (this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth), + borderColor: line.custom && line.custom.borderColor ? line.custom.borderColor : (this.getDataset().borderColor || this.chart.options.elements.line.borderColor), + fill: line.custom && line.custom.fill ? line.custom.fill : (this.getDataset().fill !== undefined ? this.getDataset().fill : this.chart.options.elements.line.fill), + borderCapStyle: line.custom && line.custom.borderCapStyle ? line.custom.borderCapStyle : (this.getDataset().borderCapStyle || this.chart.options.elements.line.borderCapStyle), + borderDash: line.custom && line.custom.borderDash ? line.custom.borderDash : (this.getDataset().borderDash || this.chart.options.elements.line.borderDash), + borderDashOffset: line.custom && line.custom.borderDashOffset ? line.custom.borderDashOffset : (this.getDataset().borderDashOffset || this.chart.options.elements.line.borderDashOffset), + borderJoinStyle: line.custom && line.custom.borderJoinStyle ? line.custom.borderJoinStyle : (this.getDataset().borderJoinStyle || this.chart.options.elements.line.borderJoinStyle), + + // Scale + scaleTop: scale.top, + scaleBottom: scale.bottom, + scaleZero: scaleBase + } + }); + + this.getDataset().metaDataset.pivot(); + + // Update Points + helpers.each(points, function(point, index) { + this.updateElement(point, index, reset); + }, this); + + + // Update bezier control points + this.updateBezierControlPoints(); + }, + updateElement: function(point, index, reset) { + var pointPosition = this.chart.scale.getPointPositionForValue(index, this.getDataset().data[index]); + + helpers.extend(point, { + // Utility + _datasetIndex: this.index, + _index: index, + _scale: this.chart.scale, + + // Desired view properties + _model: { + x: reset ? this.chart.scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales + y: reset ? this.chart.scale.yCenter : pointPosition.y, + + // Appearance + tension: point.custom && point.custom.tension ? point.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension), + radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius), + backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor), + borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor), + borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth), + pointStyle: point.custom && point.custom.pointStyle ? point.custom.pointStyle : helpers.getValueAtIndexOrDefault(this.getDataset().pointStyle, index, this.chart.options.elements.point.pointStyle), + + // Tooltip + hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius) + } + }); + + point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y)); + }, + updateBezierControlPoints: function() { + helpers.each(this.getDataset().metaData, function(point, index) { + var controlPoints = helpers.splineCurve( + helpers.previousItem(this.getDataset().metaData, index, true)._model, + point._model, + helpers.nextItem(this.getDataset().metaData, index, true)._model, + point._model.tension + ); + + // Prevent the bezier going outside of the bounds of the graph + point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left); + point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.top); + + point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left); + point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top); + + // Now pivot the point for animation + point.pivot(); + }, this); + }, + + draw: function(ease) { + var easingDecimal = ease || 1; + + // Transition Point Locations + helpers.each(this.getDataset().metaData, function(point, index) { + point.transition(easingDecimal); + }); + + // Transition and Draw the line + this.getDataset().metaDataset.transition(easingDecimal).draw(); + + // Draw the points + helpers.each(this.getDataset().metaData, function(point) { + point.draw(); + }); + }, + + setHoverStyle: function(point) { + // Point + var dataset = this.chart.data.datasets[point._datasetIndex]; + var index = point._index; + + point._model.radius = point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius); + point._model.backgroundColor = point.custom && point.custom.hoverBackgroundColor ? point.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(point._model.backgroundColor).saturate(0.5).darken(0.1).rgbString()); + point._model.borderColor = point.custom && point.custom.hoverBorderColor ? point.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(point._model.borderColor).saturate(0.5).darken(0.1).rgbString()); + point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, point._model.borderWidth); + }, + + removeHoverStyle: function(point) { + var dataset = this.chart.data.datasets[point._datasetIndex]; + var index = point._index; + + point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius); + point._model.backgroundColor = point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor); + point._model.borderColor = point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor); + point._model.borderWidth = point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth); + } + }); +}; +},{}],21:[function(require,module,exports){ +/*global window: false */ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.global.animation = { + duration: 1000, + easing: "easeOutQuart", + onProgress: helpers.noop, + onComplete: helpers.noop + }; + + Chart.Animation = Chart.Element.extend({ + currentStep: null, // the current animation step + numSteps: 60, // default number of steps + easing: "", // the easing to use for this animation + render: null, // render function used by the animation service + + onAnimationProgress: null, // user specified callback to fire on each step of the animation + onAnimationComplete: null // user specified callback to fire when the animation finishes + }); + + Chart.animationService = { + frameDuration: 17, + animations: [], + dropFrames: 0, + addAnimation: function(chartInstance, animationObject, duration, lazy) { + + if (!lazy) { + chartInstance.animating = true; + } + + for (var index = 0; index < this.animations.length; ++index) { + if (this.animations[index].chartInstance === chartInstance) { + // replacing an in progress animation + this.animations[index].animationObject = animationObject; + return; + } + } + + this.animations.push({ + chartInstance: chartInstance, + animationObject: animationObject + }); + + // If there are no animations queued, manually kickstart a digest, for lack of a better word + if (this.animations.length === 1) { + helpers.requestAnimFrame.call(window, this.digestWrapper); + } + }, + // Cancel the animation for a given chart instance + cancelAnimation: function(chartInstance) { + var index = helpers.findIndex(this.animations, function(animationWrapper) { + return animationWrapper.chartInstance === chartInstance; + }); + + if (index !== -1) { + this.animations.splice(index, 1); + chartInstance.animating = false; + } + }, + // calls startDigest with the proper context + digestWrapper: function() { + Chart.animationService.startDigest.call(Chart.animationService); + }, + startDigest: function() { + + var startTime = Date.now(); + var framesToDrop = 0; + + if (this.dropFrames > 1) { + framesToDrop = Math.floor(this.dropFrames); + this.dropFrames = this.dropFrames % 1; + } + + var i = 0; + while (i < this.animations.length) { + if (this.animations[i].animationObject.currentStep === null) { + this.animations[i].animationObject.currentStep = 0; + } + + this.animations[i].animationObject.currentStep += 1 + framesToDrop; + + if (this.animations[i].animationObject.currentStep > this.animations[i].animationObject.numSteps) { + this.animations[i].animationObject.currentStep = this.animations[i].animationObject.numSteps; + } + + this.animations[i].animationObject.render(this.animations[i].chartInstance, this.animations[i].animationObject); + if (this.animations[i].animationObject.onAnimationProgress && this.animations[i].animationObject.onAnimationProgress.call) { + this.animations[i].animationObject.onAnimationProgress.call(this.animations[i].chartInstance, this.animations[i]); + } + + if (this.animations[i].animationObject.currentStep === this.animations[i].animationObject.numSteps) { + if (this.animations[i].animationObject.onAnimationComplete && this.animations[i].animationObject.onAnimationComplete.call) { + this.animations[i].animationObject.onAnimationComplete.call(this.animations[i].chartInstance, this.animations[i]); + } + + // executed the last frame. Remove the animation. + this.animations[i].chartInstance.animating = false; + + this.animations.splice(i, 1); + } else { + ++i; + } + } + + var endTime = Date.now(); + var dropFrames = (endTime - startTime) / this.frameDuration; + + this.dropFrames += dropFrames; + + // Do we have more stuff to animate? + if (this.animations.length > 0) { + helpers.requestAnimFrame.call(window, this.digestWrapper); + } + } + }; +}; +},{}],22:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + //Create a dictionary of chart types, to allow for extension of existing types + Chart.types = {}; + + //Store a reference to each instance - allowing us to globally resize chart instances on window resize. + //Destroy method on the chart will remove the instance of the chart from this reference. + Chart.instances = {}; + + // Controllers available for dataset visualization eg. bar, line, slice, etc. + Chart.controllers = {}; + + // The main controller of a chart + Chart.Controller = function(instance) { + + this.chart = instance; + this.config = instance.config; + this.options = this.config.options = helpers.configMerge(Chart.defaults.global, Chart.defaults[this.config.type], this.config.options || {}); + this.id = helpers.uid(); + + Object.defineProperty(this, 'data', { + get: function() { + return this.config.data; + } + }); + + //Add the chart instance to the global namespace + Chart.instances[this.id] = this; + + if (this.options.responsive) { + // Silent resize before chart draws + this.resize(true); + } + + this.initialize(); + + return this; + }; + + helpers.extend(Chart.Controller.prototype, { + + initialize: function initialize() { + + // TODO + // If BeforeInit(this) doesn't return false, proceed + + this.bindEvents(); + + // Make sure controllers are built first so that each dataset is bound to an axis before the scales + // are built + this.ensureScalesHaveIDs(); + this.buildOrUpdateControllers(); + this.buildScales(); + this.buildSurroundingItems(); + this.updateLayout(); + this.resetElements(); + this.initToolTip(); + this.update(); + + // TODO + // If AfterInit(this) doesn't return false, proceed + + return this; + }, + + clear: function clear() { + helpers.clear(this.chart); + return this; + }, + + stop: function stop() { + // Stops any current animation loop occuring + Chart.animationService.cancelAnimation(this); + return this; + }, + + resize: function resize(silent) { + var canvas = this.chart.canvas; + var newWidth = helpers.getMaximumWidth(this.chart.canvas); + var newHeight = (this.options.maintainAspectRatio && isNaN(this.chart.aspectRatio) === false && isFinite(this.chart.aspectRatio) && this.chart.aspectRatio !== 0) ? newWidth / this.chart.aspectRatio : helpers.getMaximumHeight(this.chart.canvas); + + var sizeChanged = this.chart.width !== newWidth || this.chart.height !== newHeight; + + if (!sizeChanged) + return this; + + canvas.width = this.chart.width = newWidth; + canvas.height = this.chart.height = newHeight; + + helpers.retinaScale(this.chart); + + if (!silent) { + this.stop(); + this.update(this.options.responsiveAnimationDuration); + } + + return this; + }, + ensureScalesHaveIDs: function ensureScalesHaveIDs() { + var defaultXAxisID = 'x-axis-'; + var defaultYAxisID = 'y-axis-'; + + if (this.options.scales) { + if (this.options.scales.xAxes && this.options.scales.xAxes.length) { + helpers.each(this.options.scales.xAxes, function(xAxisOptions, index) { + xAxisOptions.id = xAxisOptions.id || (defaultXAxisID + index); + }); + } + + if (this.options.scales.yAxes && this.options.scales.yAxes.length) { + // Build the y axes + helpers.each(this.options.scales.yAxes, function(yAxisOptions, index) { + yAxisOptions.id = yAxisOptions.id || (defaultYAxisID + index); + }); + } + } + }, + buildScales: function buildScales() { + // Map of scale ID to scale object so we can lookup later + this.scales = {}; + + // Build the x axes + if (this.options.scales) { + if (this.options.scales.xAxes && this.options.scales.xAxes.length) { + helpers.each(this.options.scales.xAxes, function(xAxisOptions, index) { + var xType = helpers.getValueOrDefault(xAxisOptions.type, 'category'); + var ScaleClass = Chart.scaleService.getScaleConstructor(xType); + if (ScaleClass) { + var scale = new ScaleClass({ + ctx: this.chart.ctx, + options: xAxisOptions, + chart: this, + id: xAxisOptions.id + }); + + this.scales[scale.id] = scale; + } + }, this); + } + + if (this.options.scales.yAxes && this.options.scales.yAxes.length) { + // Build the y axes + helpers.each(this.options.scales.yAxes, function(yAxisOptions, index) { + var yType = helpers.getValueOrDefault(yAxisOptions.type, 'linear'); + var ScaleClass = Chart.scaleService.getScaleConstructor(yType); + if (ScaleClass) { + var scale = new ScaleClass({ + ctx: this.chart.ctx, + options: yAxisOptions, + chart: this, + id: yAxisOptions.id + }); + + this.scales[scale.id] = scale; + } + }, this); + } + } + if (this.options.scale) { + // Build radial axes + var ScaleClass = Chart.scaleService.getScaleConstructor(this.options.scale.type); + if (ScaleClass) { + var scale = new ScaleClass({ + ctx: this.chart.ctx, + options: this.options.scale, + chart: this + }); + + this.scale = scale; + + this.scales.radialScale = scale; + } + } + + Chart.scaleService.addScalesToLayout(this); + }, + + buildSurroundingItems: function() { + if (this.options.title) { + this.titleBlock = new Chart.Title({ + ctx: this.chart.ctx, + options: this.options.title, + chart: this + }); + + Chart.layoutService.addBox(this, this.titleBlock); + } + + if (this.options.legend) { + this.legend = new Chart.Legend({ + ctx: this.chart.ctx, + options: this.options.legend, + chart: this + }); + + Chart.layoutService.addBox(this, this.legend); + } + }, + + updateLayout: function() { + Chart.layoutService.update(this, this.chart.width, this.chart.height); + }, + + buildOrUpdateControllers: function buildOrUpdateControllers() { + var types = []; + var newControllers = []; + + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + if (!dataset.type) { + dataset.type = this.config.type; + } + + var type = dataset.type; + types.push(type); + + if (dataset.controller) { + dataset.controller.updateIndex(datasetIndex); + } else { + dataset.controller = new Chart.controllers[type](this, datasetIndex); + newControllers.push(dataset.controller); + } + }, this); + + if (types.length > 1) { + for (var i = 1; i < types.length; i++) { + if (types[i] !== types[i - 1]) { + this.isCombo = true; + break; + } + } + } + + return newControllers; + }, + + resetElements: function resetElements() { + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + dataset.controller.reset(); + }); + }, + + update: function update(animationDuration, lazy) { + // In case the entire data object changed + this.tooltip._data = this.data; + + // Make sure dataset controllers are updated and new controllers are reset + var newControllers = this.buildOrUpdateControllers(); + + Chart.layoutService.update(this, this.chart.width, this.chart.height); + + // Can only reset the new controllers after the scales have been updated + helpers.each(newControllers, function(controller) { + controller.reset(); + }); + + // Make sure all dataset controllers have correct meta data counts + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + dataset.controller.buildOrUpdateElements(); + }); + + // This will loop through any data and do the appropriate element update for the type + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + dataset.controller.update(); + }); + this.render(animationDuration, lazy); + }, + + render: function render(duration, lazy) { + + if (this.options.animation && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && this.options.animation.duration !== 0))) { + var animation = new Chart.Animation(); + animation.numSteps = (duration || this.options.animation.duration) / 16.66; //60 fps + animation.easing = this.options.animation.easing; + + // render function + animation.render = function(chartInstance, animationObject) { + var easingFunction = helpers.easingEffects[animationObject.easing]; + var stepDecimal = animationObject.currentStep / animationObject.numSteps; + var easeDecimal = easingFunction(stepDecimal); + + chartInstance.draw(easeDecimal, stepDecimal, animationObject.currentStep); + }; + + // user events + animation.onAnimationProgress = this.options.animation.onProgress; + animation.onAnimationComplete = this.options.animation.onComplete; + + Chart.animationService.addAnimation(this, animation, duration, lazy); + } else { + this.draw(); + if (this.options.animation && this.options.animation.onComplete && this.options.animation.onComplete.call) { + this.options.animation.onComplete.call(this); + } + } + return this; + }, + + draw: function(ease) { + var easingDecimal = ease || 1; + this.clear(); + + // Draw all the scales + helpers.each(this.boxes, function(box) { + box.draw(this.chartArea); + }, this); + if (this.scale) { + this.scale.draw(); + } + + // Clip out the chart area so that anything outside does not draw. This is necessary for zoom and pan to function + this.chart.ctx.save(); + this.chart.ctx.beginPath(); + this.chart.ctx.rect(this.chartArea.left, this.chartArea.top, this.chartArea.right - this.chartArea.left, this.chartArea.bottom - this.chartArea.top); + this.chart.ctx.clip(); + + // Draw each dataset via its respective controller (reversed to support proper line stacking) + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + if (helpers.isDatasetVisible(dataset)) { + dataset.controller.draw(ease); + } + }, null, true); + + // Restore from the clipping operation + this.chart.ctx.restore(); + + // Finally draw the tooltip + this.tooltip.transition(easingDecimal).draw(); + }, + + // Get the single element that was clicked on + // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw + getElementAtEvent: function(e) { + + var eventPosition = helpers.getRelativePosition(e, this.chart); + var elementsArray = []; + + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + if (helpers.isDatasetVisible(dataset)) { + helpers.each(dataset.metaData, function(element, index) { + if (element.inRange(eventPosition.x, eventPosition.y)) { + elementsArray.push(element); + return elementsArray; + } + }); + } + }); + + return elementsArray; + }, + + getElementsAtEvent: function(e) { + var eventPosition = helpers.getRelativePosition(e, this.chart); + var elementsArray = []; + + var found = (function() { + if (this.data.datasets) { + for (var i = 0; i < this.data.datasets.length; i++) { + if (helpers.isDatasetVisible(this.data.datasets[i])) { + for (var j = 0; j < this.data.datasets[i].metaData.length; j++) { + if (this.data.datasets[i].metaData[j].inRange(eventPosition.x, eventPosition.y)) { + return this.data.datasets[i].metaData[j]; + } + } + } + } + } + }).call(this); + + if (!found) { + return elementsArray; + } + + helpers.each(this.data.datasets, function(dataset, dsIndex) { + if (helpers.isDatasetVisible(dataset)) { + elementsArray.push(dataset.metaData[found._index]); + } + }); + + return elementsArray; + }, + + getDatasetAtEvent: function(e) { + var elementsArray = this.getElementAtEvent(e); + + if (elementsArray.length > 0) { + elementsArray = this.data.datasets[elementsArray[0]._datasetIndex].metaData; + } + + return elementsArray; + }, + + generateLegend: function generateLegend() { + return this.options.legendCallback(this); + }, + + destroy: function destroy() { + this.clear(); + helpers.unbindEvents(this, this.events); + helpers.removeResizeListener(this.chart.canvas.parentNode); + + // Reset canvas height/width attributes + var canvas = this.chart.canvas; + canvas.width = this.chart.width; + canvas.height = this.chart.height; + + // if we scaled the canvas in response to a devicePixelRatio !== 1, we need to undo that transform here + if (this.chart.originalDevicePixelRatio !== undefined) { + this.chart.ctx.scale(1 / this.chart.originalDevicePixelRatio, 1 / this.chart.originalDevicePixelRatio); + } + + // Reset to the old style since it may have been changed by the device pixel ratio changes + canvas.style.width = this.chart.originalCanvasStyleWidth; + canvas.style.height = this.chart.originalCanvasStyleHeight; + + delete Chart.instances[this.id]; + }, + + toBase64Image: function toBase64Image() { + return this.chart.canvas.toDataURL.apply(this.chart.canvas, arguments); + }, + + initToolTip: function initToolTip() { + this.tooltip = new Chart.Tooltip({ + _chart: this.chart, + _chartInstance: this, + _data: this.data, + _options: this.options + }, this); + }, + + bindEvents: function bindEvents() { + helpers.bindEvents(this, this.options.events, function(evt) { + this.eventHandler(evt); + }); + }, + eventHandler: function eventHandler(e) { + this.lastActive = this.lastActive || []; + this.lastTooltipActive = this.lastTooltipActive || []; + + // Find Active Elements for hover and tooltips + if (e.type === 'mouseout') { + this.active = []; + this.tooltipActive = []; + } else { + + var _this = this; + var getItemsForMode = function(mode) { + switch (mode) { + case 'single': + return _this.getElementAtEvent(e); + case 'label': + return _this.getElementsAtEvent(e); + case 'dataset': + return _this.getDatasetAtEvent(e); + default: + return e; + } + }; + + this.active = getItemsForMode(this.options.hover.mode); + this.tooltipActive = getItemsForMode(this.options.tooltips.mode); + } + + // On Hover hook + if (this.options.hover.onHover) { + this.options.hover.onHover.call(this, this.active); + } + + if (e.type === 'mouseup' || e.type === 'click') { + if (this.options.onClick) { + this.options.onClick.call(this, e, this.active); + } + + if (this.legend && this.legend.handleEvent) { + this.legend.handleEvent(e); + } + } + + var dataset; + var index; + + // Remove styling for last active (even if it may still be active) + if (this.lastActive.length) { + switch (this.options.hover.mode) { + case 'single': + this.data.datasets[this.lastActive[0]._datasetIndex].controller.removeHoverStyle(this.lastActive[0], this.lastActive[0]._datasetIndex, this.lastActive[0]._index); + break; + case 'label': + case 'dataset': + for (var i = 0; i < this.lastActive.length; i++) { + if (this.lastActive[i]) + this.data.datasets[this.lastActive[i]._datasetIndex].controller.removeHoverStyle(this.lastActive[i], this.lastActive[i]._datasetIndex, this.lastActive[i]._index); + } + break; + default: + // Don't change anything + } + } + + // Built in hover styling + if (this.active.length && this.options.hover.mode) { + switch (this.options.hover.mode) { + case 'single': + this.data.datasets[this.active[0]._datasetIndex].controller.setHoverStyle(this.active[0]); + break; + case 'label': + case 'dataset': + for (var j = 0; j < this.active.length; j++) { + if (this.active[j]) + this.data.datasets[this.active[j]._datasetIndex].controller.setHoverStyle(this.active[j]); + } + break; + default: + // Don't change anything + } + } + + + // Built in Tooltips + if (this.options.tooltips.enabled || this.options.tooltips.custom) { + + // The usual updates + this.tooltip.initialize(); + this.tooltip._active = this.tooltipActive; + this.tooltip.update(); + } + + // Hover animations + this.tooltip.pivot(); + + if (!this.animating) { + var changed; + + helpers.each(this.active, function(element, index) { + if (element !== this.lastActive[index]) { + changed = true; + } + }, this); + + helpers.each(this.tooltipActive, function(element, index) { + if (element !== this.lastTooltipActive[index]) { + changed = true; + } + }, this); + + // If entering, leaving, or changing elements, animate the change via pivot + if ((this.lastActive.length !== this.active.length) || + (this.lastTooltipActive.length !== this.tooltipActive.length) || + changed) { + + this.stop(); + + if (this.options.tooltips.enabled || this.options.tooltips.custom) { + this.tooltip.update(true); + } + + // We only need to render at this point. Updating will cause scales to be recomputed generating flicker & using more + // memory than necessary. + this.render(this.options.hover.animationDuration, true); + } + } + + // Remember Last Actives + this.lastActive = this.active; + this.lastTooltipActive = this.tooltipActive; + return this; + } + }); +}; + +},{}],23:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + // Base class for all dataset controllers (line, bar, etc) + Chart.DatasetController = function(chart, datasetIndex) { + this.initialize.call(this, chart, datasetIndex); + }; + + helpers.extend(Chart.DatasetController.prototype, { + initialize: function(chart, datasetIndex) { + this.chart = chart; + this.index = datasetIndex; + this.linkScales(); + this.addElements(); + }, + updateIndex: function(datasetIndex) { + this.index = datasetIndex; + }, + + linkScales: function() { + if (!this.getDataset().xAxisID) { + this.getDataset().xAxisID = this.chart.options.scales.xAxes[0].id; + } + + if (!this.getDataset().yAxisID) { + this.getDataset().yAxisID = this.chart.options.scales.yAxes[0].id; + } + }, + + getDataset: function() { + return this.chart.data.datasets[this.index]; + }, + + getScaleForId: function(scaleID) { + return this.chart.scales[scaleID]; + }, + + reset: function() { + this.update(true); + }, + + buildOrUpdateElements: function buildOrUpdateElements() { + // Handle the number of data points changing + var numData = this.getDataset().data.length; + var numMetaData = this.getDataset().metaData.length; + + // Make sure that we handle number of datapoints changing + if (numData < numMetaData) { + // Remove excess bars for data points that have been removed + this.getDataset().metaData.splice(numData, numMetaData - numData); + } else if (numData > numMetaData) { + // Add new elements + for (var index = numMetaData; index < numData; ++index) { + this.addElementAndReset(index); + } + } + }, + + // Controllers should implement the following + addElements: helpers.noop, + addElementAndReset: helpers.noop, + draw: helpers.noop, + removeHoverStyle: helpers.noop, + setHoverStyle: helpers.noop, + update: helpers.noop + }); + + Chart.DatasetController.extend = helpers.inherits; + +}; +},{}],24:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.elements = {}; + + Chart.Element = function(configuration) { + helpers.extend(this, configuration); + this.initialize.apply(this, arguments); + }; + helpers.extend(Chart.Element.prototype, { + initialize: function() {}, + pivot: function() { + if (!this._view) { + this._view = helpers.clone(this._model); + } + this._start = helpers.clone(this._view); + return this; + }, + transition: function(ease) { + if (!this._view) { + this._view = helpers.clone(this._model); + } + + // No animation -> No Transition + if (ease === 1) { + this._view = this._model; + this._start = null; + return this; + } + + if (!this._start) { + this.pivot(); + } + + helpers.each(this._model, function(value, key) { + + if (key[0] === '_' || !this._model.hasOwnProperty(key)) { + // Only non-underscored properties + } + + // Init if doesn't exist + else if (!this._view.hasOwnProperty(key)) { + if (typeof value === 'number' && !isNaN(this._view[key])) { + this._view[key] = value * ease; + } else { + this._view[key] = value; + } + } + + // No unnecessary computations + else if (value === this._view[key]) { + // It's the same! Woohoo! + } + + // Color transitions if possible + else if (typeof value === 'string') { + try { + var color = helpers.color(this._start[key]).mix(helpers.color(this._model[key]), ease); + this._view[key] = color.rgbString(); + } catch (err) { + this._view[key] = value; + } + } + // Number transitions + else if (typeof value === 'number') { + var startVal = this._start[key] !== undefined && isNaN(this._start[key]) === false ? this._start[key] : 0; + this._view[key] = ((this._model[key] - startVal) * ease) + startVal; + } + // Everything else + else { + this._view[key] = value; + } + }, this); + + return this; + }, + tooltipPosition: function() { + return { + x: this._model.x, + y: this._model.y + }; + }, + hasValue: function() { + return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y); + } + }); + + Chart.Element.extend = helpers.inherits; + +}; + +},{}],25:[function(require,module,exports){ +/*global window: false */ +/*global document: false */ +"use strict"; + +var color = require('chartjs-color'); + +module.exports = function(Chart) { + + //Global Chart helpers object for utility methods and classes + var helpers = Chart.helpers = {}; + + //-- Basic js utility methods + helpers.each = function(loopable, callback, self, reverse) { + // Check to see if null or undefined firstly. + var i, len; + if (helpers.isArray(loopable)) { + len = loopable.length; + if (reverse) { + for (i = len - 1; i >= 0; i--) { + callback.call(self, loopable[i], i); + } + } else { + for (i = 0; i < len; i++) { + callback.call(self, loopable[i], i); + } + } + } else if (typeof loopable === 'object') { + var keys = Object.keys(loopable); + len = keys.length; + for (i = 0; i < len; i++) { + callback.call(self, loopable[keys[i]], keys[i]); + } + } + }; + helpers.clone = function(obj) { + var objClone = {}; + helpers.each(obj, function(value, key) { + if (obj.hasOwnProperty(key)) { + if (helpers.isArray(value)) { + objClone[key] = value.slice(0); + } else if (typeof value === 'object' && value !== null) { + objClone[key] = helpers.clone(value); + } else { + objClone[key] = value; + } + } + }); + return objClone; + }; + helpers.extend = function(base) { + var len = arguments.length; + var additionalArgs = []; + for (var i = 1; i < len; i++) { + additionalArgs.push(arguments[i]); + } + helpers.each(additionalArgs, function(extensionObject) { + helpers.each(extensionObject, function(value, key) { + if (extensionObject.hasOwnProperty(key)) { + base[key] = value; + } + }); + }); + return base; + }; + // Need a special merge function to chart configs since they are now grouped + helpers.configMerge = function(_base) { + var base = helpers.clone(_base); + helpers.each(Array.prototype.slice.call(arguments, 1), function(extension) { + helpers.each(extension, function(value, key) { + if (extension.hasOwnProperty(key)) { + if (key === 'scales') { + // Scale config merging is complex. Add out own function here for that + base[key] = helpers.scaleMerge(base.hasOwnProperty(key) ? base[key] : {}, value); + + } else if (key === 'scale') { + // Used in polar area & radar charts since there is only one scale + base[key] = helpers.configMerge(base.hasOwnProperty(key) ? base[key] : {}, Chart.scaleService.getScaleDefaults(value.type), value); + } else if (base.hasOwnProperty(key) && helpers.isArray(base[key]) && helpers.isArray(value)) { + // In this case we have an array of objects replacing another array. Rather than doing a strict replace, + // merge. This allows easy scale option merging + var baseArray = base[key]; + + helpers.each(value, function(valueObj, index) { + + if (index < baseArray.length) { + if (typeof baseArray[index] === 'object' && baseArray[index] !== null && typeof valueObj === 'object' && valueObj !== null) { + // Two objects are coming together. Do a merge of them. + baseArray[index] = helpers.configMerge(baseArray[index], valueObj); + } else { + // Just overwrite in this case since there is nothing to merge + baseArray[index] = valueObj; + } + } else { + baseArray.push(valueObj); // nothing to merge + } + }); + + } else if (base.hasOwnProperty(key) && typeof base[key] === "object" && base[key] !== null && typeof value === "object") { + // If we are overwriting an object with an object, do a merge of the properties. + base[key] = helpers.configMerge(base[key], value); + + } else { + // can just overwrite the value in this case + base[key] = value; + } + } + }); + }); + + return base; + }; + helpers.extendDeep = function(_base) { + return _extendDeep.apply(this, arguments); + + function _extendDeep(dst) { + helpers.each(arguments, function(obj) { + if (obj !== dst) { + helpers.each(obj, function(value, key) { + if (dst[key] && dst[key].constructor && dst[key].constructor === Object) { + _extendDeep(dst[key], value); + } else { + dst[key] = value; + } + }); + } + }); + return dst; + } + }; + helpers.scaleMerge = function(_base, extension) { + var base = helpers.clone(_base); + + helpers.each(extension, function(value, key) { + if (extension.hasOwnProperty(key)) { + if (key === 'xAxes' || key === 'yAxes') { + // These properties are arrays of items + if (base.hasOwnProperty(key)) { + helpers.each(value, function(valueObj, index) { + var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear'); + var axisDefaults = Chart.scaleService.getScaleDefaults(axisType); + if (index >= base[key].length || !base[key][index].type) { + base[key].push(helpers.configMerge(axisDefaults, valueObj)); + } else if (valueObj.type && valueObj.type !== base[key][index].type) { + // Type changed. Bring in the new defaults before we bring in valueObj so that valueObj can override the correct scale defaults + base[key][index] = helpers.configMerge(base[key][index], axisDefaults, valueObj); + } else { + // Type is the same + base[key][index] = helpers.configMerge(base[key][index], valueObj); + } + }); + } else { + base[key] = []; + helpers.each(value, function(valueObj) { + var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear'); + base[key].push(helpers.configMerge(Chart.scaleService.getScaleDefaults(axisType), valueObj)); + }); + } + } else if (base.hasOwnProperty(key) && typeof base[key] === "object" && base[key] !== null && typeof value === "object") { + // If we are overwriting an object with an object, do a merge of the properties. + base[key] = helpers.configMerge(base[key], value); + + } else { + // can just overwrite the value in this case + base[key] = value; + } + } + }); + + return base; + }; + helpers.getValueAtIndexOrDefault = function(value, index, defaultValue) { + if (value === undefined || value === null) { + return defaultValue; + } + + if (helpers.isArray(value)) { + return index < value.length ? value[index] : defaultValue; + } + + return value; + }; + helpers.getValueOrDefault = function(value, defaultValue) { + return value === undefined ? defaultValue : value; + }; + helpers.indexOf = function(arrayToSearch, item) { + if (Array.prototype.indexOf) { + return arrayToSearch.indexOf(item); + } else { + for (var i = 0; i < arrayToSearch.length; i++) { + if (arrayToSearch[i] === item) + return i; + } + return -1; + } + }; + helpers.where = function(collection, filterCallback) { + var filtered = []; + + helpers.each(collection, function(item) { + if (filterCallback(item)) { + filtered.push(item); + } + }); + + return filtered; + }; + helpers.findIndex = function(arrayToSearch, callback, thisArg) { + var index = -1; + if (Array.prototype.findIndex) { + index = arrayToSearch.findIndex(callback, thisArg); + } else { + for (var i = 0; i < arrayToSearch.length; ++i) { + thisArg = thisArg !== undefined ? thisArg : arrayToSearch; + + if (callback.call(thisArg, arrayToSearch[i], i, arrayToSearch)) { + index = i; + break; + } + } + } + + return index; + }; + helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) { + // Default to start of the array + if (startIndex === undefined || startIndex === null) { + startIndex = -1; + } + for (var i = startIndex + 1; i < arrayToSearch.length; i++) { + var currentItem = arrayToSearch[i]; + if (filterCallback(currentItem)) { + return currentItem; + } + } + }; + helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) { + // Default to end of the array + if (startIndex === undefined || startIndex === null) { + startIndex = arrayToSearch.length; + } + for (var i = startIndex - 1; i >= 0; i--) { + var currentItem = arrayToSearch[i]; + if (filterCallback(currentItem)) { + return currentItem; + } + } + }; + helpers.inherits = function(extensions) { + //Basic javascript inheritance based on the model created in Backbone.js + var parent = this; + var ChartElement = (extensions && extensions.hasOwnProperty("constructor")) ? extensions.constructor : function() { + return parent.apply(this, arguments); + }; + + var Surrogate = function() { + this.constructor = ChartElement; + }; + Surrogate.prototype = parent.prototype; + ChartElement.prototype = new Surrogate(); + + ChartElement.extend = helpers.inherits; + + if (extensions) { + helpers.extend(ChartElement.prototype, extensions); + } + + ChartElement.__super__ = parent.prototype; + + return ChartElement; + }; + helpers.noop = function() {}; + helpers.uid = (function() { + var id = 0; + return function() { + return "chart-" + id++; + }; + })(); + helpers.warn = function(str) { + //Method for warning of errors + if (console && typeof console.warn === "function") { + console.warn(str); + } + }; + //-- Math methods + helpers.isNumber = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + helpers.almostEquals = function(x, y, epsilon) { + return Math.abs(x - y) < epsilon; + }; + helpers.max = function(array) { + return array.reduce(function(max, value) { + if (!isNaN(value)) { + return Math.max(max, value); + } else { + return max; + } + }, Number.NEGATIVE_INFINITY); + }; + helpers.min = function(array) { + return array.reduce(function(min, value) { + if (!isNaN(value)) { + return Math.min(min, value); + } else { + return min; + } + }, Number.POSITIVE_INFINITY); + }; + helpers.sign = function(x) { + if (Math.sign) { + return Math.sign(x); + } else { + x = +x; // convert to a number + if (x === 0 || isNaN(x)) { + return x; + } + return x > 0 ? 1 : -1; + } + }; + helpers.log10 = function(x) { + if (Math.log10) { + return Math.log10(x); + } else { + return Math.log(x) / Math.LN10; + } + }; + helpers.toRadians = function(degrees) { + return degrees * (Math.PI / 180); + }; + helpers.toDegrees = function(radians) { + return radians * (180 / Math.PI); + }; + // Gets the angle from vertical upright to the point about a centre. + helpers.getAngleFromPoint = function(centrePoint, anglePoint) { + var distanceFromXCenter = anglePoint.x - centrePoint.x, + distanceFromYCenter = anglePoint.y - centrePoint.y, + radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); + + var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); + + if (angle < (-0.5 * Math.PI)) { + angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2] + } + + return { + angle: angle, + distance: radialDistanceFromCenter + }; + }; + helpers.aliasPixel = function(pixelWidth) { + return (pixelWidth % 2 === 0) ? 0 : 0.5; + }; + helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) { + //Props to Rob Spencer at scaled innovation for his post on splining between points + //http://scaledinnovation.com/analytics/splines/aboutSplines.html + + // This function must also respect "skipped" points + + var previous = firstPoint.skip ? middlePoint : firstPoint, + current = middlePoint, + next = afterPoint.skip ? middlePoint : afterPoint; + + var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2)); + var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2)); + + var s01 = d01 / (d01 + d12); + var s12 = d12 / (d01 + d12); + + // If all points are the same, s01 & s02 will be inf + s01 = isNaN(s01) ? 0 : s01; + s12 = isNaN(s12) ? 0 : s12; + + var fa = t * s01; // scaling factor for triangle Ta + var fb = t * s12; + + return { + previous: { + x: current.x - fa * (next.x - previous.x), + y: current.y - fa * (next.y - previous.y) + }, + next: { + x: current.x + fb * (next.x - previous.x), + y: current.y + fb * (next.y - previous.y) + } + }; + }; + helpers.nextItem = function(collection, index, loop) { + if (loop) { + return index >= collection.length - 1 ? collection[0] : collection[index + 1]; + } + + return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1]; + }; + helpers.previousItem = function(collection, index, loop) { + if (loop) { + return index <= 0 ? collection[collection.length - 1] : collection[index - 1]; + } + return index <= 0 ? collection[0] : collection[index - 1]; + }; + // Implementation of the nice number algorithm used in determining where axis labels will go + helpers.niceNum = function(range, round) { + var exponent = Math.floor(helpers.log10(range)); + var fraction = range / Math.pow(10, exponent); + var niceFraction; + + if (round) { + if (fraction < 1.5) { + niceFraction = 1; + } else if (fraction < 3) { + niceFraction = 2; + } else if (fraction < 7) { + niceFraction = 5; + } else { + niceFraction = 10; + } + } else { + if (fraction <= 1.0) { + niceFraction = 1; + } else if (fraction <= 2) { + niceFraction = 2; + } else if (fraction <= 5) { + niceFraction = 5; + } else { + niceFraction = 10; + } + } + + return niceFraction * Math.pow(10, exponent); + }; + //Easing functions adapted from Robert Penner's easing equations + //http://www.robertpenner.com/easing/ + var easingEffects = helpers.easingEffects = { + linear: function(t) { + return t; + }, + easeInQuad: function(t) { + return t * t; + }, + easeOutQuad: function(t) { + return -1 * t * (t - 2); + }, + easeInOutQuad: function(t) { + if ((t /= 1 / 2) < 1) { + return 1 / 2 * t * t; + } + return -1 / 2 * ((--t) * (t - 2) - 1); + }, + easeInCubic: function(t) { + return t * t * t; + }, + easeOutCubic: function(t) { + return 1 * ((t = t / 1 - 1) * t * t + 1); + }, + easeInOutCubic: function(t) { + if ((t /= 1 / 2) < 1) { + return 1 / 2 * t * t * t; + } + return 1 / 2 * ((t -= 2) * t * t + 2); + }, + easeInQuart: function(t) { + return t * t * t * t; + }, + easeOutQuart: function(t) { + return -1 * ((t = t / 1 - 1) * t * t * t - 1); + }, + easeInOutQuart: function(t) { + if ((t /= 1 / 2) < 1) { + return 1 / 2 * t * t * t * t; + } + return -1 / 2 * ((t -= 2) * t * t * t - 2); + }, + easeInQuint: function(t) { + return 1 * (t /= 1) * t * t * t * t; + }, + easeOutQuint: function(t) { + return 1 * ((t = t / 1 - 1) * t * t * t * t + 1); + }, + easeInOutQuint: function(t) { + if ((t /= 1 / 2) < 1) { + return 1 / 2 * t * t * t * t * t; + } + return 1 / 2 * ((t -= 2) * t * t * t * t + 2); + }, + easeInSine: function(t) { + return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1; + }, + easeOutSine: function(t) { + return 1 * Math.sin(t / 1 * (Math.PI / 2)); + }, + easeInOutSine: function(t) { + return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1); + }, + easeInExpo: function(t) { + return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1)); + }, + easeOutExpo: function(t) { + return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1); + }, + easeInOutExpo: function(t) { + if (t === 0) { + return 0; + } + if (t === 1) { + return 1; + } + if ((t /= 1 / 2) < 1) { + return 1 / 2 * Math.pow(2, 10 * (t - 1)); + } + return 1 / 2 * (-Math.pow(2, -10 * --t) + 2); + }, + easeInCirc: function(t) { + if (t >= 1) { + return t; + } + return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1); + }, + easeOutCirc: function(t) { + return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t); + }, + easeInOutCirc: function(t) { + if ((t /= 1 / 2) < 1) { + return -1 / 2 * (Math.sqrt(1 - t * t) - 1); + } + return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1); + }, + easeInElastic: function(t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) { + return 0; + } + if ((t /= 1) === 1) { + return 1; + } + if (!p) { + p = 1 * 0.3; + } + if (a < Math.abs(1)) { + a = 1; + s = p / 4; + } else { + s = p / (2 * Math.PI) * Math.asin(1 / a); + } + return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)); + }, + easeOutElastic: function(t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) { + return 0; + } + if ((t /= 1) === 1) { + return 1; + } + if (!p) { + p = 1 * 0.3; + } + if (a < Math.abs(1)) { + a = 1; + s = p / 4; + } else { + s = p / (2 * Math.PI) * Math.asin(1 / a); + } + return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1; + }, + easeInOutElastic: function(t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) { + return 0; + } + if ((t /= 1 / 2) === 2) { + return 1; + } + if (!p) { + p = 1 * (0.3 * 1.5); + } + if (a < Math.abs(1)) { + a = 1; + s = p / 4; + } else { + s = p / (2 * Math.PI) * Math.asin(1 / a); + } + if (t < 1) { + return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)); + } + return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1; + }, + easeInBack: function(t) { + var s = 1.70158; + return 1 * (t /= 1) * t * ((s + 1) * t - s); + }, + easeOutBack: function(t) { + var s = 1.70158; + return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1); + }, + easeInOutBack: function(t) { + var s = 1.70158; + if ((t /= 1 / 2) < 1) { + return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)); + } + return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); + }, + easeInBounce: function(t) { + return 1 - easingEffects.easeOutBounce(1 - t); + }, + easeOutBounce: function(t) { + if ((t /= 1) < (1 / 2.75)) { + return 1 * (7.5625 * t * t); + } else if (t < (2 / 2.75)) { + return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75); + } else if (t < (2.5 / 2.75)) { + return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375); + } else { + return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375); + } + }, + easeInOutBounce: function(t) { + if (t < 1 / 2) { + return easingEffects.easeInBounce(t * 2) * 0.5; + } + return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5; + } + }; + //Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ + helpers.requestAnimFrame = (function() { + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback) { + return window.setTimeout(callback, 1000 / 60); + }; + })(); + helpers.cancelAnimFrame = (function() { + return window.cancelAnimationFrame || + window.webkitCancelAnimationFrame || + window.mozCancelAnimationFrame || + window.oCancelAnimationFrame || + window.msCancelAnimationFrame || + function(callback) { + return window.clearTimeout(callback, 1000 / 60); + }; + })(); + //-- DOM methods + helpers.getRelativePosition = function(evt, chart) { + var mouseX, mouseY; + var e = evt.originalEvent || evt, + canvas = evt.currentTarget || evt.srcElement, + boundingRect = canvas.getBoundingClientRect(); + + if (e.touches && e.touches.length > 0) { + mouseX = e.touches[0].clientX; + mouseY = e.touches[0].clientY; + + } else { + mouseX = e.clientX; + mouseY = e.clientY; + } + + // Scale mouse coordinates into canvas coordinates + // by following the pattern laid out by 'jerryj' in the comments of + // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/ + var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left')); + var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top')); + var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right')); + var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom')); + var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight; + var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom; + + // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However + // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here + mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio); + mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio); + + return { + x: mouseX, + y: mouseY + }; + + }; + helpers.addEvent = function(node, eventType, method) { + if (node.addEventListener) { + node.addEventListener(eventType, method); + } else if (node.attachEvent) { + node.attachEvent("on" + eventType, method); + } else { + node["on" + eventType] = method; + } + }; + helpers.removeEvent = function(node, eventType, handler) { + if (node.removeEventListener) { + node.removeEventListener(eventType, handler, false); + } else if (node.detachEvent) { + node.detachEvent("on" + eventType, handler); + } else { + node["on" + eventType] = helpers.noop; + } + }; + helpers.bindEvents = function(chartInstance, arrayOfEvents, handler) { + // Create the events object if it's not already present + if (!chartInstance.events) + chartInstance.events = {}; + + helpers.each(arrayOfEvents, function(eventName) { + chartInstance.events[eventName] = function() { + handler.apply(chartInstance, arguments); + }; + helpers.addEvent(chartInstance.chart.canvas, eventName, chartInstance.events[eventName]); + }); + }; + helpers.unbindEvents = function(chartInstance, arrayOfEvents) { + helpers.each(arrayOfEvents, function(handler, eventName) { + helpers.removeEvent(chartInstance.chart.canvas, eventName, handler); + }); + }; + + // Private helper function to convert max-width/max-height values that may be percentages into a number + function parseMaxStyle(styleValue, node, parentProperty) { + var valueInPixels; + if (typeof(styleValue) === 'string') { + valueInPixels = parseInt(styleValue, 10); + + if (styleValue.indexOf('%') != -1) { + // percentage * size in dimension + valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; + } + } else { + valueInPixels = styleValue; + } + + return valueInPixels; + } + + // Private helper to get a constraint dimension + // @param domNode : the node to check the constraint on + // @param maxStyle : the style that defines the maximum for the direction we are using (max-width / max-height) + // @param percentageProperty : property of parent to use when calculating width as a percentage + function getConstraintDimension(domNode, maxStyle, percentageProperty) { + var constrainedDimension; + var constrainedNode = document.defaultView.getComputedStyle(domNode)[maxStyle]; + var constrainedContainer = document.defaultView.getComputedStyle(domNode.parentNode)[maxStyle]; + var hasCNode = constrainedNode !== null && constrainedNode !== "none"; + var hasCContainer = constrainedContainer !== null && constrainedContainer !== "none"; + + if (hasCNode || hasCContainer) { + constrainedDimension = Math.min((hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : Number.POSITIVE_INFINITY), (hasCContainer ? parseMaxStyle(constrainedContainer, domNode.parentNode, percentageProperty) : Number.POSITIVE_INFINITY)); + } + return constrainedDimension; + } + // returns Number or undefined if no constraint + helpers.getConstraintWidth = function(domNode) { + return getConstraintDimension(domNode, 'max-width', 'clientWidth'); + }; + // returns Number or undefined if no constraint + helpers.getConstraintHeight = function(domNode) { + return getConstraintDimension(domNode, 'max-height', 'clientHeight'); + }; + helpers.getMaximumWidth = function(domNode) { + var container = domNode.parentNode; + var padding = parseInt(helpers.getStyle(container, 'padding-left')) + parseInt(helpers.getStyle(container, 'padding-right')); + + var w = container.clientWidth - padding; + var cw = helpers.getConstraintWidth(domNode); + if (cw !== undefined) { + w = Math.min(w, cw); + } + + return w; + }; + helpers.getMaximumHeight = function(domNode) { + var container = domNode.parentNode; + var padding = parseInt(helpers.getStyle(container, 'padding-top')) + parseInt(helpers.getStyle(container, 'padding-bottom')); + + var h = container.clientHeight - padding; + var ch = helpers.getConstraintHeight(domNode); + if (ch !== undefined) { + h = Math.min(h, ch); + } + + return h; + }; + helpers.getStyle = function(el, property) { + return el.currentStyle ? + el.currentStyle[property] : + document.defaultView.getComputedStyle(el, null).getPropertyValue(property); + }; + helpers.retinaScale = function(chart) { + var ctx = chart.ctx; + var width = chart.canvas.width; + var height = chart.canvas.height; + var pixelRatio = chart.currentDevicePixelRatio = window.devicePixelRatio || 1; + + if (pixelRatio !== 1) { + ctx.canvas.height = height * pixelRatio; + ctx.canvas.width = width * pixelRatio; + ctx.scale(pixelRatio, pixelRatio); + + // Store the device pixel ratio so that we can go backwards in `destroy`. + // The devicePixelRatio changes with zoom, so there are no guarantees that it is the same + // when destroy is called + chart.originalDevicePixelRatio = chart.originalDevicePixelRatio || pixelRatio; + } + + ctx.canvas.style.width = width + 'px'; + ctx.canvas.style.height = height + 'px'; + }; + //-- Canvas methods + helpers.clear = function(chart) { + chart.ctx.clearRect(0, 0, chart.width, chart.height); + }; + helpers.fontString = function(pixelSize, fontStyle, fontFamily) { + return fontStyle + " " + pixelSize + "px " + fontFamily; + }; + helpers.longestText = function(ctx, font, arrayOfStrings, cache) { + cache = cache || {}; + cache.data = cache.data || {}; + cache.garbageCollect = cache.garbageCollect || []; + + if (cache.font !== font) { + cache.data = {}; + cache.garbageCollect = []; + cache.font = font; + } + + ctx.font = font; + var longest = 0; + helpers.each(arrayOfStrings, function(string) { + var textWidth = cache.data[string]; + if (!textWidth) { + textWidth = cache.data[string] = ctx.measureText(string).width; + cache.garbageCollect.push(string); + } + if (textWidth > longest) + longest = textWidth; + }); + + var gcLen = cache.garbageCollect.length / 2; + if (gcLen > arrayOfStrings.length) { + for (var i = 0; i < gcLen; i++) { + delete cache.data[cache.garbageCollect[i]]; + } + cache.garbageCollect.splice(0, gcLen); + } + + return longest; + }; + helpers.drawRoundedRectangle = function(ctx, x, y, width, height, radius) { + ctx.beginPath(); + ctx.moveTo(x + radius, y); + ctx.lineTo(x + width - radius, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius); + ctx.lineTo(x + width, y + height - radius); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); + ctx.lineTo(x + radius, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius); + ctx.lineTo(x, y + radius); + ctx.quadraticCurveTo(x, y, x + radius, y); + ctx.closePath(); + }; + helpers.color = function(c) { + if (!color) { + console.log('Color.js not found!'); + return c; + } + return color(c); + }; + helpers.addResizeListener = function(node, callback) { + // Hide an iframe before the node + var hiddenIframe = document.createElement('iframe'); + var hiddenIframeClass = 'chartjs-hidden-iframe'; + + if (hiddenIframe.classlist) { + // can use classlist + hiddenIframe.classlist.add(hiddenIframeClass); + } else { + hiddenIframe.setAttribute('class', hiddenIframeClass); + } + + // Set the style + hiddenIframe.style.width = '100%'; + hiddenIframe.style.display = 'block'; + hiddenIframe.style.border = 0; + hiddenIframe.style.height = 0; + hiddenIframe.style.margin = 0; + hiddenIframe.style.position = 'absolute'; + hiddenIframe.style.left = 0; + hiddenIframe.style.right = 0; + hiddenIframe.style.top = 0; + hiddenIframe.style.bottom = 0; + + // Insert the iframe so that contentWindow is available + node.insertBefore(hiddenIframe, node.firstChild); + + (hiddenIframe.contentWindow || hiddenIframe).onresize = function() { + if (callback) { + callback(); + } + }; + }; + helpers.removeResizeListener = function(node) { + var hiddenIframe = node.querySelector('.chartjs-hidden-iframe'); + + // Remove the resize detect iframe + if (hiddenIframe) { + hiddenIframe.parentNode.removeChild(hiddenIframe); + } + }; + helpers.isArray = function(obj) { + if (!Array.isArray) { + return Object.prototype.toString.call(obj) === '[object Array]'; + } + return Array.isArray(obj); + }; + helpers.pushAllIfDefined = function(element, array) { + if (typeof element === "undefined") { + return; + } + + if (helpers.isArray(element)) { + array.push.apply(array, element); + } else { + array.push(element); + } + }; + helpers.isDatasetVisible = function(dataset) { + return !dataset.hidden; + }; + helpers.callCallback = function(fn, args, _tArg) { + if (fn && typeof fn.call === 'function') { + fn.apply(_tArg, args); + } + }; + +}; +},{"chartjs-color":1}],26:[function(require,module,exports){ +"use strict"; + +module.exports = function() { + + //Occupy the global variable of Chart, and create a simple base class + var Chart = function(context, config) { + this.config = config; + + // Support a jQuery'd canvas element + if (context.length && context[0].getContext) { + context = context[0]; + } + + // Support a canvas domnode + if (context.getContext) { + context = context.getContext("2d"); + } + + this.ctx = context; + this.canvas = context.canvas; + + // Figure out what the size of the chart will be. + // If the canvas has a specified width and height, we use those else + // we look to see if the canvas node has a CSS width and height. + // If there is still no height, fill the parent container + this.width = context.canvas.width || parseInt(Chart.helpers.getStyle(context.canvas, 'width')) || Chart.helpers.getMaximumWidth(context.canvas); + this.height = context.canvas.height || parseInt(Chart.helpers.getStyle(context.canvas, 'height')) || Chart.helpers.getMaximumHeight(context.canvas); + + this.aspectRatio = this.width / this.height; + + if (isNaN(this.aspectRatio) || isFinite(this.aspectRatio) === false) { + // If the canvas has no size, try and figure out what the aspect ratio will be. + // Some charts prefer square canvases (pie, radar, etc). If that is specified, use that + // else use the canvas default ratio of 2 + this.aspectRatio = config.aspectRatio !== undefined ? config.aspectRatio : 2; + } + + // Store the original style of the element so we can set it back + this.originalCanvasStyleWidth = context.canvas.style.width; + this.originalCanvasStyleHeight = context.canvas.style.height; + + // High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale. + Chart.helpers.retinaScale(this); + + if (config) { + this.controller = new Chart.Controller(this); + } + + // Always bind this so that if the responsive state changes we still work + var _this = this; + Chart.helpers.addResizeListener(context.canvas.parentNode, function() { + if (_this.controller && _this.controller.config.options.responsive) { + _this.controller.resize(); + } + }); + + return this.controller ? this.controller : this; + + }; + + //Globally expose the defaults to allow for user updating/changing + Chart.defaults = { + global: { + responsive: true, + responsiveAnimationDuration: 0, + maintainAspectRatio: true, + events: ["mousemove", "mouseout", "click", "touchstart", "touchmove"], + hover: { + onHover: null, + mode: 'single', + animationDuration: 400 + }, + onClick: null, + defaultColor: 'rgba(0,0,0,0.1)', + defaultFontColor: '#666', + defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + defaultFontSize: 12, + defaultFontStyle: 'normal', + showLines: true, + + // Element defaults defined in element extensions + elements: {}, + + // Legend callback string + legendCallback: function(chart) { + var text = []; + text.push('
    '); + for (var i = 0; i < chart.data.datasets.length; i++) { + text.push('
  • '); + if (chart.data.datasets[i].label) { + text.push(chart.data.datasets[i].label); + } + text.push('
  • '); + } + text.push('
'); + + return text.join(""); + } + } + }; + + return Chart; + +}; +},{}],27:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + // The layout service is very self explanatory. It's responsible for the layout within a chart. + // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need + // It is this service's responsibility of carrying out that layout. + Chart.layoutService = { + defaults: {}, + + // Register a box to a chartInstance. A box is simply a reference to an object that requires layout. eg. Scales, Legend, Plugins. + addBox: function(chartInstance, box) { + if (!chartInstance.boxes) { + chartInstance.boxes = []; + } + chartInstance.boxes.push(box); + }, + + removeBox: function(chartInstance, box) { + if (!chartInstance.boxes) { + return; + } + chartInstance.boxes.splice(chartInstance.boxes.indexOf(box), 1); + }, + + // The most important function + update: function(chartInstance, width, height) { + + if (!chartInstance) { + return; + } + + var xPadding = 0; + var yPadding = 0; + + var leftBoxes = helpers.where(chartInstance.boxes, function(box) { + return box.options.position === "left"; + }); + var rightBoxes = helpers.where(chartInstance.boxes, function(box) { + return box.options.position === "right"; + }); + var topBoxes = helpers.where(chartInstance.boxes, function(box) { + return box.options.position === "top"; + }); + var bottomBoxes = helpers.where(chartInstance.boxes, function(box) { + return box.options.position === "bottom"; + }); + + // Boxes that overlay the chartarea such as the radialLinear scale + var chartAreaBoxes = helpers.where(chartInstance.boxes, function(box) { + return box.options.position === "chartArea"; + }); + + function fullWidthSorter(a, b) { + + } + + // Ensure that full width boxes are at the very top / bottom + topBoxes.sort(function(a, b) { + return (b.options.fullWidth ? 1 : 0) - (a.options.fullWidth ? 1 : 0); + }); + bottomBoxes.sort(function(a, b) { + return (a.options.fullWidth ? 1 : 0) - (b.options.fullWidth ? 1 : 0); + }); + + // Essentially we now have any number of boxes on each of the 4 sides. + // Our canvas looks like the following. + // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and + // B1 is the bottom axis + // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays + // These locations are single-box locations only, when trying to register a chartArea location that is already taken, + // an error will be thrown. + // + // |----------------------------------------------------| + // | T1 (Full Width) | + // |----------------------------------------------------| + // | | | T2 | | + // | |----|-------------------------------------|----| + // | | | C1 | | C2 | | + // | | |----| |----| | + // | | | | | + // | L1 | L2 | ChartArea (C0) | R1 | + // | | | | | + // | | |----| |----| | + // | | | C3 | | C4 | | + // | |----|-------------------------------------|----| + // | | | B1 | | + // |----------------------------------------------------| + // | B2 (Full Width) | + // |----------------------------------------------------| + // + // What we do to find the best sizing, we do the following + // 1. Determine the minimum size of the chart area. + // 2. Split the remaining width equally between each vertical axis + // 3. Split the remaining height equally between each horizontal axis + // 4. Give each layout the maximum size it can be. The layout will return it's minimum size + // 5. Adjust the sizes of each axis based on it's minimum reported size. + // 6. Refit each axis + // 7. Position each axis in the final location + // 8. Tell the chart the final location of the chart area + // 9. Tell any axes that overlay the chart area the positions of the chart area + + // Step 1 + var chartWidth = width - (2 * xPadding); + var chartHeight = height - (2 * yPadding); + var chartAreaWidth = chartWidth / 2; // min 50% + var chartAreaHeight = chartHeight / 2; // min 50% + + // Step 2 + var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length); + + // Step 3 + var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length); + + // Step 4 + var maxChartAreaWidth = chartWidth; + var maxChartAreaHeight = chartHeight; + var minBoxSizes = []; + + helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize); + + function getMinimumBoxSize(box) { + var minSize; + var isHorizontal = box.isHorizontal(); + + if (isHorizontal) { + minSize = box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight); + maxChartAreaHeight -= minSize.height; + } else { + minSize = box.update(verticalBoxWidth, chartAreaHeight); + maxChartAreaWidth -= minSize.width; + } + + minBoxSizes.push({ + horizontal: isHorizontal, + minSize: minSize, + box: box + }); + } + + // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could + // be if the axes are drawn at their minimum sizes. + + // Steps 5 & 6 + var totalLeftBoxesWidth = xPadding; + var totalRightBoxesWidth = xPadding; + var totalTopBoxesHeight = yPadding; + var totalBottomBoxesHeight = yPadding; + + // Update, and calculate the left and right margins for the horizontal boxes + helpers.each(leftBoxes.concat(rightBoxes), fitBox); + + helpers.each(leftBoxes, function(box) { + totalLeftBoxesWidth += box.width; + }); + + helpers.each(rightBoxes, function(box) { + totalRightBoxesWidth += box.width; + }); + + // Set the Left and Right margins for the horizontal boxes + helpers.each(topBoxes.concat(bottomBoxes), fitBox); + + // Function to fit a box + function fitBox(box) { + var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) { + return minBoxSize.box === box; + }); + + if (minBoxSize) { + if (box.isHorizontal()) { + var scaleMargin = { + left: totalLeftBoxesWidth, + right: totalRightBoxesWidth, + top: 0, + bottom: 0 + }; + + // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends + // on the margin. Sometimes they need to increase in size slightly + box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin); + } else { + box.update(minBoxSize.minSize.width, maxChartAreaHeight); + } + } + } + + // Figure out how much margin is on the top and bottom of the vertical boxes + helpers.each(topBoxes, function(box) { + totalTopBoxesHeight += box.height; + }); + + helpers.each(bottomBoxes, function(box) { + totalBottomBoxesHeight += box.height; + }); + + // Let the left layout know the final margin + helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox); + + function finalFitVerticalBox(box) { + var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) { + return minBoxSize.box === box; + }); + + var scaleMargin = { + left: 0, + right: 0, + top: totalTopBoxesHeight, + bottom: totalBottomBoxesHeight + }; + + if (minBoxSize) { + box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin); + } + } + + // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance) + totalLeftBoxesWidth = xPadding; + totalRightBoxesWidth = xPadding; + totalTopBoxesHeight = yPadding; + totalBottomBoxesHeight = yPadding; + + helpers.each(leftBoxes, function(box) { + totalLeftBoxesWidth += box.width; + }); + + helpers.each(rightBoxes, function(box) { + totalRightBoxesWidth += box.width; + }); + + helpers.each(topBoxes, function(box) { + totalTopBoxesHeight += box.height; + }); + helpers.each(bottomBoxes, function(box) { + totalBottomBoxesHeight += box.height; + }); + + // Figure out if our chart area changed. This would occur if the dataset layout label rotation + // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do + // without calling `fit` again + var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight; + var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth; + + if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) { + helpers.each(leftBoxes, function(box) { + box.height = newMaxChartAreaHeight; + }); + + helpers.each(rightBoxes, function(box) { + box.height = newMaxChartAreaHeight; + }); + + helpers.each(topBoxes, function(box) { + box.width = newMaxChartAreaWidth; + }); + + helpers.each(bottomBoxes, function(box) { + box.width = newMaxChartAreaWidth; + }); + + maxChartAreaHeight = newMaxChartAreaHeight; + maxChartAreaWidth = newMaxChartAreaWidth; + } + + // Step 7 - Position the boxes + var left = xPadding; + var top = yPadding; + var right = 0; + var bottom = 0; + + helpers.each(leftBoxes.concat(topBoxes), placeBox); + + // Account for chart width and height + left += maxChartAreaWidth; + top += maxChartAreaHeight; + + helpers.each(rightBoxes, placeBox); + helpers.each(bottomBoxes, placeBox); + + function placeBox(box) { + if (box.isHorizontal()) { + box.left = box.options.fullWidth ? xPadding : totalLeftBoxesWidth; + box.right = box.options.fullWidth ? width - xPadding : totalLeftBoxesWidth + maxChartAreaWidth; + box.top = top; + box.bottom = top + box.height; + + // Move to next point + top = box.bottom; + + } else { + + box.left = left; + box.right = left + box.width; + box.top = totalTopBoxesHeight; + box.bottom = totalTopBoxesHeight + maxChartAreaHeight; + + // Move to next point + left = box.right; + } + } + + // Step 8 + chartInstance.chartArea = { + left: totalLeftBoxesWidth, + top: totalTopBoxesHeight, + right: totalLeftBoxesWidth + maxChartAreaWidth, + bottom: totalTopBoxesHeight + maxChartAreaHeight + }; + + // Step 9 + helpers.each(chartAreaBoxes, function(box) { + box.left = chartInstance.chartArea.left; + box.top = chartInstance.chartArea.top; + box.right = chartInstance.chartArea.right; + box.bottom = chartInstance.chartArea.bottom; + + box.update(maxChartAreaWidth, maxChartAreaHeight); + }); + } + }; +}; + +},{}],28:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.global.legend = { + + display: true, + position: 'top', + fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes) + reverse: false, + + // a callback that will handle + onClick: function(e, legendItem) { + var dataset = this.chart.data.datasets[legendItem.datasetIndex]; + dataset.hidden = !dataset.hidden; + + // We hid a dataset ... rerender the chart + this.chart.update(); + }, + + labels: { + boxWidth: 40, + padding: 10, + // Generates labels shown in the legend + // Valid properties to return: + // text : text to display + // fillStyle : fill of coloured box + // strokeStyle: stroke of coloured box + // hidden : if this legend item refers to a hidden item + // lineCap : cap style for line + // lineDash + // lineDashOffset : + // lineJoin : + // lineWidth : + generateLabels: function(data) { + return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) { + return { + text: dataset.label, + fillStyle: dataset.backgroundColor, + hidden: dataset.hidden, + lineCap: dataset.borderCapStyle, + lineDash: dataset.borderDash, + lineDashOffset: dataset.borderDashOffset, + lineJoin: dataset.borderJoinStyle, + lineWidth: dataset.borderWidth, + strokeStyle: dataset.borderColor, + + // Below is extra data used for toggling the datasets + datasetIndex: i + }; + }, this) : []; + } + } + }; + + Chart.Legend = Chart.Element.extend({ + + initialize: function(config) { + helpers.extend(this, config); + + // Contains hit boxes for each dataset (in dataset order) + this.legendHitBoxes = []; + + // Are we in doughnut mode which has a different data type + this.doughnutMode = false; + }, + + // These methods are ordered by lifecyle. Utilities then follow. + // Any function defined here is inherited by all legend types. + // Any function can be extended by the legend type + + beforeUpdate: helpers.noop, + update: function(maxWidth, maxHeight, margins) { + + // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) + this.beforeUpdate(); + + // Absorb the master measurements + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this.margins = margins; + + // Dimensions + this.beforeSetDimensions(); + this.setDimensions(); + this.afterSetDimensions(); + // Labels + this.beforeBuildLabels(); + this.buildLabels(); + this.afterBuildLabels(); + + // Fit + this.beforeFit(); + this.fit(); + this.afterFit(); + // + this.afterUpdate(); + + return this.minSize; + + }, + afterUpdate: helpers.noop, + + // + + beforeSetDimensions: helpers.noop, + setDimensions: function() { + // Set the unconstrained dimension before label rotation + if (this.isHorizontal()) { + // Reset position before calculating rotation + this.width = this.maxWidth; + this.left = 0; + this.right = this.width; + } else { + this.height = this.maxHeight; + + // Reset position before calculating rotation + this.top = 0; + this.bottom = this.height; + } + + // Reset padding + this.paddingLeft = 0; + this.paddingTop = 0; + this.paddingRight = 0; + this.paddingBottom = 0; + + // Reset minSize + this.minSize = { + width: 0, + height: 0 + }; + }, + afterSetDimensions: helpers.noop, + + // + + beforeBuildLabels: helpers.noop, + buildLabels: function() { + this.legendItems = this.options.labels.generateLabels.call(this, this.chart.data); + if(this.options.reverse){ + this.legendItems.reverse(); + } + }, + afterBuildLabels: helpers.noop, + + // + + beforeFit: helpers.noop, + fit: function() { + + var ctx = this.ctx; + var fontSize = helpers.getValueOrDefault(this.options.labels.fontSize, Chart.defaults.global.defaultFontSize); + var fontStyle = helpers.getValueOrDefault(this.options.labels.fontStyle, Chart.defaults.global.defaultFontStyle); + var fontFamily = helpers.getValueOrDefault(this.options.labels.fontFamily, Chart.defaults.global.defaultFontFamily); + var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily); + + // Reset hit boxes + this.legendHitBoxes = []; + + // Width + if (this.isHorizontal()) { + this.minSize.width = this.maxWidth; // fill all the width + } else { + this.minSize.width = this.options.display ? 10 : 0; + } + + // height + if (this.isHorizontal()) { + this.minSize.height = this.options.display ? 10 : 0; + } else { + this.minSize.height = this.maxHeight; // fill all the height + } + + // Increase sizes here + if (this.options.display) { + if (this.isHorizontal()) { + // Labels + + // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one + this.lineWidths = [0]; + var totalHeight = this.legendItems.length ? fontSize + (this.options.labels.padding) : 0; + + ctx.textAlign = "left"; + ctx.textBaseline = 'top'; + ctx.font = labelFont; + + helpers.each(this.legendItems, function(legendItem, i) { + var width = this.options.labels.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + if (this.lineWidths[this.lineWidths.length - 1] + width + this.options.labels.padding >= this.width) { + totalHeight += fontSize + (this.options.labels.padding); + this.lineWidths[this.lineWidths.length] = this.left; + } + + // Store the hitbox width and height here. Final position will be updated in `draw` + this.legendHitBoxes[i] = { + left: 0, + top: 0, + width: width, + height: fontSize + }; + + this.lineWidths[this.lineWidths.length - 1] += width + this.options.labels.padding; + }, this); + + this.minSize.height += totalHeight; + + } else { + // TODO vertical + } + } + + this.width = this.minSize.width; + this.height = this.minSize.height; + + }, + afterFit: helpers.noop, + + // Shared Methods + isHorizontal: function() { + return this.options.position === "top" || this.options.position === "bottom"; + }, + + // Actualy draw the legend on the canvas + draw: function() { + if (this.options.display) { + var ctx = this.ctx; + var cursor = { + x: this.left + ((this.width - this.lineWidths[0]) / 2), + y: this.top + this.options.labels.padding, + line: 0 + }; + + var fontColor = helpers.getValueOrDefault(this.options.labels.fontColor, Chart.defaults.global.defaultFontColor); + var fontSize = helpers.getValueOrDefault(this.options.labels.fontSize, Chart.defaults.global.defaultFontSize); + var fontStyle = helpers.getValueOrDefault(this.options.labels.fontStyle, Chart.defaults.global.defaultFontStyle); + var fontFamily = helpers.getValueOrDefault(this.options.labels.fontFamily, Chart.defaults.global.defaultFontFamily); + var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily); + + // Horizontal + if (this.isHorizontal()) { + // Labels + ctx.textAlign = "left"; + ctx.textBaseline = 'top'; + ctx.lineWidth = 0.5; + ctx.strokeStyle = fontColor; // for strikethrough effect + ctx.fillStyle = fontColor; // render in correct colour + ctx.font = labelFont; + + helpers.each(this.legendItems, function(legendItem, i) { + var textWidth = ctx.measureText(legendItem.text).width; + var width = this.options.labels.boxWidth + (fontSize / 2) + textWidth; + + if (cursor.x + width >= this.width) { + cursor.y += fontSize + (this.options.labels.padding); + cursor.line++; + cursor.x = this.left + ((this.width - this.lineWidths[cursor.line]) / 2); + } + + // Set the ctx for the box + ctx.save(); + + var itemOrDefault = function(item, defaulVal) { + return item !== undefined ? item : defaulVal; + }; + + ctx.fillStyle = itemOrDefault(legendItem.fillStyle, Chart.defaults.global.defaultColor); + ctx.lineCap = itemOrDefault(legendItem.lineCap, Chart.defaults.global.elements.line.borderCapStyle); + ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, Chart.defaults.global.elements.line.borderDashOffset); + ctx.lineJoin = itemOrDefault(legendItem.lineJoin, Chart.defaults.global.elements.line.borderJoinStyle); + ctx.lineWidth = itemOrDefault(legendItem.lineWidth, Chart.defaults.global.elements.line.borderWidth); + ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, Chart.defaults.global.defaultColor); + + if (ctx.setLineDash) { + // IE 9 and 10 do not support line dash + ctx.setLineDash(itemOrDefault(legendItem.lineDash, Chart.defaults.global.elements.line.borderDash)); + } + + // Draw the box + ctx.strokeRect(cursor.x, cursor.y, this.options.labels.boxWidth, fontSize); + ctx.fillRect(cursor.x, cursor.y, this.options.labels.boxWidth, fontSize); + + ctx.restore(); + + this.legendHitBoxes[i].left = cursor.x; + this.legendHitBoxes[i].top = cursor.y; + + // Fill the actual label + ctx.fillText(legendItem.text, this.options.labels.boxWidth + (fontSize / 2) + cursor.x, cursor.y); + + if (legendItem.hidden) { + // Strikethrough the text if hidden + ctx.beginPath(); + ctx.lineWidth = 2; + ctx.moveTo(this.options.labels.boxWidth + (fontSize / 2) + cursor.x, cursor.y + (fontSize / 2)); + ctx.lineTo(this.options.labels.boxWidth + (fontSize / 2) + cursor.x + textWidth, cursor.y + (fontSize / 2)); + ctx.stroke(); + } + + cursor.x += width + (this.options.labels.padding); + }, this); + } else { + + } + } + }, + + // Handle an event + handleEvent: function(e) { + var position = helpers.getRelativePosition(e, this.chart.chart); + + if (position.x >= this.left && position.x <= this.right && position.y >= this.top && position.y <= this.bottom) { + // See if we are touching one of the dataset boxes + for (var i = 0; i < this.legendHitBoxes.length; ++i) { + var hitBox = this.legendHitBoxes[i]; + + if (position.x >= hitBox.left && position.x <= hitBox.left + hitBox.width && position.y >= hitBox.top && position.y <= hitBox.top + hitBox.height) { + // Touching an element + if (this.options.onClick) { + this.options.onClick.call(this, e, this.legendItems[i]); + } + break; + } + } + } + } + }); + +}; + +},{}],29:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.scale = { + display: true, + + // grid line settings + gridLines: { + display: true, + color: "rgba(0, 0, 0, 0.1)", + lineWidth: 1, + drawOnChartArea: true, + drawTicks: true, + zeroLineWidth: 1, + zeroLineColor: "rgba(0,0,0,0.25)", + offsetGridLines: false + }, + + // scale label + scaleLabel: { + // actual label + labelString: '', + + // display property + display: false + }, + + // label settings + ticks: { + beginAtZero: false, + maxRotation: 90, + mirror: false, + padding: 10, + reverse: false, + display: true, + autoSkip: true, + autoSkipPadding: 20, + callback: function(value) { + return '' + value; + } + } + }; + + Chart.Scale = Chart.Element.extend({ + + // These methods are ordered by lifecyle. Utilities then follow. + // Any function defined here is inherited by all scale types. + // Any function can be extended by the scale type + + beforeUpdate: function() { + helpers.callCallback(this.options.beforeUpdate, [this]); + }, + update: function(maxWidth, maxHeight, margins) { + + // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) + this.beforeUpdate(); + + // Absorb the master measurements + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this.margins = helpers.extend({ + left: 0, + right: 0, + top: 0, + bottom: 0 + }, margins); + + // Dimensions + this.beforeSetDimensions(); + this.setDimensions(); + this.afterSetDimensions(); + + // Data min/max + this.beforeDataLimits(); + this.determineDataLimits(); + this.afterDataLimits(); + + // Ticks + this.beforeBuildTicks(); + this.buildTicks(); + this.afterBuildTicks(); + + this.beforeTickToLabelConversion(); + this.convertTicksToLabels(); + this.afterTickToLabelConversion(); + + // Tick Rotation + this.beforeCalculateTickRotation(); + this.calculateTickRotation(); + this.afterCalculateTickRotation(); + // Fit + this.beforeFit(); + this.fit(); + this.afterFit(); + // + this.afterUpdate(); + + return this.minSize; + + }, + afterUpdate: function() { + helpers.callCallback(this.options.afterUpdate, [this]); + }, + + // + + beforeSetDimensions: function() { + helpers.callCallback(this.options.beforeSetDimensions, [this]); + }, + setDimensions: function() { + // Set the unconstrained dimension before label rotation + if (this.isHorizontal()) { + // Reset position before calculating rotation + this.width = this.maxWidth; + this.left = 0; + this.right = this.width; + } else { + this.height = this.maxHeight; + + // Reset position before calculating rotation + this.top = 0; + this.bottom = this.height; + } + + // Reset padding + this.paddingLeft = 0; + this.paddingTop = 0; + this.paddingRight = 0; + this.paddingBottom = 0; + }, + afterSetDimensions: function() { + helpers.callCallback(this.options.afterSetDimensions, [this]); + }, + + // Data limits + beforeDataLimits: function() { + helpers.callCallback(this.options.beforeDataLimits, [this]); + }, + determineDataLimits: helpers.noop, + afterDataLimits: function() { + helpers.callCallback(this.options.afterDataLimits, [this]); + }, + + // + beforeBuildTicks: function() { + helpers.callCallback(this.options.beforeBuildTicks, [this]); + }, + buildTicks: helpers.noop, + afterBuildTicks: function() { + helpers.callCallback(this.options.afterBuildTicks, [this]); + }, + + beforeTickToLabelConversion: function() { + helpers.callCallback(this.options.beforeTickToLabelConversion, [this]); + }, + convertTicksToLabels: function() { + // Convert ticks to strings + this.ticks = this.ticks.map(function(numericalTick, index, ticks) { + if (this.options.ticks.userCallback) { + return this.options.ticks.userCallback(numericalTick, index, ticks); + } + return this.options.ticks.callback(numericalTick, index, ticks); + }, + this); + }, + afterTickToLabelConversion: function() { + helpers.callCallback(this.options.afterTickToLabelConversion, [this]); + }, + + // + + beforeCalculateTickRotation: function() { + helpers.callCallback(this.options.beforeCalculateTickRotation, [this]); + }, + calculateTickRotation: function() { + //Get the width of each grid by calculating the difference + //between x offsets between 0 and 1. + var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); + var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle); + var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily); + var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily); + this.ctx.font = tickLabelFont; + + var firstWidth = this.ctx.measureText(this.ticks[0]).width; + var lastWidth = this.ctx.measureText(this.ticks[this.ticks.length - 1]).width; + var firstRotated; + + this.labelRotation = 0; + this.paddingRight = 0; + this.paddingLeft = 0; + + if (this.options.display) { + if (this.isHorizontal()) { + this.paddingRight = lastWidth / 2 + 3; + this.paddingLeft = firstWidth / 2 + 3; + + if (!this.longestTextCache) { + this.longestTextCache = {}; + } + var originalLabelWidth = helpers.longestText(this.ctx, tickLabelFont, this.ticks, this.longestTextCache); + var labelWidth = originalLabelWidth; + var cosRotation; + var sinRotation; + + // Allow 3 pixels x2 padding either side for label readability + // only the index matters for a dataset scale, but we want a consistent interface between scales + var tickWidth = this.getPixelForTick(1) - this.getPixelForTick(0) - 6; + + //Max label rotation can be set or default to 90 - also act as a loop counter + while (labelWidth > tickWidth && this.labelRotation < this.options.ticks.maxRotation) { + cosRotation = Math.cos(helpers.toRadians(this.labelRotation)); + sinRotation = Math.sin(helpers.toRadians(this.labelRotation)); + + firstRotated = cosRotation * firstWidth; + + // We're right aligning the text now. + if (firstRotated + tickFontSize / 2 > this.yLabelWidth) { + this.paddingLeft = firstRotated + tickFontSize / 2; + } + + this.paddingRight = tickFontSize / 2; + + if (sinRotation * originalLabelWidth > this.maxHeight) { + // go back one step + this.labelRotation--; + break; + } + + this.labelRotation++; + labelWidth = cosRotation * originalLabelWidth; + } + } + } + + if (this.margins) { + this.paddingLeft = Math.max(this.paddingLeft - this.margins.left, 0); + this.paddingRight = Math.max(this.paddingRight - this.margins.right, 0); + } + }, + afterCalculateTickRotation: function() { + helpers.callCallback(this.options.afterCalculateTickRotation, [this]); + }, + + // + + beforeFit: function() { + helpers.callCallback(this.options.beforeFit, [this]); + }, + fit: function() { + + this.minSize = { + width: 0, + height: 0 + }; + + var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); + var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle); + var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily); + var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily); + + var scaleLabelFontSize = helpers.getValueOrDefault(this.options.scaleLabel.fontSize, Chart.defaults.global.defaultFontSize); + var scaleLabelFontStyle = helpers.getValueOrDefault(this.options.scaleLabel.fontStyle, Chart.defaults.global.defaultFontStyle); + var scaleLabelFontFamily = helpers.getValueOrDefault(this.options.scaleLabel.fontFamily, Chart.defaults.global.defaultFontFamily); + var scaleLabelFont = helpers.fontString(scaleLabelFontSize, scaleLabelFontStyle, scaleLabelFontFamily); + + // Width + if (this.isHorizontal()) { + // subtract the margins to line up with the chartArea if we are a full width scale + this.minSize.width = this.isFullWidth() ? this.maxWidth - this.margins.left - this.margins.right : this.maxWidth; + } else { + this.minSize.width = this.options.gridLines.display && this.options.display ? 10 : 0; + } + + // height + if (this.isHorizontal()) { + this.minSize.height = this.options.gridLines.display && this.options.display ? 10 : 0; + } else { + this.minSize.height = this.maxHeight; // fill all the height + } + + // Are we showing a title for the scale? + if (this.options.scaleLabel.display) { + if (this.isHorizontal()) { + this.minSize.height += (scaleLabelFontSize * 1.5); + } else { + this.minSize.width += (scaleLabelFontSize * 1.5); + } + } + + if (this.options.ticks.display && this.options.display) { + // Don't bother fitting the ticks if we are not showing them + if (!this.longestTextCache) { + this.longestTextCache = {}; + } + + var largestTextWidth = helpers.longestText(this.ctx, tickLabelFont, this.ticks, this.longestTextCache); + + if (this.isHorizontal()) { + // A horizontal axis is more constrained by the height. + this.longestLabelWidth = largestTextWidth; + + // TODO - improve this calculation + var labelHeight = (Math.sin(helpers.toRadians(this.labelRotation)) * this.longestLabelWidth) + 1.5 * tickFontSize; + + this.minSize.height = Math.min(this.maxHeight, this.minSize.height + labelHeight); + this.ctx.font = tickLabelFont; + + var firstLabelWidth = this.ctx.measureText(this.ticks[0]).width; + var lastLabelWidth = this.ctx.measureText(this.ticks[this.ticks.length - 1]).width; + + // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated + // by the font height + var cosRotation = Math.cos(helpers.toRadians(this.labelRotation)); + var sinRotation = Math.sin(helpers.toRadians(this.labelRotation)); + this.paddingLeft = this.labelRotation !== 0 ? (cosRotation * firstLabelWidth) + 3 : firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges + this.paddingRight = this.labelRotation !== 0 ? (sinRotation * (tickFontSize / 2)) + 3 : lastLabelWidth / 2 + 3; // when rotated + } else { + // A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first + var maxLabelWidth = this.maxWidth - this.minSize.width; + + // Account for padding + if (!this.options.ticks.mirror) { + largestTextWidth += this.options.ticks.padding; + } + + if (largestTextWidth < maxLabelWidth) { + // We don't need all the room + this.minSize.width += largestTextWidth; + } else { + // Expand to max size + this.minSize.width = this.maxWidth; + } + + this.paddingTop = tickFontSize / 2; + this.paddingBottom = tickFontSize / 2; + } + } + + if (this.margins) { + this.paddingLeft = Math.max(this.paddingLeft - this.margins.left, 0); + this.paddingTop = Math.max(this.paddingTop - this.margins.top, 0); + this.paddingRight = Math.max(this.paddingRight - this.margins.right, 0); + this.paddingBottom = Math.max(this.paddingBottom - this.margins.bottom, 0); + } + + this.width = this.minSize.width; + this.height = this.minSize.height; + + }, + afterFit: function() { + helpers.callCallback(this.options.afterFit, [this]); + }, + + // Shared Methods + isHorizontal: function() { + return this.options.position === "top" || this.options.position === "bottom"; + }, + isFullWidth: function() { + return (this.options.fullWidth); + }, + + // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not + getRightValue: function getRightValue(rawValue) { + // Null and undefined values first + if (rawValue === null || typeof(rawValue) === 'undefined') { + return NaN; + } + // isNaN(object) returns true, so make sure NaN is checking for a number + if (typeof(rawValue) === 'number' && isNaN(rawValue)) { + return NaN; + } + // If it is in fact an object, dive in one more level + if (typeof(rawValue) === "object") { + if (rawValue instanceof Date) { + return rawValue; + } else { + return getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y); + } + } + + // Value is good, return it + return rawValue; + }, + + // Used to get the value to display in the tooltip for the data at the given index + // function getLabelForIndex(index, datasetIndex) + getLabelForIndex: helpers.noop, + + // Used to get data value locations. Value can either be an index or a numerical value + getPixelForValue: helpers.noop, + + // Used for tick location, should + getPixelForTick: function(index, includeOffset) { + if (this.isHorizontal()) { + var innerWidth = this.width - (this.paddingLeft + this.paddingRight); + var tickWidth = innerWidth / Math.max((this.ticks.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1); + var pixel = (tickWidth * index) + this.paddingLeft; + + if (includeOffset) { + pixel += tickWidth / 2; + } + + var finalVal = this.left + Math.round(pixel); + finalVal += this.isFullWidth() ? this.margins.left : 0; + return finalVal; + } else { + var innerHeight = this.height - (this.paddingTop + this.paddingBottom); + return this.top + (index * (innerHeight / (this.ticks.length - 1))); + } + }, + + // Utility for getting the pixel location of a percentage of scale + getPixelForDecimal: function(decimal /*, includeOffset*/ ) { + if (this.isHorizontal()) { + var innerWidth = this.width - (this.paddingLeft + this.paddingRight); + var valueOffset = (innerWidth * decimal) + this.paddingLeft; + + var finalVal = this.left + Math.round(valueOffset); + finalVal += this.isFullWidth() ? this.margins.left : 0; + return finalVal; + } else { + return this.top + (decimal * this.height); + } + }, + + // Actualy draw the scale on the canvas + // @param {rectangle} chartArea : the area of the chart to draw full grid lines on + draw: function(chartArea) { + if (this.options.display) { + + var setContextLineSettings; + var isRotated = this.labelRotation !== 0; + var skipRatio; + var scaleLabelX; + var scaleLabelY; + var useAutoskipper = this.options.ticks.autoSkip; + + + // figure out the maximum number of gridlines to show + var maxTicks; + + if (this.options.ticks.maxTicksLimit) { + maxTicks = this.options.ticks.maxTicksLimit; + } + + var tickFontColor = helpers.getValueOrDefault(this.options.ticks.fontColor, Chart.defaults.global.defaultFontColor); + var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); + var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle); + var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily); + var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily); + + var scaleLabelFontColor = helpers.getValueOrDefault(this.options.scaleLabel.fontColor, Chart.defaults.global.defaultFontColor); + var scaleLabelFontSize = helpers.getValueOrDefault(this.options.scaleLabel.fontSize, Chart.defaults.global.defaultFontSize); + var scaleLabelFontStyle = helpers.getValueOrDefault(this.options.scaleLabel.fontStyle, Chart.defaults.global.defaultFontStyle); + var scaleLabelFontFamily = helpers.getValueOrDefault(this.options.scaleLabel.fontFamily, Chart.defaults.global.defaultFontFamily); + var scaleLabelFont = helpers.fontString(scaleLabelFontSize, scaleLabelFontStyle, scaleLabelFontFamily); + + var cosRotation = Math.cos(helpers.toRadians(this.labelRotation)); + var sinRotation = Math.sin(helpers.toRadians(this.labelRotation)); + var longestRotatedLabel = this.longestLabelWidth * cosRotation; + var rotatedLabelHeight = tickFontSize * sinRotation; + + // Make sure we draw text in the correct color and font + this.ctx.fillStyle = tickFontColor; + + if (this.isHorizontal()) { + setContextLineSettings = true; + var yTickStart = this.options.position === "bottom" ? this.top : this.bottom - 10; + var yTickEnd = this.options.position === "bottom" ? this.top + 10 : this.bottom; + skipRatio = false; + + if (((longestRotatedLabel / 2) + this.options.ticks.autoSkipPadding) * this.ticks.length > (this.width - (this.paddingLeft + this.paddingRight))) { + skipRatio = 1 + Math.floor((((longestRotatedLabel / 2) + this.options.ticks.autoSkipPadding) * this.ticks.length) / (this.width - (this.paddingLeft + this.paddingRight))); + } + + // if they defined a max number of ticks, + // increase skipRatio until that number is met + if (maxTicks && this.ticks.length > maxTicks) { + while (!skipRatio || this.ticks.length / (skipRatio || 1) > maxTicks) { + if (!skipRatio) { + skipRatio = 1; + } + skipRatio += 1; + } + } + + if (!useAutoskipper) { + skipRatio = false; + } + + helpers.each(this.ticks, function(label, index) { + // Blank ticks + var isLastTick = this.ticks.length === index + 1; + + // Since we always show the last tick,we need may need to hide the last shown one before + var shouldSkip = (skipRatio > 1 && index % skipRatio > 0) || (index % skipRatio === 0 && index + skipRatio > this.ticks.length); + if (shouldSkip && !isLastTick || (label === undefined || label === null)) { + return; + } + var xLineValue = this.getPixelForTick(index); // xvalues for grid lines + var xLabelValue = this.getPixelForTick(index, this.options.gridLines.offsetGridLines); // x values for ticks (need to consider offsetLabel option) + + if (this.options.gridLines.display) { + if (index === (typeof this.zeroLineIndex !== 'undefined' ? this.zeroLineIndex : 0)) { + // Draw the first index specially + this.ctx.lineWidth = this.options.gridLines.zeroLineWidth; + this.ctx.strokeStyle = this.options.gridLines.zeroLineColor; + setContextLineSettings = true; // reset next time + } else if (setContextLineSettings) { + this.ctx.lineWidth = this.options.gridLines.lineWidth; + this.ctx.strokeStyle = this.options.gridLines.color; + setContextLineSettings = false; + } + + xLineValue += helpers.aliasPixel(this.ctx.lineWidth); + + // Draw the label area + this.ctx.beginPath(); + + if (this.options.gridLines.drawTicks) { + this.ctx.moveTo(xLineValue, yTickStart); + this.ctx.lineTo(xLineValue, yTickEnd); + } + + // Draw the chart area + if (this.options.gridLines.drawOnChartArea) { + this.ctx.moveTo(xLineValue, chartArea.top); + this.ctx.lineTo(xLineValue, chartArea.bottom); + } + + // Need to stroke in the loop because we are potentially changing line widths & colours + this.ctx.stroke(); + } + + if (this.options.ticks.display) { + this.ctx.save(); + this.ctx.translate(xLabelValue, (isRotated) ? this.top + 12 : this.options.position === "top" ? this.bottom - 10 : this.top + 10); + this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1); + this.ctx.font = tickLabelFont; + this.ctx.textAlign = (isRotated) ? "right" : "center"; + this.ctx.textBaseline = (isRotated) ? "middle" : this.options.position === "top" ? "bottom" : "top"; + this.ctx.fillText(label, 0, 0); + this.ctx.restore(); + } + }, this); + + if (this.options.scaleLabel.display) { + // Draw the scale label + this.ctx.textAlign = "center"; + this.ctx.textBaseline = 'middle'; + this.ctx.fillStyle = scaleLabelFontColor; // render in correct colour + this.ctx.font = scaleLabelFont; + + scaleLabelX = this.left + ((this.right - this.left) / 2); // midpoint of the width + scaleLabelY = this.options.position === 'bottom' ? this.bottom - (scaleLabelFontSize / 2) : this.top + (scaleLabelFontSize / 2); + + this.ctx.fillText(this.options.scaleLabel.labelString, scaleLabelX, scaleLabelY); + } + + } else { + setContextLineSettings = true; + var xTickStart = this.options.position === "right" ? this.left : this.right - 5; + var xTickEnd = this.options.position === "right" ? this.left + 5 : this.right; + + helpers.each(this.ticks, function(label, index) { + // If the callback returned a null or undefined value, do not draw this line + if (label === undefined || label === null) { + return; + } + + var yLineValue = this.getPixelForTick(index); // xvalues for grid lines + + if (this.options.gridLines.display) { + if (index === (typeof this.zeroLineIndex !== 'undefined' ? this.zeroLineIndex : 0)) { + // Draw the first index specially + this.ctx.lineWidth = this.options.gridLines.zeroLineWidth; + this.ctx.strokeStyle = this.options.gridLines.zeroLineColor; + setContextLineSettings = true; // reset next time + } else if (setContextLineSettings) { + this.ctx.lineWidth = this.options.gridLines.lineWidth; + this.ctx.strokeStyle = this.options.gridLines.color; + setContextLineSettings = false; + } + + yLineValue += helpers.aliasPixel(this.ctx.lineWidth); + + // Draw the label area + this.ctx.beginPath(); + + if (this.options.gridLines.drawTicks) { + this.ctx.moveTo(xTickStart, yLineValue); + this.ctx.lineTo(xTickEnd, yLineValue); + } + + // Draw the chart area + if (this.options.gridLines.drawOnChartArea) { + this.ctx.moveTo(chartArea.left, yLineValue); + this.ctx.lineTo(chartArea.right, yLineValue); + } + + // Need to stroke in the loop because we are potentially changing line widths & colours + this.ctx.stroke(); + } + + if (this.options.ticks.display) { + var xLabelValue; + var yLabelValue = this.getPixelForTick(index, this.options.gridLines.offsetGridLines); // x values for ticks (need to consider offsetLabel option) + + this.ctx.save(); + + if (this.options.position === "left") { + if (this.options.ticks.mirror) { + xLabelValue = this.right + this.options.ticks.padding; + this.ctx.textAlign = "left"; + } else { + xLabelValue = this.right - this.options.ticks.padding; + this.ctx.textAlign = "right"; + } + } else { + // right side + if (this.options.ticks.mirror) { + xLabelValue = this.left - this.options.ticks.padding; + this.ctx.textAlign = "right"; + } else { + xLabelValue = this.left + this.options.ticks.padding; + this.ctx.textAlign = "left"; + } + } + + this.ctx.translate(xLabelValue, yLabelValue); + this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1); + this.ctx.font = tickLabelFont; + this.ctx.textBaseline = "middle"; + this.ctx.fillText(label, 0, 0); + this.ctx.restore(); + } + }, this); + + if (this.options.scaleLabel.display) { + // Draw the scale label + scaleLabelX = this.options.position === 'left' ? this.left + (scaleLabelFontSize / 2) : this.right - (scaleLabelFontSize / 2); + scaleLabelY = this.top + ((this.bottom - this.top) / 2); + var rotation = this.options.position === 'left' ? -0.5 * Math.PI : 0.5 * Math.PI; + + this.ctx.save(); + this.ctx.translate(scaleLabelX, scaleLabelY); + this.ctx.rotate(rotation); + this.ctx.textAlign = "center"; + this.ctx.fillStyle =scaleLabelFontColor; // render in correct colour + this.ctx.font = scaleLabelFont; + this.ctx.textBaseline = 'middle'; + this.ctx.fillText(this.options.scaleLabel.labelString, 0, 0); + this.ctx.restore(); + } + } + + // Draw the line at the edge of the axis + this.ctx.lineWidth = this.options.gridLines.lineWidth; + this.ctx.strokeStyle = this.options.gridLines.color; + var x1 = this.left, + x2 = this.right, + y1 = this.top, + y2 = this.bottom; + + if (this.isHorizontal()) { + y1 = y2 = this.options.position === 'top' ? this.bottom : this.top; + y1 += helpers.aliasPixel(this.ctx.lineWidth); + y2 += helpers.aliasPixel(this.ctx.lineWidth); + } else { + x1 = x2 = this.options.position === 'left' ? this.right : this.left; + x1 += helpers.aliasPixel(this.ctx.lineWidth); + x2 += helpers.aliasPixel(this.ctx.lineWidth); + } + + this.ctx.beginPath(); + this.ctx.moveTo(x1, y1); + this.ctx.lineTo(x2, y2); + this.ctx.stroke(); + } + } + }); +}; +},{}],30:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.scaleService = { + // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then + // use the new chart options to grab the correct scale + constructors: {}, + // Use a registration function so that we can move to an ES6 map when we no longer need to support + // old browsers + + // Scale config defaults + defaults: {}, + registerScaleType: function(type, scaleConstructor, defaults) { + this.constructors[type] = scaleConstructor; + this.defaults[type] = helpers.clone(defaults); + }, + getScaleConstructor: function(type) { + return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined; + }, + getScaleDefaults: function(type) { + // Return the scale defaults merged with the global settings so that we always use the latest ones + return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {}; + }, + addScalesToLayout: function(chartInstance) { + // Adds each scale to the chart.boxes array to be sized accordingly + helpers.each(chartInstance.scales, function(scale) { + Chart.layoutService.addBox(chartInstance, scale); + }); + } + }; +}; +},{}],31:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.global.title = { + display: false, + position: 'top', + fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes) + + fontStyle: 'bold', + padding: 10, + + // actual title + text: '' + }; + + Chart.Title = Chart.Element.extend({ + + initialize: function(config) { + helpers.extend(this, config); + this.options = helpers.configMerge(Chart.defaults.global.title, config.options); + + // Contains hit boxes for each dataset (in dataset order) + this.legendHitBoxes = []; + }, + + // These methods are ordered by lifecyle. Utilities then follow. + + beforeUpdate: helpers.noop, + update: function(maxWidth, maxHeight, margins) { + + // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) + this.beforeUpdate(); + + // Absorb the master measurements + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this.margins = margins; + + // Dimensions + this.beforeSetDimensions(); + this.setDimensions(); + this.afterSetDimensions(); + // Labels + this.beforeBuildLabels(); + this.buildLabels(); + this.afterBuildLabels(); + + // Fit + this.beforeFit(); + this.fit(); + this.afterFit(); + // + this.afterUpdate(); + + return this.minSize; + + }, + afterUpdate: helpers.noop, + + // + + beforeSetDimensions: helpers.noop, + setDimensions: function() { + // Set the unconstrained dimension before label rotation + if (this.isHorizontal()) { + // Reset position before calculating rotation + this.width = this.maxWidth; + this.left = 0; + this.right = this.width; + } else { + this.height = this.maxHeight; + + // Reset position before calculating rotation + this.top = 0; + this.bottom = this.height; + } + + // Reset padding + this.paddingLeft = 0; + this.paddingTop = 0; + this.paddingRight = 0; + this.paddingBottom = 0; + + // Reset minSize + this.minSize = { + width: 0, + height: 0 + }; + }, + afterSetDimensions: helpers.noop, + + // + + beforeBuildLabels: helpers.noop, + buildLabels: helpers.noop, + afterBuildLabels: helpers.noop, + + // + + beforeFit: helpers.noop, + fit: function() { + + var ctx = this.ctx; + var fontSize = helpers.getValueOrDefault(this.options.fontSize, Chart.defaults.global.defaultFontSize); + var fontStyle = helpers.getValueOrDefault(this.options.fontStyle, Chart.defaults.global.defaultFontStyle); + var fontFamily = helpers.getValueOrDefault(this.options.fontFamily, Chart.defaults.global.defaultFontFamily); + var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily); + + // Width + if (this.isHorizontal()) { + this.minSize.width = this.maxWidth; // fill all the width + } else { + this.minSize.width = 0; + } + + // height + if (this.isHorizontal()) { + this.minSize.height = 0; + } else { + this.minSize.height = this.maxHeight; // fill all the height + } + + // Increase sizes here + if (this.isHorizontal()) { + + // Title + if (this.options.display) { + this.minSize.height += fontSize + (this.options.padding * 2); + } + } else { + if (this.options.display) { + this.minSize.width += fontSize + (this.options.padding * 2); + } + } + + this.width = this.minSize.width; + this.height = this.minSize.height; + + }, + afterFit: helpers.noop, + + // Shared Methods + isHorizontal: function() { + return this.options.position === "top" || this.options.position === "bottom"; + }, + + // Actualy draw the title block on the canvas + draw: function() { + if (this.options.display) { + var ctx = this.ctx; + var titleX, titleY; + + var fontColor = helpers.getValueOrDefault(this.options.fontColor, Chart.defaults.global.defaultFontColor); + var fontSize = helpers.getValueOrDefault(this.options.fontSize, Chart.defaults.global.defaultFontSize); + var fontStyle = helpers.getValueOrDefault(this.options.fontStyle, Chart.defaults.global.defaultFontStyle); + var fontFamily = helpers.getValueOrDefault(this.options.fontFamily, Chart.defaults.global.defaultFontFamily); + var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily); + + ctx.fillStyle = fontColor; // render in correct colour + ctx.font = titleFont; + + // Horizontal + if (this.isHorizontal()) { + // Title + ctx.textAlign = "center"; + ctx.textBaseline = 'middle'; + + titleX = this.left + ((this.right - this.left) / 2); // midpoint of the width + titleY = this.top + ((this.bottom - this.top) / 2); // midpoint of the height + + ctx.fillText(this.options.text, titleX, titleY); + } else { + + // Title + titleX = this.options.position === 'left' ? this.left + (fontSize / 2) : this.right - (fontSize / 2); + titleY = this.top + ((this.bottom - this.top) / 2); + var rotation = this.options.position === 'left' ? -0.5 * Math.PI : 0.5 * Math.PI; + + ctx.save(); + ctx.translate(titleX, titleY); + ctx.rotate(rotation); + ctx.textAlign = "center"; + ctx.textBaseline = 'middle'; + ctx.fillText(this.options.text, 0, 0); + ctx.restore(); + } + } + } + }); +}; +},{}],32:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.global.tooltips = { + enabled: true, + custom: null, + mode: 'single', + backgroundColor: "rgba(0,0,0,0.8)", + titleFontStyle: "bold", + titleSpacing: 2, + titleMarginBottom: 6, + titleColor: "#fff", + titleAlign: "left", + bodySpacing: 2, + bodyColor: "#fff", + bodyAlign: "left", + footerFontStyle: "bold", + footerSpacing: 2, + footerMarginTop: 6, + footerColor: "#fff", + footerAlign: "left", + yPadding: 6, + xPadding: 6, + yAlign : 'center', + xAlign : 'center', + caretSize: 5, + cornerRadius: 6, + multiKeyBackground: '#fff', + callbacks: { + // Args are: (tooltipItems, data) + beforeTitle: helpers.noop, + title: function(tooltipItems, data) { + // Pick first xLabel for now + var title = ''; + + if (tooltipItems.length > 0) { + if (tooltipItems[0].xLabel) { + title = tooltipItems[0].xLabel; + } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) { + title = data.labels[tooltipItems[0].index]; + } + } + + return title; + }, + afterTitle: helpers.noop, + + // Args are: (tooltipItems, data) + beforeBody: helpers.noop, + + // Args are: (tooltipItem, data) + beforeLabel: helpers.noop, + label: function(tooltipItem, data) { + var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || ''; + return datasetLabel + ': ' + tooltipItem.yLabel; + }, + afterLabel: helpers.noop, + + // Args are: (tooltipItems, data) + afterBody: helpers.noop, + + // Args are: (tooltipItems, data) + beforeFooter: helpers.noop, + footer: helpers.noop, + afterFooter: helpers.noop + } + }; + + // Helper to push or concat based on if the 2nd parameter is an array or not + function pushOrConcat(base, toPush) { + if (toPush) { + if (helpers.isArray(toPush)) { + base = base.concat(toPush); + } else { + base.push(toPush); + } + } + + return base; + } + + Chart.Tooltip = Chart.Element.extend({ + initialize: function() { + var options = this._options; + helpers.extend(this, { + _model: { + // Positioning + xPadding: options.tooltips.xPadding, + yPadding: options.tooltips.yPadding, + xAlign : options.tooltips.yAlign, + yAlign : options.tooltips.xAlign, + + // Body + bodyColor: options.tooltips.bodyColor, + _bodyFontFamily: helpers.getValueOrDefault(options.tooltips.bodyFontFamily, Chart.defaults.global.defaultFontFamily), + _bodyFontStyle: helpers.getValueOrDefault(options.tooltips.bodyFontStyle, Chart.defaults.global.defaultFontStyle), + _bodyAlign: options.tooltips.bodyAlign, + bodyFontSize: helpers.getValueOrDefault(options.tooltips.bodyFontSize, Chart.defaults.global.defaultFontSize), + bodySpacing: options.tooltips.bodySpacing, + + // Title + titleColor: options.tooltips.titleColor, + _titleFontFamily: helpers.getValueOrDefault(options.tooltips.titleFontFamily, Chart.defaults.global.defaultFontFamily), + _titleFontStyle: helpers.getValueOrDefault(options.tooltips.titleFontStyle, Chart.defaults.global.defaultFontStyle), + titleFontSize: helpers.getValueOrDefault(options.tooltips.titleFontSize, Chart.defaults.global.defaultFontSize), + _titleAlign: options.tooltips.titleAlign, + titleSpacing: options.tooltips.titleSpacing, + titleMarginBottom: options.tooltips.titleMarginBottom, + + // Footer + footerColor: options.tooltips.footerColor, + _footerFontFamily: helpers.getValueOrDefault(options.tooltips.footerFontFamily, Chart.defaults.global.defaultFontFamily), + _footerFontStyle: helpers.getValueOrDefault(options.tooltips.footerFontStyle, Chart.defaults.global.defaultFontStyle), + footerFontSize: helpers.getValueOrDefault(options.tooltips.footerFontSize, Chart.defaults.global.defaultFontSize), + _footerAlign: options.tooltips.footerAlign, + footerSpacing: options.tooltips.footerSpacing, + footerMarginTop: options.tooltips.footerMarginTop, + + // Appearance + caretSize: options.tooltips.caretSize, + cornerRadius: options.tooltips.cornerRadius, + backgroundColor: options.tooltips.backgroundColor, + opacity: 0, + legendColorBackground: options.tooltips.multiKeyBackground + } + }); + }, + + // Get the title + // Args are: (tooltipItem, data) + getTitle: function() { + var beforeTitle = this._options.tooltips.callbacks.beforeTitle.apply(this, arguments), + title = this._options.tooltips.callbacks.title.apply(this, arguments), + afterTitle = this._options.tooltips.callbacks.afterTitle.apply(this, arguments); + + var lines = []; + lines = pushOrConcat(lines, beforeTitle); + lines = pushOrConcat(lines, title); + lines = pushOrConcat(lines, afterTitle); + + return lines; + }, + + // Args are: (tooltipItem, data) + getBeforeBody: function() { + var lines = this._options.tooltips.callbacks.beforeBody.apply(this, arguments); + return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : []; + }, + + // Args are: (tooltipItem, data) + getBody: function(tooltipItems, data) { + var lines = []; + + helpers.each(tooltipItems, function(bodyItem) { + helpers.pushAllIfDefined(this._options.tooltips.callbacks.beforeLabel.call(this, bodyItem, data), lines); + helpers.pushAllIfDefined(this._options.tooltips.callbacks.label.call(this, bodyItem, data), lines); + helpers.pushAllIfDefined(this._options.tooltips.callbacks.afterLabel.call(this, bodyItem, data), lines); + }, this); + + return lines; + }, + + // Args are: (tooltipItem, data) + getAfterBody: function() { + var lines = this._options.tooltips.callbacks.afterBody.apply(this, arguments); + return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : []; + }, + + // Get the footer and beforeFooter and afterFooter lines + // Args are: (tooltipItem, data) + getFooter: function() { + var beforeFooter = this._options.tooltips.callbacks.beforeFooter.apply(this, arguments); + var footer = this._options.tooltips.callbacks.footer.apply(this, arguments); + var afterFooter = this._options.tooltips.callbacks.afterFooter.apply(this, arguments); + + var lines = []; + lines = pushOrConcat(lines, beforeFooter); + lines = pushOrConcat(lines, footer); + lines = pushOrConcat(lines, afterFooter); + + return lines; + }, + + getAveragePosition: function(elements) { + + if (!elements.length) { + return false; + } + + var xPositions = []; + var yPositions = []; + + helpers.each(elements, function(el) { + if (el) { + var pos = el.tooltipPosition(); + xPositions.push(pos.x); + yPositions.push(pos.y); + } + }); + + var x = 0, + y = 0; + for (var i = 0; i < xPositions.length; i++) { + x += xPositions[i]; + y += yPositions[i]; + } + + return { + x: Math.round(x / xPositions.length), + y: Math.round(y / xPositions.length) + }; + + }, + + update: function(changed) { + if (this._active.length) { + this._model.opacity = 1; + + var element = this._active[0], + labelColors = [], + tooltipPosition; + + var tooltipItems = []; + + if (this._options.tooltips.mode === 'single') { + var yScale = element._yScale || element._scale; // handle radar || polarArea charts + tooltipItems.push({ + xLabel: element._xScale ? element._xScale.getLabelForIndex(element._index, element._datasetIndex) : '', + yLabel: yScale ? yScale.getLabelForIndex(element._index, element._datasetIndex) : '', + index: element._index, + datasetIndex: element._datasetIndex + }); + tooltipPosition = this.getAveragePosition(this._active); + } else { + helpers.each(this._data.datasets, function(dataset, datasetIndex) { + if (!helpers.isDatasetVisible(dataset)) { + return; + } + var currentElement = dataset.metaData[element._index]; + if (currentElement) { + var yScale = element._yScale || element._scale; // handle radar || polarArea charts + + tooltipItems.push({ + xLabel: currentElement._xScale ? currentElement._xScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '', + yLabel: yScale ? yScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '', + index: element._index, + datasetIndex: datasetIndex + }); + } + }, null, element._yScale.options.stacked); + + helpers.each(this._active, function(active) { + if (active) { + labelColors.push({ + borderColor: active._view.borderColor, + backgroundColor: active._view.backgroundColor + }); + } + }, null, element._yScale.options.stacked); + + tooltipPosition = this.getAveragePosition(this._active); + tooltipPosition.y = this._active[0]._yScale.getPixelForDecimal(0.5); + } + + // Build the Text Lines + helpers.extend(this._model, { + title: this.getTitle(tooltipItems, this._data), + beforeBody: this.getBeforeBody(tooltipItems, this._data), + body: this.getBody(tooltipItems, this._data), + afterBody: this.getAfterBody(tooltipItems, this._data), + footer: this.getFooter(tooltipItems, this._data) + }); + + helpers.extend(this._model, { + x: Math.round(tooltipPosition.x), + y: Math.round(tooltipPosition.y), + caretPadding: helpers.getValueOrDefault(tooltipPosition.padding, 2), + labelColors: labelColors + }); + + // We need to determine alignment of + var tooltipSize = this.getTooltipSize(this._model); + this.determineAlignment(tooltipSize); // Smart Tooltip placement to stay on the canvas + + helpers.extend(this._model, this.getBackgroundPoint(this._model, tooltipSize)); + } else { + this._model.opacity = 0; + } + + if (changed && this._options.tooltips.custom) { + this._options.tooltips.custom.call(this, this._model); + } + + return this; + }, + getTooltipSize: function getTooltipSize(vm) { + var ctx = this._chart.ctx; + + var size = { + height: vm.yPadding * 2, // Tooltip Padding + width: 0 + }; + var combinedBodyLength = vm.body.length + vm.beforeBody.length + vm.afterBody.length; + + size.height += vm.title.length * vm.titleFontSize; // Title Lines + size.height += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing + size.height += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin + size.height += combinedBodyLength * vm.bodyFontSize; // Body Lines + size.height += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing + size.height += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin + size.height += vm.footer.length * (vm.footerFontSize); // Footer Lines + size.height += vm.footer.length ? (vm.footer.length - 1) * vm.footerSpacing : 0; // Footer Line Spacing + + // Width + ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily); + helpers.each(vm.title, function(line) { + size.width = Math.max(size.width, ctx.measureText(line).width); + }); + + ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); + helpers.each(vm.beforeBody.concat(vm.afterBody), function(line) { + size.width = Math.max(size.width, ctx.measureText(line).width); + }); + helpers.each(vm.body, function(line) { + size.width = Math.max(size.width, ctx.measureText(line).width + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0)); + }, this); + + ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily); + helpers.each(vm.footer, function(line) { + size.width = Math.max(size.width, ctx.measureText(line).width); + }); + size.width += 2 * vm.xPadding; + + return size; + }, + determineAlignment: function determineAlignment(size) { + if (this._model.y < size.height) { + this._model.yAlign = 'top'; + } else if (this._model.y > (this._chart.height - size.height)) { + this._model.yAlign = 'bottom'; + } + + var lf, rf; // functions to determine left, right alignment + var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart + var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges + var _this = this; + var midX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2; + var midY = (this._chartInstance.chartArea.top + this._chartInstance.chartArea.bottom) / 2; + + if (this._model.yAlign === 'center') { + lf = function(x) { + return x <= midX; + }; + rf = function(x) { + return x > midX; + }; + } else { + lf = function(x) { + return x <= (size.width / 2); + }; + rf = function(x) { + return x >= (_this._chart.width - (size.width / 2)); + }; + } + + olf = function(x) { + return x + size.width > _this._chart.width; + }; + orf = function(x) { + return x - size.width < 0; + }; + yf = function(y) { + return y <= midY ? 'top' : 'bottom'; + }; + + if (lf(this._model.x)) { + this._model.xAlign = 'left'; + + // Is tooltip too wide and goes over the right side of the chart.? + if (olf(this._model.x)) { + this._model.xAlign = 'center'; + this._model.yAlign = yf(this._model.y); + } + } else if (rf(this._model.x)) { + this._model.xAlign = 'right'; + + // Is tooltip too wide and goes outside left edge of canvas? + if (orf(this._model.x)) { + this._model.xAlign = 'center'; + this._model.yAlign = yf(this._model.y); + } + } + }, + getBackgroundPoint: function getBackgroundPoint(vm, size) { + // Background Position + var pt = { + x: vm.x, + y: vm.y + }; + + if (vm.xAlign === 'right') { + pt.x -= size.width; + } else if (vm.xAlign === 'center') { + pt.x -= (size.width / 2); + } + + if (vm.yAlign === 'top') { + pt.y += vm.caretPadding + vm.caretSize; + } else if (vm.yAlign === 'bottom') { + pt.y -= size.height + vm.caretPadding + vm.caretSize; + } else { + pt.y -= (size.height / 2); + } + + if (vm.yAlign === 'center') { + if (vm.xAlign === 'left') { + pt.x += vm.caretPadding + vm.caretSize; + } else if (vm.xAlign === 'right') { + pt.x -= vm.caretPadding + vm.caretSize; + } + } else { + if (vm.xAlign === 'left') { + pt.x -= vm.cornerRadius + vm.caretPadding; + } else if (vm.xAlign === 'right') { + pt.x += vm.cornerRadius + vm.caretPadding; + } + } + + return pt; + }, + drawCaret: function drawCaret(tooltipPoint, size, opacity, caretPadding) { + var vm = this._view; + var ctx = this._chart.ctx; + var x1, x2, x3; + var y1, y2, y3; + + if (vm.yAlign === 'center') { + // Left or right side + if (vm.xAlign === 'left') { + x1 = tooltipPoint.x; + x2 = x1 - vm.caretSize; + x3 = x1; + } else { + x1 = tooltipPoint.x + size.width; + x2 = x1 + vm.caretSize; + x3 = x1; + } + + y2 = tooltipPoint.y + (size.height / 2); + y1 = y2 - vm.caretSize; + y3 = y2 + vm.caretSize; + } else { + if (vm.xAlign === 'left') { + x1 = tooltipPoint.x + vm.cornerRadius; + x2 = x1 + vm.caretSize; + x3 = x2 + vm.caretSize; + } else if (vm.xAlign === 'right') { + x1 = tooltipPoint.x + size.width - vm.cornerRadius; + x2 = x1 - vm.caretSize; + x3 = x2 - vm.caretSize; + } else { + x2 = tooltipPoint.x + (size.width / 2); + x1 = x2 - vm.caretSize; + x3 = x2 + vm.caretSize; + } + + if (vm.yAlign === 'top') { + y1 = tooltipPoint.y; + y2 = y1 - vm.caretSize; + y3 = y1; + } else { + y1 = tooltipPoint.y + size.height; + y2 = y1 + vm.caretSize; + y3 = y1; + } + } + + var bgColor = helpers.color(vm.backgroundColor); + ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString(); + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x3, y3); + ctx.closePath(); + ctx.fill(); + }, + drawTitle: function drawTitle(pt, vm, ctx, opacity) { + if (vm.title.length) { + ctx.textAlign = vm._titleAlign; + ctx.textBaseline = "top"; + + var titleColor = helpers.color(vm.titleColor); + ctx.fillStyle = titleColor.alpha(opacity * titleColor.alpha()).rgbString(); + ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily); + + helpers.each(vm.title, function(title, i) { + ctx.fillText(title, pt.x, pt.y); + pt.y += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing + + if (i + 1 === vm.title.length) { + pt.y += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing + } + }); + } + }, + drawBody: function drawBody(pt, vm, ctx, opacity) { + ctx.textAlign = vm._bodyAlign; + ctx.textBaseline = "top"; + + var bodyColor = helpers.color(vm.bodyColor); + ctx.fillStyle = bodyColor.alpha(opacity * bodyColor.alpha()).rgbString(); + ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); + + // Before Body + helpers.each(vm.beforeBody, function(beforeBody) { + ctx.fillText(beforeBody, pt.x, pt.y); + pt.y += vm.bodyFontSize + vm.bodySpacing; + }); + + helpers.each(vm.body, function(body, i) { + // Draw Legend-like boxes if needed + if (this._options.tooltips.mode !== 'single') { + // Fill a white rect so that colours merge nicely if the opacity is < 1 + ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString(); + ctx.fillRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize); + + // Border + ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString(); + ctx.strokeRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize); + + // Inner square + ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString(); + ctx.fillRect(pt.x + 1, pt.y + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2); + + ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text + } + + // Body Line + ctx.fillText(body, pt.x + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y); + + pt.y += vm.bodyFontSize + vm.bodySpacing; + }, this); + + // After Body + helpers.each(vm.afterBody, function(afterBody) { + ctx.fillText(afterBody, pt.x, pt.y); + pt.y += vm.bodyFontSize; + }); + + pt.y -= vm.bodySpacing; // Remove last body spacing + }, + drawFooter: function drawFooter(pt, vm, ctx, opacity) { + if (vm.footer.length) { + pt.y += vm.footerMarginTop; + + ctx.textAlign = vm._footerAlign; + ctx.textBaseline = "top"; + + var footerColor = helpers.color(vm.footerColor); + ctx.fillStyle = footerColor.alpha(opacity * footerColor.alpha()).rgbString(); + ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily); + + helpers.each(vm.footer, function(footer) { + ctx.fillText(footer, pt.x, pt.y); + pt.y += vm.footerFontSize + vm.footerSpacing; + }); + } + }, + draw: function draw() { + var ctx = this._chart.ctx; + var vm = this._view; + + if (vm.opacity === 0) { + return; + } + + var caretPadding = vm.caretPadding; + var tooltipSize = this.getTooltipSize(vm); + var pt = { + x: vm.x, + y: vm.y + }; + + // IE11/Edge does not like very small opacities, so snap to 0 + var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity; + + if (this._options.tooltips.enabled) { + // Draw Background + var bgColor = helpers.color(vm.backgroundColor); + ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString(); + helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius); + ctx.fill(); + + // Draw Caret + this.drawCaret(pt, tooltipSize, opacity, caretPadding); + + // Draw Title, Body, and Footer + pt.x += vm.xPadding; + pt.y += vm.yPadding; + + // Titles + this.drawTitle(pt, vm, ctx, opacity); + + // Body + this.drawBody(pt, vm, ctx, opacity); + + // Footer + this.drawFooter(pt, vm, ctx, opacity); + } + } + }); +}; + +},{}],33:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart, moment) { + + var helpers = Chart.helpers; + + Chart.defaults.global.elements.arc = { + backgroundColor: Chart.defaults.global.defaultColor, + borderColor: "#fff", + borderWidth: 2 + }; + + Chart.elements.Arc = Chart.Element.extend({ + inLabelRange: function(mouseX) { + var vm = this._view; + + if (vm) { + return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2)); + } else { + return false; + } + }, + inRange: function(chartX, chartY) { + + var vm = this._view; + + if (vm) { + var pointRelativePosition = helpers.getAngleFromPoint(vm, { + x: chartX, + y: chartY + }); + + // Put into the range of (-PI/2, 3PI/2] + var startAngle = vm.startAngle < (-0.5 * Math.PI) ? vm.startAngle + (2.0 * Math.PI) : vm.startAngle > (1.5 * Math.PI) ? vm.startAngle - (2.0 * Math.PI) : vm.startAngle; + var endAngle = vm.endAngle < (-0.5 * Math.PI) ? vm.endAngle + (2.0 * Math.PI) : vm.endAngle > (1.5 * Math.PI) ? vm.endAngle - (2.0 * Math.PI) : vm.endAngle; + + //Check if within the range of the open/close angle + var betweenAngles = (pointRelativePosition.angle >= startAngle && pointRelativePosition.angle <= endAngle), + withinRadius = (pointRelativePosition.distance >= vm.innerRadius && pointRelativePosition.distance <= vm.outerRadius); + + return (betweenAngles && withinRadius); + } else { + return false; + } + }, + tooltipPosition: function() { + var vm = this._view; + + var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2), + rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius; + return { + x: vm.x + (Math.cos(centreAngle) * rangeFromCentre), + y: vm.y + (Math.sin(centreAngle) * rangeFromCentre) + }; + }, + draw: function() { + + var ctx = this._chart.ctx; + var vm = this._view; + + ctx.beginPath(); + + ctx.arc(vm.x, vm.y, vm.outerRadius, vm.startAngle, vm.endAngle); + + ctx.arc(vm.x, vm.y, vm.innerRadius, vm.endAngle, vm.startAngle, true); + + ctx.closePath(); + ctx.strokeStyle = vm.borderColor; + ctx.lineWidth = vm.borderWidth; + + ctx.fillStyle = vm.backgroundColor; + + ctx.fill(); + ctx.lineJoin = 'bevel'; + + if (vm.borderWidth) { + ctx.stroke(); + } + } + }); +}; + +},{}],34:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.global.elements.line = { + tension: 0.4, + backgroundColor: Chart.defaults.global.defaultColor, + borderWidth: 3, + borderColor: Chart.defaults.global.defaultColor, + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: 'miter', + fill: true // do we fill in the area between the line and its base axis + }; + + Chart.elements.Line = Chart.Element.extend({ + lineToNextPoint: function(previousPoint, point, nextPoint, skipHandler, previousSkipHandler) { + var ctx = this._chart.ctx; + + if (point._view.skip) { + skipHandler.call(this, previousPoint, point, nextPoint); + } else if (previousPoint._view.skip) { + previousSkipHandler.call(this, previousPoint, point, nextPoint); + } else if (point._view.tension === 0) { + ctx.lineTo(point._view.x, point._view.y); + } else { + // Line between points + ctx.bezierCurveTo( + previousPoint._view.controlPointNextX, + previousPoint._view.controlPointNextY, + point._view.controlPointPreviousX, + point._view.controlPointPreviousY, + point._view.x, + point._view.y + ); + } + }, + + draw: function() { + var _this = this; + + var vm = this._view; + var ctx = this._chart.ctx; + var first = this._children[0]; + var last = this._children[this._children.length - 1]; + + function loopBackToStart(drawLineToCenter) { + if (!first._view.skip && !last._view.skip) { + // Draw a bezier line from last to first + ctx.bezierCurveTo( + last._view.controlPointNextX, + last._view.controlPointNextY, + first._view.controlPointPreviousX, + first._view.controlPointPreviousY, + first._view.x, + first._view.y + ); + } else if (drawLineToCenter) { + // Go to center + ctx.lineTo(_this._view.scaleZero.x, _this._view.scaleZero.y); + } + } + + ctx.save(); + + // If we had points and want to fill this line, do so. + if (this._children.length > 0 && vm.fill) { + // Draw the background first (so the border is always on top) + ctx.beginPath(); + + helpers.each(this._children, function(point, index) { + var previous = helpers.previousItem(this._children, index); + var next = helpers.nextItem(this._children, index); + + // First point moves to it's starting position no matter what + if (index === 0) { + if (this._loop) { + ctx.moveTo(vm.scaleZero.x, vm.scaleZero.y); + } else { + ctx.moveTo(point._view.x, vm.scaleZero); + } + + if (point._view.skip) { + if (!this._loop) { + ctx.moveTo(next._view.x, this._view.scaleZero); + } + } else { + ctx.lineTo(point._view.x, point._view.y); + } + } else { + this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) { + if (this._loop) { + // Go to center + ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y); + } else { + ctx.lineTo(previousPoint._view.x, this._view.scaleZero); + ctx.moveTo(nextPoint._view.x, this._view.scaleZero); + } + }, function(previousPoint, point) { + // If we skipped the last point, draw a line to ourselves so that the fill is nice + ctx.lineTo(point._view.x, point._view.y); + }); + } + }, this); + + // For radial scales, loop back around to the first point + if (this._loop) { + loopBackToStart(true); + } else { + //Round off the line by going to the base of the chart, back to the start, then fill. + ctx.lineTo(this._children[this._children.length - 1]._view.x, vm.scaleZero); + ctx.lineTo(this._children[0]._view.x, vm.scaleZero); + } + + ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor; + ctx.closePath(); + ctx.fill(); + } + + // Now draw the line between all the points with any borders + ctx.lineCap = vm.borderCapStyle || Chart.defaults.global.elements.line.borderCapStyle; + + // IE 9 and 10 do not support line dash + if (ctx.setLineDash) { + ctx.setLineDash(vm.borderDash || Chart.defaults.global.elements.line.borderDash); + } + + ctx.lineDashOffset = vm.borderDashOffset || Chart.defaults.global.elements.line.borderDashOffset; + ctx.lineJoin = vm.borderJoinStyle || Chart.defaults.global.elements.line.borderJoinStyle; + ctx.lineWidth = vm.borderWidth || Chart.defaults.global.elements.line.borderWidth; + ctx.strokeStyle = vm.borderColor || Chart.defaults.global.defaultColor; + ctx.beginPath(); + + helpers.each(this._children, function(point, index) { + var previous = helpers.previousItem(this._children, index); + var next = helpers.nextItem(this._children, index); + + if (index === 0) { + ctx.moveTo(point._view.x, point._view.y); + } else { + this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) { + ctx.moveTo(nextPoint._view.x, nextPoint._view.y); + }, function(previousPoint, point) { + // If we skipped the last point, move up to our point preventing a line from being drawn + ctx.moveTo(point._view.x, point._view.y); + }); + } + }, this); + + if (this._loop && this._children.length > 0) { + loopBackToStart(); + } + + ctx.stroke(); + ctx.restore(); + } + }); +}; +},{}],35:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.global.elements.point = { + radius: 3, + pointStyle: 'circle', + backgroundColor: Chart.defaults.global.defaultColor, + borderWidth: 1, + borderColor: Chart.defaults.global.defaultColor, + // Hover + hitRadius: 1, + hoverRadius: 4, + hoverBorderWidth: 1 + }; + + + Chart.elements.Point = Chart.Element.extend({ + inRange: function(mouseX, mouseY) { + var vm = this._view; + + if (vm) { + var hoverRange = vm.hitRadius + vm.radius; + return ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(hoverRange, 2)); + } else { + return false; + } + }, + inLabelRange: function(mouseX) { + var vm = this._view; + + if (vm) { + return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2)); + } else { + return false; + } + }, + tooltipPosition: function() { + var vm = this._view; + return { + x: vm.x, + y: vm.y, + padding: vm.radius + vm.borderWidth + }; + }, + draw: function() { + + var vm = this._view; + var ctx = this._chart.ctx; + + + if (vm.skip) { + return; + } + + if (typeof vm.pointStyle === 'object' && ((vm.pointStyle.toString() === '[object HTMLImageElement]') || (vm.pointStyle.toString() === '[object HTMLCanvasElement]'))) { + ctx.drawImage(vm.pointStyle, vm.x - vm.pointStyle.width / 2, vm.y - vm.pointStyle.height / 2); + return; + } + + if (!isNaN(vm.radius) && vm.radius > 0) { + + ctx.strokeStyle = vm.borderColor || Chart.defaults.global.defaultColor; + ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, Chart.defaults.global.elements.point.borderWidth); + + ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor; + + var radius = vm.radius; + + var xOffset; + var yOffset; + + switch (vm.pointStyle) { + // Default includes circle + default: ctx.beginPath(); + ctx.arc(vm.x, vm.y, radius, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); + break; + case 'triangle': + ctx.beginPath(); + var edgeLength = 3 * radius / Math.sqrt(3); + var height = edgeLength * Math.sqrt(3) / 2; + ctx.moveTo(vm.x - edgeLength / 2, vm.y + height / 3); + ctx.lineTo(vm.x + edgeLength / 2, vm.y + height / 3); + ctx.lineTo(vm.x, vm.y - 2 * height / 3); + ctx.closePath(); + ctx.fill(); + break; + case 'rect': + ctx.fillRect(vm.x - 1 / Math.SQRT2 * radius, vm.y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx.strokeRect(vm.x - 1 / Math.SQRT2 * radius, vm.y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + break; + case 'rectRot': + ctx.translate(vm.x, vm.y); + ctx.rotate(Math.PI / 4); + ctx.fillRect(-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx.strokeRect(-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx.setTransform(1, 0, 0, 1, 0, 0); + break; + case 'cross': + ctx.beginPath(); + ctx.moveTo(vm.x, vm.y + radius); + ctx.lineTo(vm.x, vm.y - radius); + ctx.moveTo(vm.x - radius, vm.y); + ctx.lineTo(vm.x + radius, vm.y); + ctx.closePath(); + break; + case 'crossRot': + ctx.beginPath(); + xOffset = Math.cos(Math.PI / 4) * radius; + yOffset = Math.sin(Math.PI / 4) * radius; + ctx.moveTo(vm.x - xOffset, vm.y - yOffset); + ctx.lineTo(vm.x + xOffset, vm.y + yOffset); + ctx.moveTo(vm.x - xOffset, vm.y + yOffset); + ctx.lineTo(vm.x + xOffset, vm.y - yOffset); + ctx.closePath(); + break; + case 'star': + ctx.beginPath(); + ctx.moveTo(vm.x, vm.y + radius); + ctx.lineTo(vm.x, vm.y - radius); + ctx.moveTo(vm.x - radius, vm.y); + ctx.lineTo(vm.x + radius, vm.y); + xOffset = Math.cos(Math.PI / 4) * radius; + yOffset = Math.sin(Math.PI / 4) * radius; + ctx.moveTo(vm.x - xOffset, vm.y - yOffset); + ctx.lineTo(vm.x + xOffset, vm.y + yOffset); + ctx.moveTo(vm.x - xOffset, vm.y + yOffset); + ctx.lineTo(vm.x + xOffset, vm.y - yOffset); + ctx.closePath(); + break; + case 'line': + ctx.beginPath(); + ctx.moveTo(vm.x - radius, vm.y); + ctx.lineTo(vm.x + radius, vm.y); + ctx.closePath(); + break; + case 'dash': + ctx.beginPath(); + ctx.moveTo(vm.x, vm.y); + ctx.lineTo(vm.x + radius, vm.y); + ctx.closePath(); + break; + } + + ctx.stroke(); + } + } + }); +}; +},{}],36:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.global.elements.rectangle = { + backgroundColor: Chart.defaults.global.defaultColor, + borderWidth: 0, + borderColor: Chart.defaults.global.defaultColor, + borderSkipped: 'bottom' + }; + + Chart.elements.Rectangle = Chart.Element.extend({ + draw: function() { + + var ctx = this._chart.ctx; + var vm = this._view; + + var halfWidth = vm.width / 2, + leftX = vm.x - halfWidth, + rightX = vm.x + halfWidth, + top = vm.base - (vm.base - vm.y), + halfStroke = vm.borderWidth / 2; + + // Canvas doesn't allow us to stroke inside the width so we can + // adjust the sizes to fit if we're setting a stroke on the line + if (vm.borderWidth) { + leftX += halfStroke; + rightX -= halfStroke; + top += halfStroke; + } + + ctx.beginPath(); + + ctx.fillStyle = vm.backgroundColor; + ctx.strokeStyle = vm.borderColor; + ctx.lineWidth = vm.borderWidth; + + // Corner points, from bottom-left to bottom-right clockwise + // | 1 2 | + // | 0 3 | + var corners = [ + [leftX, vm.base], + [leftX, top], + [rightX, top], + [rightX, vm.base] + ]; + + // Find first (starting) corner with fallback to 'bottom' + var borders = ['bottom', 'left', 'top', 'right']; + var startCorner = borders.indexOf(vm.borderSkipped, 0); + if (startCorner === -1) + startCorner = 0; + + function cornerAt(index) { + return corners[(startCorner + index) % 4]; + } + + // Draw rectangle from 'startCorner' + ctx.moveTo.apply(ctx, cornerAt(0)); + for (var i = 1; i < 4; i++) + ctx.lineTo.apply(ctx, cornerAt(i)); + + ctx.fill(); + if (vm.borderWidth) { + ctx.stroke(); + } + }, + height: function() { + var vm = this._view; + return vm.base - vm.y; + }, + inRange: function(mouseX, mouseY) { + var vm = this._view; + var inRange = false; + + if (vm) { + if (vm.y < vm.base) { + inRange = (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.y && mouseY <= vm.base); + } else { + inRange = (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.base && mouseY <= vm.y); + } + } + + return inRange; + }, + inLabelRange: function(mouseX) { + var vm = this._view; + + if (vm) { + return (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2); + } else { + return false; + } + }, + tooltipPosition: function() { + var vm = this._view; + return { + x: vm.x, + y: vm.y + }; + } + }); + +}; +},{}],37:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + // Default config for a category scale + var defaultConfig = { + position: "bottom" + }; + + var DatasetScale = Chart.Scale.extend({ + buildTicks: function(index) { + this.startIndex = 0; + this.endIndex = this.chart.data.labels.length; + var findIndex; + + if (this.options.ticks.min !== undefined) { + // user specified min value + findIndex = helpers.indexOf(this.chart.data.labels, this.options.ticks.min); + this.startIndex = findIndex !== -1 ? findIndex : this.startIndex; + } + + if (this.options.ticks.max !== undefined) { + // user specified max value + findIndex = helpers.indexOf(this.chart.data.labels, this.options.ticks.max); + this.endIndex = findIndex !== -1 ? findIndex : this.endIndex; + } + + // If we are viewing some subset of labels, slice the original array + this.ticks = (this.startIndex === 0 && this.endIndex === this.chart.data.labels.length) ? this.chart.data.labels : this.chart.data.labels.slice(this.startIndex, this.endIndex + 1); + }, + + getLabelForIndex: function(index, datasetIndex) { + return this.ticks[index]; + }, + + // Used to get data value locations. Value can either be an index or a numerical value + getPixelForValue: function(value, index, datasetIndex, includeOffset) { + // 1 is added because we need the length but we have the indexes + var offsetAmt = Math.max((this.ticks.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1); + + if (this.isHorizontal()) { + var innerWidth = this.width - (this.paddingLeft + this.paddingRight); + var valueWidth = innerWidth / offsetAmt; + var widthOffset = (valueWidth * (index - this.startIndex)) + this.paddingLeft; + + if (this.options.gridLines.offsetGridLines && includeOffset) { + widthOffset += (valueWidth / 2); + } + + return this.left + Math.round(widthOffset); + } else { + var innerHeight = this.height - (this.paddingTop + this.paddingBottom); + var valueHeight = innerHeight / offsetAmt; + var heightOffset = (valueHeight * (index - this.startIndex)) + this.paddingTop; + + if (this.options.gridLines.offsetGridLines && includeOffset) { + heightOffset += (valueHeight / 2); + } + + return this.top + Math.round(heightOffset); + } + }, + getPixelForTick: function(index, includeOffset) { + return this.getPixelForValue(this.ticks[index], index + this.startIndex, null, includeOffset); + } + }); + + Chart.scaleService.registerScaleType("category", DatasetScale, defaultConfig); + +}; +},{}],38:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + var defaultConfig = { + position: "left", + ticks: { + callback: function(tickValue, index, ticks) { + var delta = ticks[1] - ticks[0]; + + // If we have a number like 2.5 as the delta, figure out how many decimal places we need + if (Math.abs(delta) > 1) { + if (tickValue !== Math.floor(tickValue)) { + // not an integer + delta = tickValue - Math.floor(tickValue); + } + } + + var logDelta = helpers.log10(Math.abs(delta)); + var tickString = ''; + + if (tickValue !== 0) { + var numDecimal = -1 * Math.floor(logDelta); + numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places + tickString = tickValue.toFixed(numDecimal); + } else { + tickString = '0'; // never show decimal places for 0 + } + + return tickString; + } + } + }; + + var LinearScale = Chart.Scale.extend({ + determineDataLimits: function() { + // First Calculate the range + this.min = null; + this.max = null; + + if (this.options.stacked) { + var valuesPerType = {}; + var hasPositiveValues = false; + var hasNegativeValues = false; + + helpers.each(this.chart.data.datasets, function(dataset) { + if (valuesPerType[dataset.type] === undefined) { + valuesPerType[dataset.type] = { + positiveValues: [], + negativeValues: [] + }; + } + + // Store these per type + var positiveValues = valuesPerType[dataset.type].positiveValues; + var negativeValues = valuesPerType[dataset.type].negativeValues; + + if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) { + helpers.each(dataset.data, function(rawValue, index) { + + var value = +this.getRightValue(rawValue); + if (isNaN(value)) { + return; + } + + positiveValues[index] = positiveValues[index] || 0; + negativeValues[index] = negativeValues[index] || 0; + + if (this.options.relativePoints) { + positiveValues[index] = 100; + } else { + if (value < 0) { + hasNegativeValues = true; + negativeValues[index] += value; + } else { + hasPositiveValues = true; + positiveValues[index] += value; + } + } + }, this); + } + }, this); + + helpers.each(valuesPerType, function(valuesForType) { + var values = valuesForType.positiveValues.concat(valuesForType.negativeValues); + var minVal = helpers.min(values); + var maxVal = helpers.max(values); + this.min = this.min === null ? minVal : Math.min(this.min, minVal); + this.max = this.max === null ? maxVal : Math.max(this.max, maxVal); + }, this); + + } else { + helpers.each(this.chart.data.datasets, function(dataset) { + if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) { + helpers.each(dataset.data, function(rawValue, index) { + var value = +this.getRightValue(rawValue); + if (isNaN(value)) { + return; + } + + if (this.min === null) { + this.min = value; + } else if (value < this.min) { + this.min = value; + } + + if (this.max === null) { + this.max = value; + } else if (value > this.max) { + this.max = value; + } + }, this); + } + }, this); + } + + // If we are forcing it to begin at 0, but 0 will already be rendered on the chart, + // do nothing since that would make the chart weird. If the user really wants a weird chart + // axis, they can manually override it + if (this.options.ticks.beginAtZero) { + var minSign = helpers.sign(this.min); + var maxSign = helpers.sign(this.max); + + if (minSign < 0 && maxSign < 0) { + // move the top up to 0 + this.max = 0; + } else if (minSign > 0 && maxSign > 0) { + // move the botttom down to 0 + this.min = 0; + } + } + + if (this.options.ticks.min !== undefined) { + this.min = this.options.ticks.min; + } else if (this.options.ticks.suggestedMin !== undefined) { + this.min = Math.min(this.min, this.options.ticks.suggestedMin); + } + + if (this.options.ticks.max !== undefined) { + this.max = this.options.ticks.max; + } else if (this.options.ticks.suggestedMax !== undefined) { + this.max = Math.max(this.max, this.options.ticks.suggestedMax); + } + + if (this.min === this.max) { + this.min--; + this.max++; + } + }, + buildTicks: function() { + + // Then calulate the ticks + this.ticks = []; + + // Figure out what the max number of ticks we can support it is based on the size of + // the axis area. For now, we say that the minimum tick spacing in pixels must be 50 + // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on + // the graph + + var maxTicks; + + if (this.isHorizontal()) { + maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11, Math.ceil(this.width / 50)); + } else { + // The factor of 2 used to scale the font size has been experimentally determined. + var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); + maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11, Math.ceil(this.height / (2 * tickFontSize))); + } + + // Make sure we always have at least 2 ticks + maxTicks = Math.max(2, maxTicks); + + // To get a "nice" value for the tick spacing, we will use the appropriately named + // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks + // for details. + + var spacing; + var fixedStepSizeSet = (this.options.ticks.fixedStepSize && this.options.ticks.fixedStepSize > 0) || (this.options.ticks.stepSize && this.options.ticks.stepSize > 0); + if (fixedStepSizeSet) { + spacing = helpers.getValueOrDefault(this.options.ticks.fixedStepSize, this.options.ticks.stepSize); + } else { + var niceRange = helpers.niceNum(this.max - this.min, false); + spacing = helpers.niceNum(niceRange / (maxTicks - 1), true); + } + var niceMin = Math.floor(this.min / spacing) * spacing; + var niceMax = Math.ceil(this.max / spacing) * spacing; + var numSpaces = (niceMax - niceMin) / spacing; + + // If very close to our rounded value, use it. + if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { + numSpaces = Math.round(numSpaces); + } else { + numSpaces = Math.ceil(numSpaces); + } + + // Put the values into the ticks array + this.ticks.push(this.options.ticks.min !== undefined ? this.options.ticks.min : niceMin); + for (var j = 1; j < numSpaces; ++j) { + this.ticks.push(niceMin + (j * spacing)); + } + this.ticks.push(this.options.ticks.max !== undefined ? this.options.ticks.max : niceMax); + + if (this.options.position === "left" || this.options.position === "right") { + // We are in a vertical orientation. The top value is the highest. So reverse the array + this.ticks.reverse(); + } + + // At this point, we need to update our max and min given the tick values since we have expanded the + // range of the scale + this.max = helpers.max(this.ticks); + this.min = helpers.min(this.ticks); + + if (this.options.ticks.reverse) { + this.ticks.reverse(); + + this.start = this.max; + this.end = this.min; + } else { + this.start = this.min; + this.end = this.max; + } + }, + getLabelForIndex: function(index, datasetIndex) { + return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); + }, + convertTicksToLabels: function() { + this.ticksAsNumbers = this.ticks.slice(); + this.zeroLineIndex = this.ticks.indexOf(0); + + Chart.Scale.prototype.convertTicksToLabels.call(this); + }, + // Utils + getPixelForValue: function(value, index, datasetIndex, includeOffset) { + // This must be called after fit has been run so that + // this.left, this.top, this.right, and this.bottom have been defined + var rightValue = +this.getRightValue(value); + var pixel; + var range = this.end - this.start; + + if (this.isHorizontal()) { + var innerWidth = this.width - (this.paddingLeft + this.paddingRight); + pixel = this.left + (innerWidth / range * (rightValue - this.start)); + return Math.round(pixel + this.paddingLeft); + } else { + var innerHeight = this.height - (this.paddingTop + this.paddingBottom); + pixel = (this.bottom - this.paddingBottom) - (innerHeight / range * (rightValue - this.start)); + return Math.round(pixel); + } + }, + getPixelForTick: function(index, includeOffset) { + return this.getPixelForValue(this.ticksAsNumbers[index], null, null, includeOffset); + } + }); + Chart.scaleService.registerScaleType("linear", LinearScale, defaultConfig); + +}; +},{}],39:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + var defaultConfig = { + position: "left", + + // label settings + ticks: { + callback: function(value, index, arr) { + var remain = value / (Math.pow(10, Math.floor(Chart.helpers.log10(value)))); + + if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === arr.length - 1) { + return value.toExponential(); + } else { + return ''; + } + } + } + }; + + var LogarithmicScale = Chart.Scale.extend({ + determineDataLimits: function() { + // Calculate Range + this.min = null; + this.max = null; + + if (this.options.stacked) { + var valuesPerType = {}; + + helpers.each(this.chart.data.datasets, function(dataset) { + if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) { + if (valuesPerType[dataset.type] === undefined) { + valuesPerType[dataset.type] = []; + } + + helpers.each(dataset.data, function(rawValue, index) { + var values = valuesPerType[dataset.type]; + var value = +this.getRightValue(rawValue); + if (isNaN(value)) { + return; + } + + values[index] = values[index] || 0; + + if (this.options.relativePoints) { + values[index] = 100; + } else { + // Don't need to split positive and negative since the log scale can't handle a 0 crossing + values[index] += value; + } + }, this); + } + }, this); + + helpers.each(valuesPerType, function(valuesForType) { + var minVal = helpers.min(valuesForType); + var maxVal = helpers.max(valuesForType); + this.min = this.min === null ? minVal : Math.min(this.min, minVal); + this.max = this.max === null ? maxVal : Math.max(this.max, maxVal); + }, this); + + } else { + helpers.each(this.chart.data.datasets, function(dataset) { + if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) { + helpers.each(dataset.data, function(rawValue, index) { + var value = +this.getRightValue(rawValue); + if (isNaN(value)) { + return; + } + + if (this.min === null) { + this.min = value; + } else if (value < this.min) { + this.min = value; + } + + if (this.max === null) { + this.max = value; + } else if (value > this.max) { + this.max = value; + } + }, this); + } + }, this); + } + + this.min = this.options.ticks.min !== undefined ? this.options.ticks.min : this.min; + this.max = this.options.ticks.max !== undefined ? this.options.ticks.max : this.max; + + if (this.min === this.max) { + if (this.min !== 0 && this.min !== null) { + this.min = Math.pow(10, Math.floor(helpers.log10(this.min)) - 1); + this.max = Math.pow(10, Math.floor(helpers.log10(this.max)) + 1); + } else { + this.min = 1; + this.max = 10; + } + } + }, + buildTicks: function() { + // Reset the ticks array. Later on, we will draw a grid line at these positions + // The array simply contains the numerical value of the spots where ticks will be + this.ticks = []; + + // Figure out what the max number of ticks we can support it is based on the size of + // the axis area. For now, we say that the minimum tick spacing in pixels must be 50 + // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on + // the graph + + var tickVal = this.options.ticks.min !== undefined ? this.options.ticks.min : Math.pow(10, Math.floor(helpers.log10(this.min))); + + while (tickVal < this.max) { + this.ticks.push(tickVal); + + var exp = Math.floor(helpers.log10(tickVal)); + var significand = Math.floor(tickVal / Math.pow(10, exp)) + 1; + + if (significand === 10) { + significand = 1; + ++exp; + } + + tickVal = significand * Math.pow(10, exp); + } + + var lastTick = this.options.ticks.max !== undefined ? this.options.ticks.max : tickVal; + this.ticks.push(lastTick); + + if (this.options.position === "left" || this.options.position === "right") { + // We are in a vertical orientation. The top value is the highest. So reverse the array + this.ticks.reverse(); + } + + // At this point, we need to update our max and min given the tick values since we have expanded the + // range of the scale + this.max = helpers.max(this.ticks); + this.min = helpers.min(this.ticks); + + if (this.options.ticks.reverse) { + this.ticks.reverse(); + + this.start = this.max; + this.end = this.min; + } else { + this.start = this.min; + this.end = this.max; + } + }, + convertTicksToLabels: function() { + this.tickValues = this.ticks.slice(); + + Chart.Scale.prototype.convertTicksToLabels.call(this); + }, + // Get the correct tooltip label + getLabelForIndex: function(index, datasetIndex) { + return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); + }, + getPixelForTick: function(index, includeOffset) { + return this.getPixelForValue(this.tickValues[index], null, null, includeOffset); + }, + getPixelForValue: function(value, index, datasetIndex, includeOffset) { + var pixel; + + var newVal = +this.getRightValue(value); + var range = helpers.log10(this.end) - helpers.log10(this.start); + + if (this.isHorizontal()) { + + if (newVal === 0) { + pixel = this.left + this.paddingLeft; + } else { + var innerWidth = this.width - (this.paddingLeft + this.paddingRight); + pixel = this.left + (innerWidth / range * (helpers.log10(newVal) - helpers.log10(this.start))); + pixel += this.paddingLeft; + } + } else { + // Bottom - top since pixels increase downard on a screen + if (newVal === 0) { + pixel = this.top + this.paddingTop; + } else { + var innerHeight = this.height - (this.paddingTop + this.paddingBottom); + pixel = (this.bottom - this.paddingBottom) - (innerHeight / range * (helpers.log10(newVal) - helpers.log10(this.start))); + } + } + + return pixel; + } + + }); + Chart.scaleService.registerScaleType("logarithmic", LogarithmicScale, defaultConfig); + +}; +},{}],40:[function(require,module,exports){ +"use strict"; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + var defaultConfig = { + display: true, + + //Boolean - Whether to animate scaling the chart from the centre + animate: true, + lineArc: false, + position: "chartArea", + + angleLines: { + display: true, + color: "rgba(0, 0, 0, 0.1)", + lineWidth: 1 + }, + + // label settings + ticks: { + //Boolean - Show a backdrop to the scale label + showLabelBackdrop: true, + + //String - The colour of the label backdrop + backdropColor: "rgba(255,255,255,0.75)", + + //Number - The backdrop padding above & below the label in pixels + backdropPaddingY: 2, + + //Number - The backdrop padding to the side of the label in pixels + backdropPaddingX: 2 + }, + + pointLabels: { + //Number - Point label font size in pixels + fontSize: 10, + + //Function - Used to convert point labels + callback: function(label) { + return label; + } + } + }; + + var LinearRadialScale = Chart.Scale.extend({ + getValueCount: function() { + return this.chart.data.labels.length; + }, + setDimensions: function() { + // Set the unconstrained dimension before label rotation + this.width = this.maxWidth; + this.height = this.maxHeight; + this.xCenter = Math.round(this.width / 2); + this.yCenter = Math.round(this.height / 2); + + var minSize = helpers.min([this.height, this.width]); + var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); + this.drawingArea = (this.options.display) ? (minSize / 2) - (tickFontSize / 2 + this.options.ticks.backdropPaddingY) : (minSize / 2); + }, + determineDataLimits: function() { + this.min = null; + this.max = null; + + helpers.each(this.chart.data.datasets, function(dataset) { + if (helpers.isDatasetVisible(dataset)) { + helpers.each(dataset.data, function(rawValue, index) { + var value = +this.getRightValue(rawValue); + if (isNaN(value)) { + return; + } + + if (this.min === null) { + this.min = value; + } else if (value < this.min) { + this.min = value; + } + + if (this.max === null) { + this.max = value; + } else if (value > this.max) { + this.max = value; + } + }, this); + } + }, this); + + // If we are forcing it to begin at 0, but 0 will already be rendered on the chart, + // do nothing since that would make the chart weird. If the user really wants a weird chart + // axis, they can manually override it + if (this.options.ticks.beginAtZero) { + var minSign = helpers.sign(this.min); + var maxSign = helpers.sign(this.max); + + if (minSign < 0 && maxSign < 0) { + // move the top up to 0 + this.max = 0; + } else if (minSign > 0 && maxSign > 0) { + // move the botttom down to 0 + this.min = 0; + } + } + + if (this.options.ticks.min !== undefined) { + this.min = this.options.ticks.min; + } else if (this.options.ticks.suggestedMin !== undefined) { + this.min = Math.min(this.min, this.options.ticks.suggestedMin); + } + + if (this.options.ticks.max !== undefined) { + this.max = this.options.ticks.max; + } else if (this.options.ticks.suggestedMax !== undefined) { + this.max = Math.max(this.max, this.options.ticks.suggestedMax); + } + + if (this.min === this.max) { + this.min--; + this.max++; + } + }, + buildTicks: function() { + + + this.ticks = []; + + // Figure out what the max number of ticks we can support it is based on the size of + // the axis area. For now, we say that the minimum tick spacing in pixels must be 50 + // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on + // the graph + var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); + var maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize))); + maxTicks = Math.max(2, maxTicks); // Make sure we always have at least 2 ticks + + // To get a "nice" value for the tick spacing, we will use the appropriately named + // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks + // for details. + + var niceRange = helpers.niceNum(this.max - this.min, false); + var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true); + var niceMin = Math.floor(this.min / spacing) * spacing; + var niceMax = Math.ceil(this.max / spacing) * spacing; + + var numSpaces = Math.ceil((niceMax - niceMin) / spacing); + + // Put the values into the ticks array + this.ticks.push(this.options.ticks.min !== undefined ? this.options.ticks.min : niceMin); + for (var j = 1; j < numSpaces; ++j) { + this.ticks.push(niceMin + (j * spacing)); + } + this.ticks.push(this.options.ticks.max !== undefined ? this.options.ticks.max : niceMax); + + // At this point, we need to update our max and min given the tick values since we have expanded the + // range of the scale + this.max = helpers.max(this.ticks); + this.min = helpers.min(this.ticks); + + if (this.options.ticks.reverse) { + this.ticks.reverse(); + + this.start = this.max; + this.end = this.min; + } else { + this.start = this.min; + this.end = this.max; + } + + this.zeroLineIndex = this.ticks.indexOf(0); + }, + convertTicksToLabels: function() { + Chart.Scale.prototype.convertTicksToLabels.call(this); + + // Point labels + this.pointLabels = this.chart.data.labels.map(this.options.pointLabels.callback, this); + }, + getLabelForIndex: function(index, datasetIndex) { + return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); + }, + fit: function() { + /* + * Right, this is really confusing and there is a lot of maths going on here + * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9 + * + * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif + * + * Solution: + * + * We assume the radius of the polygon is half the size of the canvas at first + * at each index we check if the text overlaps. + * + * Where it does, we store that angle and that index. + * + * After finding the largest index and angle we calculate how much we need to remove + * from the shape radius to move the point inwards by that x. + * + * We average the left and right distances to get the maximum shape radius that can fit in the box + * along with labels. + * + * Once we have that, we can find the centre point for the chart, by taking the x text protrusion + * on each side, removing that from the size, halving it and adding the left x protrusion width. + * + * This will mean we have a shape fitted to the canvas, as large as it can be with the labels + * and position it in the most space efficient manner + * + * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif + */ + + var pointLabelFontSize = helpers.getValueOrDefault(this.options.pointLabels.fontSize, Chart.defaults.global.defaultFontSize); + var pointLabeFontStyle = helpers.getValueOrDefault(this.options.pointLabels.fontStyle, Chart.defaults.global.defaultFontStyle); + var pointLabeFontFamily = helpers.getValueOrDefault(this.options.pointLabels.fontFamily, Chart.defaults.global.defaultFontFamily); + var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily); + + // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width. + // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points + var largestPossibleRadius = helpers.min([(this.height / 2 - pointLabelFontSize - 5), this.width / 2]), + pointPosition, + i, + textWidth, + halfTextWidth, + furthestRight = this.width, + furthestRightIndex, + furthestRightAngle, + furthestLeft = 0, + furthestLeftIndex, + furthestLeftAngle, + xProtrusionLeft, + xProtrusionRight, + radiusReductionRight, + radiusReductionLeft, + maxWidthRadius; + this.ctx.font = pointLabeFont; + + for (i = 0; i < this.getValueCount(); i++) { + // 5px to space the text slightly out - similar to what we do in the draw function. + pointPosition = this.getPointPosition(i, largestPossibleRadius); + textWidth = this.ctx.measureText(this.pointLabels[i] ? this.pointLabels[i] : '').width + 5; + if (i === 0 || i === this.getValueCount() / 2) { + // If we're at index zero, or exactly the middle, we're at exactly the top/bottom + // of the radar chart, so text will be aligned centrally, so we'll half it and compare + // w/left and right text sizes + halfTextWidth = textWidth / 2; + if (pointPosition.x + halfTextWidth > furthestRight) { + furthestRight = pointPosition.x + halfTextWidth; + furthestRightIndex = i; + } + if (pointPosition.x - halfTextWidth < furthestLeft) { + furthestLeft = pointPosition.x - halfTextWidth; + furthestLeftIndex = i; + } + } else if (i < this.getValueCount() / 2) { + // Less than half the values means we'll left align the text + if (pointPosition.x + textWidth > furthestRight) { + furthestRight = pointPosition.x + textWidth; + furthestRightIndex = i; + } + } else if (i > this.getValueCount() / 2) { + // More than half the values means we'll right align the text + if (pointPosition.x - textWidth < furthestLeft) { + furthestLeft = pointPosition.x - textWidth; + furthestLeftIndex = i; + } + } + } + + xProtrusionLeft = furthestLeft; + xProtrusionRight = Math.ceil(furthestRight - this.width); + + furthestRightAngle = this.getIndexAngle(furthestRightIndex); + furthestLeftAngle = this.getIndexAngle(furthestLeftIndex); + + radiusReductionRight = xProtrusionRight / Math.sin(furthestRightAngle + Math.PI / 2); + radiusReductionLeft = xProtrusionLeft / Math.sin(furthestLeftAngle + Math.PI / 2); + + // Ensure we actually need to reduce the size of the chart + radiusReductionRight = (helpers.isNumber(radiusReductionRight)) ? radiusReductionRight : 0; + radiusReductionLeft = (helpers.isNumber(radiusReductionLeft)) ? radiusReductionLeft : 0; + + this.drawingArea = Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2); + this.setCenterPoint(radiusReductionLeft, radiusReductionRight); + }, + setCenterPoint: function(leftMovement, rightMovement) { + + var maxRight = this.width - rightMovement - this.drawingArea, + maxLeft = leftMovement + this.drawingArea; + + this.xCenter = Math.round(((maxLeft + maxRight) / 2) + this.left); + // Always vertically in the centre as the text height doesn't change + this.yCenter = Math.round((this.height / 2) + this.top); + }, + + getIndexAngle: function(index) { + var angleMultiplier = (Math.PI * 2) / this.getValueCount(); + // Start from the top instead of right, so remove a quarter of the circle + + return index * angleMultiplier - (Math.PI / 2); + }, + getDistanceFromCenterForValue: function(value) { + if (value === null) { + return 0; // null always in center + } + + // Take into account half font size + the yPadding of the top value + var scalingFactor = this.drawingArea / (this.max - this.min); + if (this.options.reverse) { + return (this.max - value) * scalingFactor; + } else { + return (value - this.min) * scalingFactor; + } + }, + getPointPosition: function(index, distanceFromCenter) { + var thisAngle = this.getIndexAngle(index); + return { + x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + this.xCenter, + y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + this.yCenter + }; + }, + getPointPositionForValue: function(index, value) { + return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); + }, + draw: function() { + if (this.options.display) { + var ctx = this.ctx; + helpers.each(this.ticks, function(label, index) { + // Don't draw a centre value (if it is minimum) + if (index > 0 || this.options.reverse) { + var yCenterOffset = this.getDistanceFromCenterForValue(this.ticks[index]); + var yHeight = this.yCenter - yCenterOffset; + + // Draw circular lines around the scale + if (this.options.gridLines.display) { + ctx.strokeStyle = this.options.gridLines.color; + ctx.lineWidth = this.options.gridLines.lineWidth; + + if (this.options.lineArc) { + // Draw circular arcs between the points + ctx.beginPath(); + ctx.arc(this.xCenter, this.yCenter, yCenterOffset, 0, Math.PI * 2); + ctx.closePath(); + ctx.stroke(); + } else { + // Draw straight lines connecting each index + ctx.beginPath(); + for (var i = 0; i < this.getValueCount(); i++) { + var pointPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.ticks[index])); + if (i === 0) { + ctx.moveTo(pointPosition.x, pointPosition.y); + } else { + ctx.lineTo(pointPosition.x, pointPosition.y); + } + } + ctx.closePath(); + ctx.stroke(); + } + } + + if (this.options.ticks.display) { + var tickFontColor = helpers.getValueOrDefault(this.options.ticks.fontColor, Chart.defaults.global.defaultFontColor); + var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); + var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle); + var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily); + var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily); + ctx.font = tickLabelFont; + + if (this.options.ticks.showLabelBackdrop) { + var labelWidth = ctx.measureText(label).width; + ctx.fillStyle = this.options.ticks.backdropColor; + ctx.fillRect( + this.xCenter - labelWidth / 2 - this.options.ticks.backdropPaddingX, + yHeight - tickFontSize / 2 - this.options.ticks.backdropPaddingY, + labelWidth + this.options.ticks.backdropPaddingX * 2, + tickFontSize + this.options.ticks.backdropPaddingY * 2 + ); + } + + ctx.textAlign = 'center'; + ctx.textBaseline = "middle"; + ctx.fillStyle = tickFontColor; + ctx.fillText(label, this.xCenter, yHeight); + } + } + }, this); + + if (!this.options.lineArc) { + ctx.lineWidth = this.options.angleLines.lineWidth; + ctx.strokeStyle = this.options.angleLines.color; + + for (var i = this.getValueCount() - 1; i >= 0; i--) { + if (this.options.angleLines.display) { + var outerPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max)); + ctx.beginPath(); + ctx.moveTo(this.xCenter, this.yCenter); + ctx.lineTo(outerPosition.x, outerPosition.y); + ctx.stroke(); + ctx.closePath(); + } + // Extra 3px out for some label spacing + var pointLabelPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max) + 5); + + var pointLabelFontColor = helpers.getValueOrDefault(this.options.pointLabels.fontColor, Chart.defaults.global.defaultFontColor); + var pointLabelFontSize = helpers.getValueOrDefault(this.options.pointLabels.fontSize, Chart.defaults.global.defaultFontSize); + var pointLabeFontStyle = helpers.getValueOrDefault(this.options.pointLabels.fontStyle, Chart.defaults.global.defaultFontStyle); + var pointLabeFontFamily = helpers.getValueOrDefault(this.options.pointLabels.fontFamily, Chart.defaults.global.defaultFontFamily); + var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily); + + ctx.font = pointLabeFont; + ctx.fillStyle = pointLabelFontColor; + + var labelsCount = this.pointLabels.length, + halfLabelsCount = this.pointLabels.length / 2, + quarterLabelsCount = halfLabelsCount / 2, + upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount), + exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount); + if (i === 0) { + ctx.textAlign = 'center'; + } else if (i === halfLabelsCount) { + ctx.textAlign = 'center'; + } else if (i < halfLabelsCount) { + ctx.textAlign = 'left'; + } else { + ctx.textAlign = 'right'; + } + + // Set the correct text baseline based on outer positioning + if (exactQuarter) { + ctx.textBaseline = 'middle'; + } else if (upperHalf) { + ctx.textBaseline = 'bottom'; + } else { + ctx.textBaseline = 'top'; + } + + ctx.fillText(this.pointLabels[i] ? this.pointLabels[i] : '', pointLabelPosition.x, pointLabelPosition.y); + } + } + } + } + }); + Chart.scaleService.registerScaleType("radialLinear", LinearRadialScale, defaultConfig); + +}; +},{}],41:[function(require,module,exports){ +/*global window: false */ +"use strict"; + +var moment = require('moment'); +moment = typeof(moment) === 'function' ? moment : window.moment; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + var time = { + units: [{ + name: 'millisecond', + steps: [1, 2, 5, 10, 20, 50, 100, 250, 500] + }, { + name: 'second', + steps: [1, 2, 5, 10, 30] + }, { + name: 'minute', + steps: [1, 2, 5, 10, 30] + }, { + name: 'hour', + steps: [1, 2, 3, 6, 12] + }, { + name: 'day', + steps: [1, 2, 5] + }, { + name: 'week', + maxStep: 4 + }, { + name: 'month', + maxStep: 3 + }, { + name: 'quarter', + maxStep: 4 + }, { + name: 'year', + maxStep: false + }] + }; + + var defaultConfig = { + position: "bottom", + + time: { + parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment + format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/ + unit: false, // false == automatic or override with week, month, year, etc. + round: false, // none, or override with week, month, year, etc. + displayFormat: false, // DEPRECATED + + // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/ + displayFormats: { + 'millisecond': 'h:mm:ss.SSS a', // 11:20:01.123 AM, + 'second': 'h:mm:ss a', // 11:20:01 AM + 'minute': 'h:mm:ss a', // 11:20:01 AM + 'hour': 'MMM D, hA', // Sept 4, 5PM + 'day': 'll', // Sep 4 2015 + 'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ? + 'month': 'MMM YYYY', // Sept 2015 + 'quarter': '[Q]Q - YYYY', // Q3 + 'year': 'YYYY' // 2015 + } + }, + ticks: { + autoSkip: false, + } + }; + + var TimeScale = Chart.Scale.extend({ + initialize: function() { + if (!moment) { + throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com'); + } + + Chart.Scale.prototype.initialize.call(this); + }, + getLabelMoment: function(datasetIndex, index) { + return this.labelMoments[datasetIndex][index]; + }, + determineDataLimits: function() { + this.labelMoments = []; + + // Only parse these once. If the dataset does not have data as x,y pairs, we will use + // these + var scaleLabelMoments = []; + if (this.chart.data.labels && this.chart.data.labels.length > 0) { + helpers.each(this.chart.data.labels, function(label, index) { + var labelMoment = this.parseTime(label); + if (this.options.time.round) { + labelMoment.startOf(this.options.time.round); + } + scaleLabelMoments.push(labelMoment); + }, this); + + this.firstTick = moment.min.call(this, scaleLabelMoments); + this.lastTick = moment.max.call(this, scaleLabelMoments); + } else { + this.firstTick = null; + this.lastTick = null; + } + + helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { + var momentsForDataset = []; + + if (typeof dataset.data[0] === 'object') { + helpers.each(dataset.data, function(value, index) { + var labelMoment = this.parseTime(this.getRightValue(value)); + if (this.options.time.round) { + labelMoment.startOf(this.options.time.round); + } + momentsForDataset.push(labelMoment); + + // May have gone outside the scale ranges, make sure we keep the first and last ticks updated + this.firstTick = this.firstTick !== null ? moment.min(this.firstTick, labelMoment) : labelMoment; + this.lastTick = this.lastTick !== null ? moment.max(this.lastTick, labelMoment) : labelMoment; + }, this); + } else { + // We have no labels. Use the ones from the scale + momentsForDataset = scaleLabelMoments; + } + + this.labelMoments.push(momentsForDataset); + }, this); + + // Set these after we've done all the data + if (this.options.time.min) { + this.firstTick = this.parseTime(this.options.time.min); + } + + if (this.options.time.max) { + this.lastTick = this.parseTime(this.options.time.max); + } + + // We will modify these, so clone for later + this.firstTick = (this.firstTick || moment()).clone(); + this.lastTick = (this.lastTick || moment()).clone(); + }, + buildTicks: function(index) { + + this.ticks = []; + this.unitScale = 1; // How much we scale the unit by, ie 2 means 2x unit per step + this.scaleSizeInUnits = 0; // How large the scale is in the base unit (seconds, minutes, etc) + + // Set unit override if applicable + if (this.options.time.unit) { + this.tickUnit = this.options.time.unit || 'day'; + this.displayFormat = this.options.time.displayFormats[this.tickUnit]; + this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true); + this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, 1); + } else { + // Determine the smallest needed unit of the time + var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); + var innerWidth = this.isHorizontal() ? this.width - (this.paddingLeft + this.paddingRight) : this.height - (this.paddingTop + this.paddingBottom); + + // Crude approximation of what the label length might be + var tempFirstLabel = this.tickFormatFunction(this.firstTick, 0, []); + var tickLabelWidth = tempFirstLabel.length * tickFontSize; + var cosRotation = Math.cos(helpers.toRadians(this.options.ticks.maxRotation)); + var sinRotation = Math.sin(helpers.toRadians(this.options.ticks.maxRotation)); + tickLabelWidth = (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation); + var labelCapacity = innerWidth / (tickLabelWidth + 10); + + // Start as small as possible + this.tickUnit = 'millisecond'; + this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true); + this.displayFormat = this.options.time.displayFormats[this.tickUnit]; + + var unitDefinitionIndex = 0; + var unitDefinition = time.units[unitDefinitionIndex]; + + // While we aren't ideal and we don't have units left + while (unitDefinitionIndex < time.units.length) { + // Can we scale this unit. If `false` we can scale infinitely + this.unitScale = 1; + + if (helpers.isArray(unitDefinition.steps) && Math.ceil(this.scaleSizeInUnits / labelCapacity) < helpers.max(unitDefinition.steps)) { + // Use one of the prefedined steps + for (var idx = 0; idx < unitDefinition.steps.length; ++idx) { + if (unitDefinition.steps[idx] > Math.ceil(this.scaleSizeInUnits / labelCapacity)) { + this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, unitDefinition.steps[idx]); + break; + } + } + + break; + } else if ((unitDefinition.maxStep === false) || (Math.ceil(this.scaleSizeInUnits / labelCapacity) < unitDefinition.maxStep)) { + // We have a max step. Scale this unit + this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, Math.ceil(this.scaleSizeInUnits / labelCapacity)); + break; + } else { + // Move to the next unit up + ++unitDefinitionIndex; + unitDefinition = time.units[unitDefinitionIndex]; + + this.tickUnit = unitDefinition.name; + this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true); + this.displayFormat = this.options.time.displayFormats[unitDefinition.name]; + } + } + } + + var roundedStart; + + // Only round the first tick if we have no hard minimum + if (!this.options.time.min) { + this.firstTick.startOf(this.tickUnit); + roundedStart = this.firstTick; + } else { + roundedStart = this.firstTick.clone().startOf(this.tickUnit); + } + + // Only round the last tick if we have no hard maximum + if (!this.options.time.max) { + this.lastTick.endOf(this.tickUnit); + } + + this.smallestLabelSeparation = this.width; + + helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { + for (var i = 1; i < this.labelMoments[datasetIndex].length; i++) { + this.smallestLabelSeparation = Math.min(this.smallestLabelSeparation, this.labelMoments[datasetIndex][i].diff(this.labelMoments[datasetIndex][i - 1], this.tickUnit, true)); + } + }, this); + + // Tick displayFormat override + if (this.options.time.displayFormat) { + this.displayFormat = this.options.time.displayFormat; + } + + // first tick. will have been rounded correctly if options.time.min is not specified + this.ticks.push(this.firstTick.clone()); + + // For every unit in between the first and last moment, create a moment and add it to the ticks tick + for (var i = 1; i < this.scaleSizeInUnits; ++i) { + var newTick = roundedStart.clone().add(i, this.tickUnit); + + // Are we greater than the max time + if (this.options.time.max && newTick.diff(this.lastTick, this.tickUnit, true) >= 0) { + break; + } + + if (i % this.unitScale === 0) { + this.ticks.push(newTick); + } + } + + // Always show the right tick + if (this.ticks[this.ticks.length - 1].diff(this.lastTick, this.tickUnit) !== 0 || this.scaleSizeInUnits === 0) { + // this is a weird case. If the option is the same as the end option, we can't just diff the times because the tick was created from the roundedStart + // but the last tick was not rounded. + if (this.options.time.max) { + this.ticks.push(this.lastTick.clone()); + this.scaleSizeInUnits = this.lastTick.diff(this.ticks[0], this.tickUnit, true); + } else { + this.scaleSizeInUnits = Math.ceil(this.scaleSizeInUnits / this.unitScale) * this.unitScale; + this.ticks.push(this.firstTick.clone().add(this.scaleSizeInUnits, this.tickUnit)); + this.lastTick = this.ticks[this.ticks.length - 1].clone(); + } + } + }, + // Get tooltip label + getLabelForIndex: function(index, datasetIndex) { + var label = this.chart.data.labels && index < this.chart.data.labels.length ? this.chart.data.labels[index] : ''; + + if (typeof this.chart.data.datasets[datasetIndex].data[0] === 'object') { + label = this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); + } + + // Format nicely + if (this.options.time.tooltipFormat) { + label = this.parseTime(label).format(this.options.time.tooltipFormat); + } + + return label; + }, + // Function to format an individual tick mark + tickFormatFunction: function tickFormatFunction(tick, index, ticks) { + var formattedTick = tick.format(this.displayFormat); + + if (this.options.ticks.userCallback) { + return this.options.ticks.userCallback(formattedTick, index, ticks); + } else { + return formattedTick; + } + }, + convertTicksToLabels: function() { + this.ticks = this.ticks.map(this.tickFormatFunction, this); + }, + getPixelForValue: function(value, index, datasetIndex, includeOffset) { + var labelMoment = this.getLabelMoment(datasetIndex, index); + + if (labelMoment) { + var offset = labelMoment.diff(this.firstTick, this.tickUnit, true); + + var decimal = offset / this.scaleSizeInUnits; + + if (this.isHorizontal()) { + var innerWidth = this.width - (this.paddingLeft + this.paddingRight); + var valueWidth = innerWidth / Math.max(this.ticks.length - 1, 1); + var valueOffset = (innerWidth * decimal) + this.paddingLeft; + + return this.left + Math.round(valueOffset); + } else { + var innerHeight = this.height - (this.paddingTop + this.paddingBottom); + var valueHeight = innerHeight / Math.max(this.ticks.length - 1, 1); + var heightOffset = (innerHeight * decimal) + this.paddingTop; + + return this.top + Math.round(heightOffset); + } + } + }, + parseTime: function(label) { + if (typeof this.options.time.parser === 'string') { + return moment(label, this.options.time.parser); + } + if (typeof this.options.time.parser === 'function') { + return this.options.time.parser(label); + } + // Date objects + if (typeof label.getMonth === 'function' || typeof label === 'number') { + return moment(label); + } + // Moment support + if (label.isValid && label.isValid()) { + return label; + } + // Custom parsing (return an instance of moment) + if (typeof this.options.time.format !== 'string' && this.options.time.format.call) { + console.warn("options.time.format is deprecated and replaced by options.time.parser. See http://nnnick.github.io/Chart.js/docs-v2/#scales-time-scale"); + return this.options.time.format(label); + } + // Moment format parsing + return moment(label, this.options.time.format); + } + }); + Chart.scaleService.registerScaleType("time", TimeScale, defaultConfig); + +}; +},{"moment":6}]},{},[7]); diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/Chart.min.js b/gridplatform/bootstrap/static/bootstrap/chart.js/Chart.min.js new file mode 100755 index 0000000..10e4f2b --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/Chart.min.js @@ -0,0 +1,15 @@ +!function t(e,i,s){function a(n,r){if(!i[n]){if(!e[n]){var l="function"==typeof require&&require;if(!r&&l)return l(n,!0);if(o)return o(n,!0);var h=new Error("Cannot find module '"+n+"'");throw h.code="MODULE_NOT_FOUND",h}var c=i[n]={exports:{}};e[n][0].call(c.exports,function(t){var i=e[n][1][t];return a(i?i:t)},c,c.exports,t,e,i,s)}return i[n].exports}for(var o="function"==typeof require&&require,n=0;n=s?s/12.92:Math.pow((s+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),i=t.luminosity();return e>i?(e+.05)/(i+.05):(i+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb,e=(299*t[0]+587*t[1]+114*t[2])/1e3;return 128>e},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;3>e;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){return this.values.hsl[2]+=this.values.hsl[2]*t,this.setValues("hsl",this.values.hsl),this},darken:function(t){return this.values.hsl[2]-=this.values.hsl[2]*t,this.setValues("hsl",this.values.hsl),this},saturate:function(t){return this.values.hsl[1]+=this.values.hsl[1]*t,this.setValues("hsl",this.values.hsl),this},desaturate:function(t){return this.values.hsl[1]-=this.values.hsl[1]*t,this.setValues("hsl",this.values.hsl),this},whiten:function(t){return this.values.hwb[1]+=this.values.hwb[1]*t,this.setValues("hwb",this.values.hwb),this},blacken:function(t){return this.values.hwb[2]+=this.values.hwb[2]*t,this.setValues("hwb",this.values.hwb),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){return this.setValues("alpha",this.values.alpha-this.values.alpha*t),this},opaquer:function(t){return this.setValues("alpha",this.values.alpha+this.values.alpha*t),this},rotate:function(t){var e=this.values.hsl[0];return e=(e+t)%360,e=0>e?360+e:e,this.values.hsl[0]=e,this.setValues("hsl",this.values.hsl),this},mix:function(t,e){e=1-(null==e?.5:e);for(var i=2*e-1,s=this.alpha()-t.alpha(),a=((i*s==-1?i:(i+s)/(1+i*s))+1)/2,o=1-a,n=this.rgbArray(),r=t.rgbArray(),l=0;le&&(e+=360),s=(r+l)/2,i=l==r?0:.5>=s?h/(l+r):h/(2-l-r),[e,100*i,100*s]}function a(t){var e,i,s,a=t[0],o=t[1],n=t[2],r=Math.min(a,o,n),l=Math.max(a,o,n),h=l-r;return i=0==l?0:h/l*1e3/10,l==r?e=0:a==l?e=(o-n)/h:o==l?e=2+(n-a)/h:n==l&&(e=4+(a-o)/h),e=Math.min(60*e,360),0>e&&(e+=360),s=l/255*1e3/10,[e,i,s]}function o(t){var e=t[0],i=t[1],a=t[2],o=s(t)[0],n=1/255*Math.min(e,Math.min(i,a)),a=1-1/255*Math.max(e,Math.max(i,a));return[o,100*n,100*a]}function n(t){var e,i,s,a,o=t[0]/255,n=t[1]/255,r=t[2]/255;return a=Math.min(1-o,1-n,1-r),e=(1-o-a)/(1-a)||0,i=(1-n-a)/(1-a)||0,s=(1-r-a)/(1-a)||0,[100*e,100*i,100*s,100*a]}function l(t){return X[JSON.stringify(t)]}function h(t){var e=t[0]/255,i=t[1]/255,s=t[2]/255;e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92,i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92,s=s>.04045?Math.pow((s+.055)/1.055,2.4):s/12.92;var a=.4124*e+.3576*i+.1805*s,o=.2126*e+.7152*i+.0722*s,n=.0193*e+.1192*i+.9505*s;return[100*a,100*o,100*n]}function c(t){var e,i,s,a=h(t),o=a[0],n=a[1],r=a[2];return o/=95.047,n/=100,r/=108.883,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,n=n>.008856?Math.pow(n,1/3):7.787*n+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,e=116*n-16,i=500*(o-n),s=200*(n-r),[e,i,s]}function d(t){return z(c(t))}function u(t){var e,i,s,a,o,n=t[0]/360,r=t[1]/100,l=t[2]/100;if(0==r)return o=255*l,[o,o,o];i=.5>l?l*(1+r):l+r-l*r,e=2*l-i,a=[0,0,0];for(var h=0;3>h;h++)s=n+1/3*-(h-1),0>s&&s++,s>1&&s--,o=1>6*s?e+6*(i-e)*s:1>2*s?i:2>3*s?e+(i-e)*(2/3-s)*6:e,a[h]=255*o;return a}function f(t){var e,i,s=t[0],a=t[1]/100,o=t[2]/100;return 0===o?[0,0,0]:(o*=2,a*=1>=o?o:2-o,i=(o+a)/2,e=2*a/(o+a),[s,100*e,100*i])}function m(t){return o(u(t))}function p(t){return n(u(t))}function v(t){return l(u(t))}function x(t){var e=t[0]/60,i=t[1]/100,s=t[2]/100,a=Math.floor(e)%6,o=e-Math.floor(e),n=255*s*(1-i),r=255*s*(1-i*o),l=255*s*(1-i*(1-o)),s=255*s;switch(a){case 0:return[s,l,n];case 1:return[r,s,n];case 2:return[n,s,l];case 3:return[n,r,s];case 4:return[l,n,s];case 5:return[s,n,r]}}function y(t){var e,i,s=t[0],a=t[1]/100,o=t[2]/100;return i=(2-a)*o,e=a*o,e/=1>=i?i:2-i,e=e||0,i/=2,[s,100*e,100*i]}function _(t){return o(x(t))}function k(t){return n(x(t))}function D(t){return l(x(t))}function S(t){var e,i,s,a,o=t[0]/360,n=t[1]/100,l=t[2]/100,h=n+l;switch(h>1&&(n/=h,l/=h),e=Math.floor(6*o),i=1-l,s=6*o-e,0!=(1&e)&&(s=1-s),a=n+s*(i-n),e){default:case 6:case 0:r=i,g=a,b=n;break;case 1:r=a,g=i,b=n;break;case 2:r=n,g=i,b=a;break;case 3:r=n,g=a,b=i;break;case 4:r=a,g=n,b=i;break;case 5:r=i,g=n,b=a}return[255*r,255*g,255*b]}function w(t){return s(S(t))}function C(t){return a(S(t))}function M(t){return n(S(t))}function A(t){return l(S(t))}function T(t){var e,i,s,a=t[0]/100,o=t[1]/100,n=t[2]/100,r=t[3]/100;return e=1-Math.min(1,a*(1-r)+r),i=1-Math.min(1,o*(1-r)+r),s=1-Math.min(1,n*(1-r)+r),[255*e,255*i,255*s]}function I(t){return s(T(t))}function F(t){return a(T(t))}function P(t){return o(T(t))}function O(t){return l(T(t))}function V(t){var e,i,s,a=t[0]/100,o=t[1]/100,n=t[2]/100;return e=3.2406*a+-1.5372*o+n*-.4986,i=a*-.9689+1.8758*o+.0415*n,s=.0557*a+o*-.204+1.057*n,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:e=12.92*e,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i=12.92*i,s=s>.0031308?1.055*Math.pow(s,1/2.4)-.055:s=12.92*s,e=Math.min(Math.max(0,e),1),i=Math.min(Math.max(0,i),1),s=Math.min(Math.max(0,s),1),[255*e,255*i,255*s]}function W(t){var e,i,s,a=t[0],o=t[1],n=t[2];return a/=95.047,o/=100,n/=108.883,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,n=n>.008856?Math.pow(n,1/3):7.787*n+16/116,e=116*o-16,i=500*(a-o),s=200*(o-n),[e,i,s]}function R(t){return z(W(t))}function L(t){var e,i,s,a,o=t[0],n=t[1],r=t[2];return 8>=o?(i=100*o/903.3,a=7.787*(i/100)+16/116):(i=100*Math.pow((o+16)/116,3),a=Math.pow(i/100,1/3)),e=.008856>=e/95.047?e=95.047*(n/500+a-16/116)/7.787:95.047*Math.pow(n/500+a,3),s=.008859>=s/108.883?s=108.883*(a-r/200-16/116)/7.787:108.883*Math.pow(a-r/200,3),[e,i,s]}function z(t){var e,i,s,a=t[0],o=t[1],n=t[2];return e=Math.atan2(n,o),i=360*e/2/Math.PI,0>i&&(i+=360),s=Math.sqrt(o*o+n*n),[a,s,i]}function B(t){return V(L(t))}function Y(t){var e,i,s,a=t[0],o=t[1],n=t[2];return s=n/360*2*Math.PI,e=o*Math.cos(s),i=o*Math.sin(s),[a,e,i]}function H(t){return L(Y(t))}function N(t){return B(Y(t))}function E(t){return J[t]}function U(t){return s(E(t))}function j(t){return a(E(t))}function G(t){return o(E(t))}function q(t){return n(E(t))}function Z(t){return c(E(t))}function Q(t){return h(E(t))}e.exports={rgb2hsl:s,rgb2hsv:a,rgb2hwb:o,rgb2cmyk:n,rgb2keyword:l,rgb2xyz:h,rgb2lab:c,rgb2lch:d,hsl2rgb:u,hsl2hsv:f,hsl2hwb:m,hsl2cmyk:p,hsl2keyword:v,hsv2rgb:x,hsv2hsl:y,hsv2hwb:_,hsv2cmyk:k,hsv2keyword:D,hwb2rgb:S,hwb2hsl:w,hwb2hsv:C,hwb2cmyk:M,hwb2keyword:A,cmyk2rgb:T,cmyk2hsl:I,cmyk2hsv:F,cmyk2hwb:P,cmyk2keyword:O,keyword2rgb:E,keyword2hsl:U,keyword2hsv:j,keyword2hwb:G,keyword2cmyk:q,keyword2lab:Z,keyword2xyz:Q,xyz2rgb:V,xyz2lab:W,xyz2lch:R,lab2xyz:L,lab2rgb:B,lab2lch:z,lch2lab:Y,lch2xyz:H,lch2rgb:N};var J={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]},X={};for(var $ in J)X[JSON.stringify(J[$])]=$},{}],3:[function(t,e,i){var s=t("./conversions"),a=function(){return new h};for(var o in s){a[o+"Raw"]=function(t){return function(e){return"number"==typeof e&&(e=Array.prototype.slice.call(arguments)),s[t](e)}}(o);var n=/(\w+)2(\w+)/.exec(o),r=n[1],l=n[2];a[r]=a[r]||{},a[r][l]=a[o]=function(t){return function(e){"number"==typeof e&&(e=Array.prototype.slice.call(arguments));var i=s[t](e);if("string"==typeof i||void 0===i)return i;for(var a=0;ae||t[3]&&t[3]<1?d(t,e):"rgb("+t[0]+", "+t[1]+", "+t[2]+")"}function d(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function u(t,e){if(1>e||t[3]&&t[3]<1)return f(t,e);var i=Math.round(t[0]/255*100),s=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgb("+i+"%, "+s+"%, "+a+"%)"}function f(t,e){var i=Math.round(t[0]/255*100),s=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgba("+i+"%, "+s+"%, "+a+"%, "+(e||t[3]||1)+")"}function m(t,e){return 1>e||t[3]&&t[3]<1?g(t,e):"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"}function g(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function p(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"}function b(t){return _[t.slice(0,3)]}function v(t,e,i){return Math.min(Math.max(e,t),i)}function x(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var y=t("color-name");e.exports={getRgba:s,getHsla:a,getRgb:n,getHsl:r,getHwb:o,getAlpha:l,hexString:h,rgbString:c,rgbaString:d,percentString:u,percentaString:f,hslString:m,hslaString:g,hwbString:p,keyword:b};var _={};for(var k in y)_[y[k]]=k},{"color-name":4}],6:[function(t,e,i){!function(t,s){"object"==typeof i&&"undefined"!=typeof e?e.exports=s():"function"==typeof define&&define.amd?define(s):t.moment=s()}(this,function(){"use strict";function i(){return Zi.apply(null,arguments)}function s(t){Zi=t}function a(t){return"[object Array]"===Object.prototype.toString.call(t)}function o(t){return t instanceof Date||"[object Date]"===Object.prototype.toString.call(t)}function n(t,e){var i,s=[];for(i=0;i0)for(i in Ji)s=Ji[i],a=e[s],m(a)||(t[s]=a);return t}function p(t){g(this,t),this._d=new Date(null!=t._d?t._d.getTime():NaN),Xi===!1&&(Xi=!0,i.updateOffset(this),Xi=!1)}function b(t){return t instanceof p||null!=t&&null!=t._isAMomentObject}function v(t){return 0>t?Math.ceil(t):Math.floor(t)}function x(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=v(e)),i}function y(t,e,i){var s,a=Math.min(t.length,e.length),o=Math.abs(t.length-e.length),n=0;for(s=0;a>s;s++)(i&&t[s]!==e[s]||!i&&x(t[s])!==x(e[s]))&&n++;return n+o}function _(){}function k(t){return t?t.toLowerCase().replace("_","-"):t}function D(t){for(var e,i,s,a,o=0;o0;){if(s=S(a.slice(0,e).join("-")))return s;if(i&&i.length>=e&&y(a,i,!0)>=e-1)break;e--}o++}return null}function S(i){var s=null;if(!$i[i]&&"undefined"!=typeof e&&e&&e.exports)try{s=Qi._abbr,t("./locale/"+i),w(s)}catch(a){}return $i[i]}function w(t,e){var i;return t&&(i=m(e)?M(t):C(t,e),i&&(Qi=i)),Qi._abbr}function C(t,e){return null!==e?(e.abbr=t,$i[t]=$i[t]||new _,$i[t].set(e),w(t),$i[t]):(delete $i[t],null)}function M(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return Qi;if(!a(t)){if(e=S(t))return e;t=[t]}return D(t)}function A(t,e){var i=t.toLowerCase();Ki[i]=Ki[i+"s"]=Ki[e]=t}function T(t){return"string"==typeof t?Ki[t]||Ki[t.toLowerCase()]:void 0}function I(t){var e,i,s={};for(i in t)r(t,i)&&(e=T(i),e&&(s[e]=t[i]));return s}function F(t){return t instanceof Function||"[object Function]"===Object.prototype.toString.call(t)}function P(t,e){return function(s){return null!=s?(V(this,t,s),i.updateOffset(this,e),this):O(this,t)}}function O(t,e){return t.isValid()?t._d["get"+(t._isUTC?"UTC":"")+e]():NaN}function V(t,e,i){t.isValid()&&t._d["set"+(t._isUTC?"UTC":"")+e](i)}function W(t,e){var i;if("object"==typeof t)for(i in t)this.set(i,t[i]);else if(t=T(t),F(this[t]))return this[t](e);return this}function R(t,e,i){var s=""+Math.abs(t),a=e-s.length,o=t>=0;return(o?i?"+":"":"-")+Math.pow(10,Math.max(0,a)).toString().substr(1)+s}function L(t,e,i,s){var a=s;"string"==typeof s&&(a=function(){return this[s]()}),t&&(ss[t]=a),e&&(ss[e[0]]=function(){return R(a.apply(this,arguments),e[1],e[2])}),i&&(ss[i]=function(){return this.localeData().ordinal(a.apply(this,arguments),t)})}function z(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function B(t){var e,i,s=t.match(ts);for(e=0,i=s.length;i>e;e++)ss[s[e]]?s[e]=ss[s[e]]:s[e]=z(s[e]);return function(a){var o="";for(e=0;i>e;e++)o+=s[e]instanceof Function?s[e].call(a,t):s[e];return o}}function Y(t,e){return t.isValid()?(e=H(e,t.localeData()),is[e]=is[e]||B(e),is[e](t)):t.localeData().invalidDate()}function H(t,e){function i(t){return e.longDateFormat(t)||t}var s=5;for(es.lastIndex=0;s>=0&&es.test(t);)t=t.replace(es,i),es.lastIndex=0,s-=1;return t}function N(t,e,i){_s[t]=F(e)?e:function(t,s){return t&&i?i:e}}function E(t,e){return r(_s,t)?_s[t](e._strict,e._locale):new RegExp(U(t))}function U(t){return j(t.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,s,a){return e||i||s||a}))}function j(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function G(t,e){var i,s=e;for("string"==typeof t&&(t=[t]),"number"==typeof e&&(s=function(t,i){i[e]=x(t)}),i=0;is;s++){if(a=h([2e3,s]),i&&!this._longMonthsParse[s]&&(this._longMonthsParse[s]=new RegExp("^"+this.months(a,"").replace(".","")+"$","i"),this._shortMonthsParse[s]=new RegExp("^"+this.monthsShort(a,"").replace(".","")+"$","i")),i||this._monthsParse[s]||(o="^"+this.months(a,"")+"|^"+this.monthsShort(a,""),this._monthsParse[s]=new RegExp(o.replace(".",""),"i")),i&&"MMMM"===e&&this._longMonthsParse[s].test(t))return s;if(i&&"MMM"===e&&this._shortMonthsParse[s].test(t))return s;if(!i&&this._monthsParse[s].test(t))return s}}function K(t,e){var i;return t.isValid()?"string"==typeof e&&(e=t.localeData().monthsParse(e),"number"!=typeof e)?t:(i=Math.min(t.date(),Q(t.year(),e)),t._d["set"+(t._isUTC?"UTC":"")+"Month"](e,i),t):t}function tt(t){return null!=t?(K(this,t),i.updateOffset(this,!0),this):O(this,"Month")}function et(){return Q(this.year(),this.month())}function it(t){return this._monthsParseExact?(r(this,"_monthsRegex")||at.call(this),t?this._monthsShortStrictRegex:this._monthsShortRegex):this._monthsShortStrictRegex&&t?this._monthsShortStrictRegex:this._monthsShortRegex}function st(t){return this._monthsParseExact?(r(this,"_monthsRegex")||at.call(this),t?this._monthsStrictRegex:this._monthsRegex):this._monthsStrictRegex&&t?this._monthsStrictRegex:this._monthsRegex}function at(){function t(t,e){return e.length-t.length}var e,i,s=[],a=[],o=[];for(e=0;12>e;e++)i=h([2e3,e]),s.push(this.monthsShort(i,"")),a.push(this.months(i,"")),o.push(this.months(i,"")),o.push(this.monthsShort(i,""));for(s.sort(t),a.sort(t),o.sort(t),e=0;12>e;e++)s[e]=j(s[e]),a[e]=j(a[e]),o[e]=j(o[e]);this._monthsRegex=new RegExp("^("+o.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+a.join("|")+")$","i"),this._monthsShortStrictRegex=new RegExp("^("+s.join("|")+")$","i")}function ot(t){var e,i=t._a;return i&&-2===d(t).overflow&&(e=i[Ss]<0||i[Ss]>11?Ss:i[ws]<1||i[ws]>Q(i[Ds],i[Ss])?ws:i[Cs]<0||i[Cs]>24||24===i[Cs]&&(0!==i[Ms]||0!==i[As]||0!==i[Ts])?Cs:i[Ms]<0||i[Ms]>59?Ms:i[As]<0||i[As]>59?As:i[Ts]<0||i[Ts]>999?Ts:-1,d(t)._overflowDayOfYear&&(Ds>e||e>ws)&&(e=ws),d(t)._overflowWeeks&&-1===e&&(e=Is),d(t)._overflowWeekday&&-1===e&&(e=Fs),d(t).overflow=e),t}function nt(t){i.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}function rt(t,e){var i=!0;return l(function(){return i&&(nt(t+"\nArguments: "+Array.prototype.slice.call(arguments).join(", ")+"\n"+(new Error).stack),i=!1),e.apply(this,arguments)},e)}function lt(t,e){Ls[t]||(nt(e),Ls[t]=!0)}function ht(t){var e,i,s,a,o,n,r=t._i,l=zs.exec(r)||Bs.exec(r);if(l){for(d(t).iso=!0,e=0,i=Hs.length;i>e;e++)if(Hs[e][1].exec(l[1])){a=Hs[e][0],s=Hs[e][2]!==!1;break}if(null==a)return void(t._isValid=!1);if(l[3]){for(e=0,i=Ns.length;i>e;e++)if(Ns[e][1].exec(l[3])){o=(l[2]||" ")+Ns[e][0];break}if(null==o)return void(t._isValid=!1)}if(!s&&null!=o)return void(t._isValid=!1);if(l[4]){if(!Ys.exec(l[4]))return void(t._isValid=!1);n="Z"}t._f=a+(o||"")+(n||""),St(t)}else t._isValid=!1}function ct(t){ +var e=Es.exec(t._i);return null!==e?void(t._d=new Date(+e[1])):(ht(t),void(t._isValid===!1&&(delete t._isValid,i.createFromInputFallback(t))))}function dt(t,e,i,s,a,o,n){var r=new Date(t,e,i,s,a,o,n);return 100>t&&t>=0&&isFinite(r.getFullYear())&&r.setFullYear(t),r}function ut(t){var e=new Date(Date.UTC.apply(null,arguments));return 100>t&&t>=0&&isFinite(e.getUTCFullYear())&&e.setUTCFullYear(t),e}function ft(t){return mt(t)?366:365}function mt(t){return t%4===0&&t%100!==0||t%400===0}function gt(){return mt(this.year())}function pt(t,e,i){var s=7+e-i,a=(7+ut(t,0,s).getUTCDay()-e)%7;return-a+s-1}function bt(t,e,i,s,a){var o,n,r=(7+i-s)%7,l=pt(t,s,a),h=1+7*(e-1)+r+l;return 0>=h?(o=t-1,n=ft(o)+h):h>ft(t)?(o=t+1,n=h-ft(t)):(o=t,n=h),{year:o,dayOfYear:n}}function vt(t,e,i){var s,a,o=pt(t.year(),e,i),n=Math.floor((t.dayOfYear()-o-1)/7)+1;return 1>n?(a=t.year()-1,s=n+xt(a,e,i)):n>xt(t.year(),e,i)?(s=n-xt(t.year(),e,i),a=t.year()+1):(a=t.year(),s=n),{week:s,year:a}}function xt(t,e,i){var s=pt(t,e,i),a=pt(t+1,e,i);return(ft(t)-s+a)/7}function yt(t,e,i){return null!=t?t:null!=e?e:i}function _t(t){var e=new Date(i.now());return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function kt(t){var e,i,s,a,o=[];if(!t._d){for(s=_t(t),t._w&&null==t._a[ws]&&null==t._a[Ss]&&Dt(t),t._dayOfYear&&(a=yt(t._a[Ds],s[Ds]),t._dayOfYear>ft(a)&&(d(t)._overflowDayOfYear=!0),i=ut(a,0,t._dayOfYear),t._a[Ss]=i.getUTCMonth(),t._a[ws]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=o[e]=s[e];for(;7>e;e++)t._a[e]=o[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[Cs]&&0===t._a[Ms]&&0===t._a[As]&&0===t._a[Ts]&&(t._nextDay=!0,t._a[Cs]=0),t._d=(t._useUTC?ut:dt).apply(null,o),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[Cs]=24)}}function Dt(t){var e,i,s,a,o,n,r,l;e=t._w,null!=e.GG||null!=e.W||null!=e.E?(o=1,n=4,i=yt(e.GG,t._a[Ds],vt(Pt(),1,4).year),s=yt(e.W,1),a=yt(e.E,1),(1>a||a>7)&&(l=!0)):(o=t._locale._week.dow,n=t._locale._week.doy,i=yt(e.gg,t._a[Ds],vt(Pt(),o,n).year),s=yt(e.w,1),null!=e.d?(a=e.d,(0>a||a>6)&&(l=!0)):null!=e.e?(a=e.e+o,(e.e<0||e.e>6)&&(l=!0)):a=o),1>s||s>xt(i,o,n)?d(t)._overflowWeeks=!0:null!=l?d(t)._overflowWeekday=!0:(r=bt(i,s,a,o,n),t._a[Ds]=r.year,t._dayOfYear=r.dayOfYear)}function St(t){if(t._f===i.ISO_8601)return void ht(t);t._a=[],d(t).empty=!0;var e,s,a,o,n,r=""+t._i,l=r.length,h=0;for(a=H(t._f,t._locale).match(ts)||[],e=0;e0&&d(t).unusedInput.push(n),r=r.slice(r.indexOf(s)+s.length),h+=s.length),ss[o]?(s?d(t).empty=!1:d(t).unusedTokens.push(o),Z(o,s,t)):t._strict&&!s&&d(t).unusedTokens.push(o);d(t).charsLeftOver=l-h,r.length>0&&d(t).unusedInput.push(r),d(t).bigHour===!0&&t._a[Cs]<=12&&t._a[Cs]>0&&(d(t).bigHour=void 0),t._a[Cs]=wt(t._locale,t._a[Cs],t._meridiem),kt(t),ot(t)}function wt(t,e,i){var s;return null==i?e:null!=t.meridiemHour?t.meridiemHour(e,i):null!=t.isPM?(s=t.isPM(i),s&&12>e&&(e+=12),s||12!==e||(e=0),e):e}function Ct(t){var e,i,s,a,o;if(0===t._f.length)return d(t).invalidFormat=!0,void(t._d=new Date(NaN));for(a=0;ao)&&(s=o,i=e));l(t,i||e)}function Mt(t){if(!t._d){var e=I(t._i);t._a=n([e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],function(t){return t&&parseInt(t,10)}),kt(t)}}function At(t){var e=new p(ot(Tt(t)));return e._nextDay&&(e.add(1,"d"),e._nextDay=void 0),e}function Tt(t){var e=t._i,i=t._f;return t._locale=t._locale||M(t._l),null===e||void 0===i&&""===e?f({nullInput:!0}):("string"==typeof e&&(t._i=e=t._locale.preparse(e)),b(e)?new p(ot(e)):(a(i)?Ct(t):i?St(t):o(e)?t._d=e:It(t),u(t)||(t._d=null),t))}function It(t){var e=t._i;void 0===e?t._d=new Date(i.now()):o(e)?t._d=new Date(+e):"string"==typeof e?ct(t):a(e)?(t._a=n(e.slice(0),function(t){return parseInt(t,10)}),kt(t)):"object"==typeof e?Mt(t):"number"==typeof e?t._d=new Date(e):i.createFromInputFallback(t)}function Ft(t,e,i,s,a){var o={};return"boolean"==typeof i&&(s=i,i=void 0),o._isAMomentObject=!0,o._useUTC=o._isUTC=a,o._l=i,o._i=t,o._f=e,o._strict=s,At(o)}function Pt(t,e,i,s){return Ft(t,e,i,s,!1)}function Ot(t,e){var i,s;if(1===e.length&&a(e[0])&&(e=e[0]),!e.length)return Pt();for(i=e[0],s=1;st&&(t=-t,i="-"),i+R(~~(t/60),2)+e+R(~~t%60,2)})}function Bt(t,e){var i=(e||"").match(t)||[],s=i[i.length-1]||[],a=(s+"").match(Zs)||["-",0,0],o=+(60*a[1])+x(a[2]);return"+"===a[0]?o:-o}function Yt(t,e){var s,a;return e._isUTC?(s=e.clone(),a=(b(t)||o(t)?+t:+Pt(t))-+s,s._d.setTime(+s._d+a),i.updateOffset(s,!1),s):Pt(t).local()}function Ht(t){return 15*-Math.round(t._d.getTimezoneOffset()/15)}function Nt(t,e){var s,a=this._offset||0;return this.isValid()?null!=t?("string"==typeof t?t=Bt(vs,t):Math.abs(t)<16&&(t=60*t),!this._isUTC&&e&&(s=Ht(this)),this._offset=t,this._isUTC=!0,null!=s&&this.add(s,"m"),a!==t&&(!e||this._changeInProgress?ae(this,Kt(t-a,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,i.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?a:Ht(this):null!=t?this:NaN}function Et(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}function Ut(t){return this.utcOffset(0,t)}function jt(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(Ht(this),"m")),this}function Gt(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Bt(bs,this._i)),this}function qt(t){return this.isValid()?(t=t?Pt(t).utcOffset():0,(this.utcOffset()-t)%60===0):!1}function Zt(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Qt(){if(!m(this._isDSTShifted))return this._isDSTShifted;var t={};if(g(t,this),t=Tt(t),t._a){var e=t._isUTC?h(t._a):Pt(t._a);this._isDSTShifted=this.isValid()&&y(t._a,e.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Jt(){return this.isValid()?!this._isUTC:!1}function Xt(){return this.isValid()?this._isUTC:!1}function $t(){return this.isValid()?this._isUTC&&0===this._offset:!1}function Kt(t,e){var i,s,a,o=t,n=null;return Lt(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(n=Qs.exec(t))?(i="-"===n[1]?-1:1,o={y:0,d:x(n[ws])*i,h:x(n[Cs])*i,m:x(n[Ms])*i,s:x(n[As])*i,ms:x(n[Ts])*i}):(n=Js.exec(t))?(i="-"===n[1]?-1:1,o={y:te(n[2],i),M:te(n[3],i),d:te(n[4],i),h:te(n[5],i),m:te(n[6],i),s:te(n[7],i),w:te(n[8],i)}):null==o?o={}:"object"==typeof o&&("from"in o||"to"in o)&&(a=ie(Pt(o.from),Pt(o.to)),o={},o.ms=a.milliseconds,o.M=a.months),s=new Rt(o),Lt(t)&&r(t,"_locale")&&(s._locale=t._locale),s}function te(t,e){var i=t&&parseFloat(t.replace(",","."));return(isNaN(i)?0:i)*e}function ee(t,e){var i={milliseconds:0,months:0};return i.months=e.month()-t.month()+12*(e.year()-t.year()),t.clone().add(i.months,"M").isAfter(e)&&--i.months,i.milliseconds=+e-+t.clone().add(i.months,"M"),i}function ie(t,e){var i;return t.isValid()&&e.isValid()?(e=Yt(e,t),t.isBefore(e)?i=ee(t,e):(i=ee(e,t),i.milliseconds=-i.milliseconds,i.months=-i.months),i):{milliseconds:0,months:0}}function se(t,e){return function(i,s){var a,o;return null===s||isNaN(+s)||(lt(e,"moment()."+e+"(period, number) is deprecated. Please use moment()."+e+"(number, period)."),o=i,i=s,s=o),i="string"==typeof i?+i:i,a=Kt(i,s),ae(this,a,t),this}}function ae(t,e,s,a){var o=e._milliseconds,n=e._days,r=e._months;t.isValid()&&(a=null==a?!0:a,o&&t._d.setTime(+t._d+o*s),n&&V(t,"Date",O(t,"Date")+n*s),r&&K(t,O(t,"Month")+r*s),a&&i.updateOffset(t,n||r))}function oe(t,e){var i=t||Pt(),s=Yt(i,this).startOf("day"),a=this.diff(s,"days",!0),o=-6>a?"sameElse":-1>a?"lastWeek":0>a?"lastDay":1>a?"sameDay":2>a?"nextDay":7>a?"nextWeek":"sameElse",n=e&&(F(e[o])?e[o]():e[o]);return this.format(n||this.localeData().calendar(o,this,Pt(i)))}function ne(){return new p(this)}function re(t,e){var i=b(t)?t:Pt(t);return this.isValid()&&i.isValid()?(e=T(m(e)?"millisecond":e),"millisecond"===e?+this>+i:+i<+this.clone().startOf(e)):!1}function le(t,e){var i=b(t)?t:Pt(t);return this.isValid()&&i.isValid()?(e=T(m(e)?"millisecond":e),"millisecond"===e?+i>+this:+this.clone().endOf(e)<+i):!1}function he(t,e,i){return this.isAfter(t,i)&&this.isBefore(e,i)}function ce(t,e){var i,s=b(t)?t:Pt(t);return this.isValid()&&s.isValid()?(e=T(e||"millisecond"),"millisecond"===e?+this===+s:(i=+s,+this.clone().startOf(e)<=i&&i<=+this.clone().endOf(e))):!1}function de(t,e){return this.isSame(t,e)||this.isAfter(t,e)}function ue(t,e){return this.isSame(t,e)||this.isBefore(t,e)}function fe(t,e,i){var s,a,o,n;return this.isValid()?(s=Yt(t,this),s.isValid()?(a=6e4*(s.utcOffset()-this.utcOffset()),e=T(e),"year"===e||"month"===e||"quarter"===e?(n=me(this,s),"quarter"===e?n/=3:"year"===e&&(n/=12)):(o=this-s,n="second"===e?o/1e3:"minute"===e?o/6e4:"hour"===e?o/36e5:"day"===e?(o-a)/864e5:"week"===e?(o-a)/6048e5:o),i?n:v(n)):NaN):NaN}function me(t,e){var i,s,a=12*(e.year()-t.year())+(e.month()-t.month()),o=t.clone().add(a,"months");return 0>e-o?(i=t.clone().add(a-1,"months"),s=(e-o)/(o-i)):(i=t.clone().add(a+1,"months"),s=(e-o)/(i-o)),-(a+s)}function ge(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function pe(){var t=this.clone().utc();return 0o&&(e=o),Ne.call(this,t,e,i,s,a))}function Ne(t,e,i,s,a){var o=bt(t,e,i,s,a),n=ut(o.year,0,o.dayOfYear);return this.year(n.getUTCFullYear()),this.month(n.getUTCMonth()),this.date(n.getUTCDate()),this}function Ee(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)}function Ue(t){return vt(t,this._week.dow,this._week.doy).week}function je(){return this._week.dow}function Ge(){return this._week.doy}function qe(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")}function Ze(t){var e=vt(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")}function Qe(t,e){return"string"!=typeof t?t:isNaN(t)?(t=e.weekdaysParse(t),"number"==typeof t?t:null):parseInt(t,10)}function Je(t,e){return a(this._weekdays)?this._weekdays[t.day()]:this._weekdays[this._weekdays.isFormat.test(e)?"format":"standalone"][t.day()]}function Xe(t){return this._weekdaysShort[t.day()]}function $e(t){return this._weekdaysMin[t.day()]}function Ke(t,e,i){var s,a,o;for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),s=0;7>s;s++){if(a=Pt([2e3,1]).day(s),i&&!this._fullWeekdaysParse[s]&&(this._fullWeekdaysParse[s]=new RegExp("^"+this.weekdays(a,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[s]=new RegExp("^"+this.weekdaysShort(a,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[s]=new RegExp("^"+this.weekdaysMin(a,"").replace(".",".?")+"$","i")),this._weekdaysParse[s]||(o="^"+this.weekdays(a,"")+"|^"+this.weekdaysShort(a,"")+"|^"+this.weekdaysMin(a,""),this._weekdaysParse[s]=new RegExp(o.replace(".",""),"i")),i&&"dddd"===e&&this._fullWeekdaysParse[s].test(t))return s;if(i&&"ddd"===e&&this._shortWeekdaysParse[s].test(t))return s;if(i&&"dd"===e&&this._minWeekdaysParse[s].test(t))return s;if(!i&&this._weekdaysParse[s].test(t))return s}}function ti(t){if(!this.isValid())return null!=t?this:NaN;var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=Qe(t,this.localeData()),this.add(t-e,"d")):e}function ei(t){if(!this.isValid())return null!=t?this:NaN;var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")}function ii(t){return this.isValid()?null==t?this.day()||7:this.day(this.day()%7?t:t-7):null!=t?this:NaN}function si(t){var e=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")}function ai(){return this.hours()%12||12}function oi(t,e){L(t,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),e)})}function ni(t,e){return e._meridiemParse}function ri(t){return"p"===(t+"").toLowerCase().charAt(0)}function li(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"}function hi(t,e){e[Ts]=x(1e3*("0."+t))}function ci(){return this._isUTC?"UTC":""}function di(){return this._isUTC?"Coordinated Universal Time":""}function ui(t){return Pt(1e3*t)}function fi(){return Pt.apply(null,arguments).parseZone()}function mi(t,e,i){var s=this._calendar[t];return F(s)?s.call(e,i):s}function gi(t){var e=this._longDateFormat[t],i=this._longDateFormat[t.toUpperCase()];return e||!i?e:(this._longDateFormat[t]=i.replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t])}function pi(){return this._invalidDate}function bi(t){return this._ordinal.replace("%d",t)}function vi(t){return t}function xi(t,e,i,s){var a=this._relativeTime[i];return F(a)?a(t,e,i,s):a.replace(/%d/i,t)}function yi(t,e){var i=this._relativeTime[t>0?"future":"past"];return F(i)?i(e):i.replace(/%s/i,e)}function _i(t){var e,i;for(i in t)e=t[i],F(e)?this[i]=e:this["_"+i]=e;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function ki(t,e,i,s){var a=M(),o=h().set(s,e);return a[i](o,t)}function Di(t,e,i,s,a){if("number"==typeof t&&(e=t,t=void 0),t=t||"",null!=e)return ki(t,e,i,a);var o,n=[];for(o=0;s>o;o++)n[o]=ki(t,o,i,a);return n}function Si(t,e){return Di(t,e,"months",12,"month")}function wi(t,e){return Di(t,e,"monthsShort",12,"month")}function Ci(t,e){return Di(t,e,"weekdays",7,"day")}function Mi(t,e){return Di(t,e,"weekdaysShort",7,"day")}function Ai(t,e){return Di(t,e,"weekdaysMin",7,"day")}function Ti(){var t=this._data;return this._milliseconds=ya(this._milliseconds),this._days=ya(this._days),this._months=ya(this._months),t.milliseconds=ya(t.milliseconds),t.seconds=ya(t.seconds),t.minutes=ya(t.minutes),t.hours=ya(t.hours),t.months=ya(t.months),t.years=ya(t.years),this}function Ii(t,e,i,s){var a=Kt(e,i);return t._milliseconds+=s*a._milliseconds,t._days+=s*a._days,t._months+=s*a._months,t._bubble()}function Fi(t,e){return Ii(this,t,e,1)}function Pi(t,e){return Ii(this,t,e,-1)}function Oi(t){return 0>t?Math.floor(t):Math.ceil(t)}function Vi(){var t,e,i,s,a,o=this._milliseconds,n=this._days,r=this._months,l=this._data;return o>=0&&n>=0&&r>=0||0>=o&&0>=n&&0>=r||(o+=864e5*Oi(Ri(r)+n),n=0,r=0),l.milliseconds=o%1e3,t=v(o/1e3),l.seconds=t%60,e=v(t/60),l.minutes=e%60,i=v(e/60),l.hours=i%24,n+=v(i/24),a=v(Wi(n)),r+=a,n-=Oi(Ri(a)),s=v(r/12),r%=12,l.days=n,l.months=r,l.years=s,this}function Wi(t){return 4800*t/146097}function Ri(t){return 146097*t/4800}function Li(t){var e,i,s=this._milliseconds;if(t=T(t),"month"===t||"year"===t)return e=this._days+s/864e5,i=this._months+Wi(e),"month"===t?i:i/12;switch(e=this._days+Math.round(Ri(this._months)),t){case"week":return e/7+s/6048e5;case"day":return e+s/864e5;case"hour":return 24*e+s/36e5;case"minute":return 1440*e+s/6e4;case"second":return 86400*e+s/1e3;case"millisecond":return Math.floor(864e5*e)+s;default:throw new Error("Unknown unit "+t)}}function zi(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*x(this._months/12)}function Bi(t){return function(){return this.as(t)}}function Yi(t){return t=T(t),this[t+"s"]()}function Hi(t){return function(){return this._data[t]}}function Ni(){return v(this.days()/7)}function Ei(t,e,i,s,a){return a.relativeTime(e||1,!!i,t,s)}function Ui(t,e,i){var s=Kt(t).abs(),a=Ra(s.as("s")),o=Ra(s.as("m")),n=Ra(s.as("h")),r=Ra(s.as("d")),l=Ra(s.as("M")),h=Ra(s.as("y")),c=a=o&&["m"]||o=n&&["h"]||n=r&&["d"]||r=l&&["M"]||l=h&&["y"]||["yy",h];return c[2]=e,c[3]=+t>0,c[4]=i,Ei.apply(null,c)}function ji(t,e){return void 0===La[t]?!1:void 0===e?La[t]:(La[t]=e,!0)}function Gi(t){var e=this.localeData(),i=Ui(this,!t,e);return t&&(i=e.pastFuture(+this,i)),e.postformat(i)}function qi(){var t,e,i,s=za(this._milliseconds)/1e3,a=za(this._days),o=za(this._months);t=v(s/60),e=v(t/60),s%=60,t%=60,i=v(o/12),o%=12;var n=i,r=o,l=a,h=e,c=t,d=s,u=this.asSeconds();return u?(0>u?"-":"")+"P"+(n?n+"Y":"")+(r?r+"M":"")+(l?l+"D":"")+(h||c||d?"T":"")+(h?h+"H":"")+(c?c+"M":"")+(d?d+"S":""):"P0D"}var Zi,Qi,Ji=i.momentProperties=[],Xi=!1,$i={},Ki={},ts=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,es=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,is={},ss={},as=/\d/,os=/\d\d/,ns=/\d{3}/,rs=/\d{4}/,ls=/[+-]?\d{6}/,hs=/\d\d?/,cs=/\d\d\d\d?/,ds=/\d\d\d\d\d\d?/,us=/\d{1,3}/,fs=/\d{1,4}/,ms=/[+-]?\d{1,6}/,gs=/\d+/,ps=/[+-]?\d+/,bs=/Z|[+-]\d\d:?\d\d/gi,vs=/Z|[+-]\d\d(?::?\d\d)?/gi,xs=/[+-]?\d+(\.\d{1,3})?/,ys=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,_s={},ks={},Ds=0,Ss=1,ws=2,Cs=3,Ms=4,As=5,Ts=6,Is=7,Fs=8;L("M",["MM",2],"Mo",function(){return this.month()+1}),L("MMM",0,0,function(t){return this.localeData().monthsShort(this,t)}),L("MMMM",0,0,function(t){return this.localeData().months(this,t)}),A("month","M"),N("M",hs),N("MM",hs,os),N("MMM",function(t,e){return e.monthsShortRegex(t)}),N("MMMM",function(t,e){return e.monthsRegex(t)}),G(["M","MM"],function(t,e){e[Ss]=x(t)-1}),G(["MMM","MMMM"],function(t,e,i,s){var a=i._locale.monthsParse(t,s,i._strict);null!=a?e[Ss]=a:d(i).invalidMonth=t});var Ps=/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/,Os="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),Vs="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),Ws=ys,Rs=ys,Ls={};i.suppressDeprecationWarnings=!1;var zs=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,Bs=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,Ys=/Z|[+-]\d\d(?::?\d\d)?/,Hs=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Ns=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Es=/^\/?Date\((\-?\d+)/i;i.createFromInputFallback=rt("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),L("Y",0,0,function(){var t=this.year();return 9999>=t?""+t:"+"+t}),L(0,["YY",2],0,function(){return this.year()%100}),L(0,["YYYY",4],0,"year"),L(0,["YYYYY",5],0,"year"),L(0,["YYYYYY",6,!0],0,"year"),A("year","y"),N("Y",ps),N("YY",hs,os),N("YYYY",fs,rs),N("YYYYY",ms,ls),N("YYYYYY",ms,ls),G(["YYYYY","YYYYYY"],Ds),G("YYYY",function(t,e){e[Ds]=2===t.length?i.parseTwoDigitYear(t):x(t)}),G("YY",function(t,e){e[Ds]=i.parseTwoDigitYear(t)}),G("Y",function(t,e){e[Ds]=parseInt(t,10)}),i.parseTwoDigitYear=function(t){return x(t)+(x(t)>68?1900:2e3)};var Us=P("FullYear",!1);i.ISO_8601=function(){};var js=rt("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var t=Pt.apply(null,arguments);return this.isValid()&&t.isValid()?this>t?this:t:f()}),Gs=rt("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var t=Pt.apply(null,arguments);return this.isValid()&&t.isValid()?t>this?this:t:f()}),qs=function(){return Date.now?Date.now():+new Date};zt("Z",":"),zt("ZZ",""),N("Z",vs),N("ZZ",vs),G(["Z","ZZ"],function(t,e,i){i._useUTC=!0,i._tzm=Bt(vs,t)});var Zs=/([\+\-]|\d\d)/gi;i.updateOffset=function(){};var Qs=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/,Js=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Kt.fn=Rt.prototype;var Xs=se(1,"add"),$s=se(-1,"subtract");i.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var Ks=rt("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return void 0===t?this.localeData():this.locale(t)});L(0,["gg",2],0,function(){return this.weekYear()%100}),L(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Re("gggg","weekYear"),Re("ggggg","weekYear"),Re("GGGG","isoWeekYear"),Re("GGGGG","isoWeekYear"),A("weekYear","gg"),A("isoWeekYear","GG"),N("G",ps),N("g",ps),N("GG",hs,os),N("gg",hs,os),N("GGGG",fs,rs),N("gggg",fs,rs),N("GGGGG",ms,ls),N("ggggg",ms,ls),q(["gggg","ggggg","GGGG","GGGGG"],function(t,e,i,s){e[s.substr(0,2)]=x(t)}),q(["gg","GG"],function(t,e,s,a){e[a]=i.parseTwoDigitYear(t)}),L("Q",0,"Qo","quarter"),A("quarter","Q"),N("Q",as),G("Q",function(t,e){e[Ss]=3*(x(t)-1)}),L("w",["ww",2],"wo","week"),L("W",["WW",2],"Wo","isoWeek"),A("week","w"),A("isoWeek","W"),N("w",hs),N("ww",hs,os),N("W",hs),N("WW",hs,os),q(["w","ww","W","WW"],function(t,e,i,s){e[s.substr(0,1)]=x(t)});var ta={dow:0,doy:6};L("D",["DD",2],"Do","date"),A("date","D"),N("D",hs),N("DD",hs,os),N("Do",function(t,e){return t?e._ordinalParse:e._ordinalParseLenient}),G(["D","DD"],ws),G("Do",function(t,e){e[ws]=x(t.match(hs)[0],10)});var ea=P("Date",!0);L("d",0,"do","day"),L("dd",0,0,function(t){return this.localeData().weekdaysMin(this,t)}),L("ddd",0,0,function(t){return this.localeData().weekdaysShort(this,t)}),L("dddd",0,0,function(t){return this.localeData().weekdays(this,t)}),L("e",0,0,"weekday"),L("E",0,0,"isoWeekday"),A("day","d"),A("weekday","e"),A("isoWeekday","E"),N("d",hs),N("e",hs),N("E",hs),N("dd",ys),N("ddd",ys),N("dddd",ys),q(["dd","ddd","dddd"],function(t,e,i,s){var a=i._locale.weekdaysParse(t,s,i._strict);null!=a?e.d=a:d(i).invalidWeekday=t}),q(["d","e","E"],function(t,e,i,s){e[s]=x(t)});var ia="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),sa="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),aa="Su_Mo_Tu_We_Th_Fr_Sa".split("_");L("DDD",["DDDD",3],"DDDo","dayOfYear"),A("dayOfYear","DDD"),N("DDD",us),N("DDDD",ns),G(["DDD","DDDD"],function(t,e,i){i._dayOfYear=x(t)}),L("H",["HH",2],0,"hour"),L("h",["hh",2],0,ai),L("hmm",0,0,function(){return""+ai.apply(this)+R(this.minutes(),2)}),L("hmmss",0,0,function(){return""+ai.apply(this)+R(this.minutes(),2)+R(this.seconds(),2)}),L("Hmm",0,0,function(){return""+this.hours()+R(this.minutes(),2)}),L("Hmmss",0,0,function(){return""+this.hours()+R(this.minutes(),2)+R(this.seconds(),2)}),oi("a",!0),oi("A",!1),A("hour","h"),N("a",ni),N("A",ni),N("H",hs),N("h",hs),N("HH",hs,os),N("hh",hs,os),N("hmm",cs),N("hmmss",ds),N("Hmm",cs),N("Hmmss",ds),G(["H","HH"],Cs),G(["a","A"],function(t,e,i){i._isPm=i._locale.isPM(t),i._meridiem=t}),G(["h","hh"],function(t,e,i){e[Cs]=x(t),d(i).bigHour=!0}),G("hmm",function(t,e,i){var s=t.length-2;e[Cs]=x(t.substr(0,s)),e[Ms]=x(t.substr(s)),d(i).bigHour=!0}),G("hmmss",function(t,e,i){var s=t.length-4,a=t.length-2;e[Cs]=x(t.substr(0,s)),e[Ms]=x(t.substr(s,2)),e[As]=x(t.substr(a)),d(i).bigHour=!0}),G("Hmm",function(t,e,i){var s=t.length-2;e[Cs]=x(t.substr(0,s)),e[Ms]=x(t.substr(s))}),G("Hmmss",function(t,e,i){var s=t.length-4,a=t.length-2;e[Cs]=x(t.substr(0,s)),e[Ms]=x(t.substr(s,2)),e[As]=x(t.substr(a))});var oa=/[ap]\.?m?\.?/i,na=P("Hours",!0);L("m",["mm",2],0,"minute"),A("minute","m"),N("m",hs),N("mm",hs,os),G(["m","mm"],Ms);var ra=P("Minutes",!1);L("s",["ss",2],0,"second"),A("second","s"),N("s",hs),N("ss",hs,os),G(["s","ss"],As);var la=P("Seconds",!1);L("S",0,0,function(){return~~(this.millisecond()/100)}),L(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),L(0,["SSS",3],0,"millisecond"),L(0,["SSSS",4],0,function(){return 10*this.millisecond()}),L(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),L(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),L(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),L(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),L(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),A("millisecond","ms"),N("S",us,as),N("SS",us,os),N("SSS",us,ns);var ha;for(ha="SSSS";ha.length<=9;ha+="S")N(ha,gs);for(ha="S";ha.length<=9;ha+="S")G(ha,hi);var ca=P("Milliseconds",!1);L("z",0,0,"zoneAbbr"),L("zz",0,0,"zoneName");var da=p.prototype;da.add=Xs,da.calendar=oe,da.clone=ne,da.diff=fe,da.endOf=we,da.format=be,da.from=ve,da.fromNow=xe,da.to=ye,da.toNow=_e,da.get=W,da.invalidAt=Ve,da.isAfter=re,da.isBefore=le,da.isBetween=he,da.isSame=ce,da.isSameOrAfter=de,da.isSameOrBefore=ue,da.isValid=Pe,da.lang=Ks,da.locale=ke,da.localeData=De,da.max=Gs,da.min=js,da.parsingFlags=Oe,da.set=W,da.startOf=Se,da.subtract=$s,da.toArray=Te,da.toObject=Ie,da.toDate=Ae,da.toISOString=pe,da.toJSON=Fe,da.toString=ge,da.unix=Me,da.valueOf=Ce,da.creationData=We,da.year=Us,da.isLeapYear=gt,da.weekYear=Le,da.isoWeekYear=ze,da.quarter=da.quarters=Ee,da.month=tt,da.daysInMonth=et,da.week=da.weeks=qe,da.isoWeek=da.isoWeeks=Ze,da.weeksInYear=Ye,da.isoWeeksInYear=Be,da.date=ea,da.day=da.days=ti,da.weekday=ei,da.isoWeekday=ii,da.dayOfYear=si,da.hour=da.hours=na,da.minute=da.minutes=ra,da.second=da.seconds=la,da.millisecond=da.milliseconds=ca,da.utcOffset=Nt,da.utc=Ut,da.local=jt,da.parseZone=Gt,da.hasAlignedHourOffset=qt,da.isDST=Zt,da.isDSTShifted=Qt,da.isLocal=Jt,da.isUtcOffset=Xt,da.isUtc=$t,da.isUTC=$t,da.zoneAbbr=ci,da.zoneName=di,da.dates=rt("dates accessor is deprecated. Use date instead.",ea),da.months=rt("months accessor is deprecated. Use month instead",tt),da.years=rt("years accessor is deprecated. Use year instead",Us),da.zone=rt("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Et);var ua=da,fa={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},ma={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},ga="Invalid date",pa="%d",ba=/\d{1,2}/,va={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},xa=_.prototype;xa._calendar=fa,xa.calendar=mi,xa._longDateFormat=ma,xa.longDateFormat=gi,xa._invalidDate=ga,xa.invalidDate=pi,xa._ordinal=pa,xa.ordinal=bi,xa._ordinalParse=ba,xa.preparse=vi,xa.postformat=vi,xa._relativeTime=va,xa.relativeTime=xi,xa.pastFuture=yi,xa.set=_i,xa.months=J,xa._months=Os,xa.monthsShort=X,xa._monthsShort=Vs,xa.monthsParse=$,xa._monthsRegex=Rs,xa.monthsRegex=st,xa._monthsShortRegex=Ws,xa.monthsShortRegex=it,xa.week=Ue,xa._week=ta,xa.firstDayOfYear=Ge,xa.firstDayOfWeek=je,xa.weekdays=Je,xa._weekdays=ia,xa.weekdaysMin=$e,xa._weekdaysMin=aa,xa.weekdaysShort=Xe,xa._weekdaysShort=sa,xa.weekdaysParse=Ke,xa.isPM=ri,xa._meridiemParse=oa,xa.meridiem=li,w("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,i=1===x(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),i.lang=rt("moment.lang is deprecated. Use moment.locale instead.",w),i.langData=rt("moment.langData is deprecated. Use moment.localeData instead.",M);var ya=Math.abs,_a=Bi("ms"),ka=Bi("s"),Da=Bi("m"),Sa=Bi("h"),wa=Bi("d"),Ca=Bi("w"),Ma=Bi("M"),Aa=Bi("y"),Ta=Hi("milliseconds"),Ia=Hi("seconds"),Fa=Hi("minutes"),Pa=Hi("hours"),Oa=Hi("days"),Va=Hi("months"),Wa=Hi("years"),Ra=Math.round,La={s:45,m:45,h:22,d:26,M:11},za=Math.abs,Ba=Rt.prototype;Ba.abs=Ti,Ba.add=Fi,Ba.subtract=Pi,Ba.as=Li,Ba.asMilliseconds=_a,Ba.asSeconds=ka,Ba.asMinutes=Da,Ba.asHours=Sa,Ba.asDays=wa,Ba.asWeeks=Ca,Ba.asMonths=Ma,Ba.asYears=Aa,Ba.valueOf=zi,Ba._bubble=Vi,Ba.get=Yi,Ba.milliseconds=Ta,Ba.seconds=Ia,Ba.minutes=Fa,Ba.hours=Pa,Ba.days=Oa,Ba.weeks=Ni,Ba.months=Va,Ba.years=Wa,Ba.humanize=Gi,Ba.toISOString=qi,Ba.toString=qi,Ba.toJSON=qi,Ba.locale=ke,Ba.localeData=De,Ba.toIsoString=rt("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",qi),Ba.lang=Ks,L("X",0,0,"unix"),L("x",0,0,"valueOf"),N("x",ps),N("X",xs),G("X",function(t,e,i){i._d=new Date(1e3*parseFloat(t,10))}),G("x",function(t,e,i){i._d=new Date(x(t))}),i.version="2.11.2",s(Pt),i.fn=ua,i.min=Vt,i.max=Wt,i.now=qs,i.utc=h,i.unix=ui,i.months=Si,i.isDate=o,i.locale=w,i.invalid=f,i.duration=Kt,i.isMoment=b,i.weekdays=Ci,i.parseZone=fi,i.localeData=M,i.isDuration=Lt,i.monthsShort=wi,i.weekdaysMin=Ai,i.defineLocale=C,i.weekdaysShort=Mi,i.normalizeUnits=T,i.relativeTimeThreshold=ji,i.prototype=ua;var Ya=i;return Ya})},{}],7:[function(t,e,i){/*! + * Chart.js + * http://chartjs.org/ + * Version: 2.0.0-beta2 + * + * Copyright 2015 Nick Downie + * Released under the MIT license + * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md + */ +var s=t("./core/core.js")();t("./core/core.helpers")(s),t("./core/core.element")(s),t("./core/core.animation")(s),t("./core/core.controller")(s),t("./core/core.datasetController")(s),t("./core/core.layoutService")(s),t("./core/core.legend")(s),t("./core/core.scale")(s),t("./core/core.scaleService")(s),t("./core/core.title")(s),t("./core/core.tooltip")(s),t("./controllers/controller.bar")(s),t("./controllers/controller.bubble")(s),t("./controllers/controller.doughnut")(s),t("./controllers/controller.line")(s),t("./controllers/controller.polarArea")(s),t("./controllers/controller.radar")(s),t("./scales/scale.category")(s),t("./scales/scale.linear")(s),t("./scales/scale.logarithmic")(s),t("./scales/scale.radialLinear")(s),t("./scales/scale.time")(s),t("./elements/element.arc")(s),t("./elements/element.line")(s),t("./elements/element.point")(s),t("./elements/element.rectangle")(s),t("./charts/Chart.Bar")(s),t("./charts/Chart.Bubble")(s),t("./charts/Chart.Doughnut")(s),t("./charts/Chart.Line")(s),t("./charts/Chart.PolarArea")(s),t("./charts/Chart.Radar")(s),t("./charts/Chart.Scatter")(s),window.Chart=e.exports=s},{"./charts/Chart.Bar":8,"./charts/Chart.Bubble":9,"./charts/Chart.Doughnut":10,"./charts/Chart.Line":11,"./charts/Chart.PolarArea":12,"./charts/Chart.Radar":13,"./charts/Chart.Scatter":14,"./controllers/controller.bar":15,"./controllers/controller.bubble":16,"./controllers/controller.doughnut":17,"./controllers/controller.line":18,"./controllers/controller.polarArea":19,"./controllers/controller.radar":20,"./core/core.animation":21,"./core/core.controller":22,"./core/core.datasetController":23,"./core/core.element":24,"./core/core.helpers":25,"./core/core.js":26,"./core/core.layoutService":27,"./core/core.legend":28,"./core/core.scale":29,"./core/core.scaleService":30,"./core/core.title":31,"./core/core.tooltip":32,"./elements/element.arc":33,"./elements/element.line":34,"./elements/element.point":35,"./elements/element.rectangle":36,"./scales/scale.category":37,"./scales/scale.linear":38,"./scales/scale.logarithmic":39,"./scales/scale.radialLinear":40,"./scales/scale.time":41}],8:[function(t,e,i){"use strict";e.exports=function(t){t.Bar=function(e,i){return i.type="bar",new t(e,i)}}},{}],9:[function(t,e,i){"use strict";e.exports=function(t){t.Bubble=function(e,i){return i.type="bubble",new t(e,i)}}},{}],10:[function(t,e,i){"use strict";e.exports=function(t){t.Doughnut=function(e,i){return i.type="doughnut",new t(e,i)}}},{}],11:[function(t,e,i){"use strict";e.exports=function(t){t.Line=function(e,i){return i.type="line",new t(e,i)}}},{}],12:[function(t,e,i){"use strict";e.exports=function(t){t.PolarArea=function(e,i){return i.type="polarArea",new t(e,i)}}},{}],13:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers,i={aspectRatio:1};t.Radar=function(s,a){return a.options=e.configMerge(i,a.options),a.type="radar",new t(s,a)}}},{}],14:[function(t,e,i){"use strict";e.exports=function(t){var e={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-1"}],yAxes:[{type:"linear",position:"left",id:"y-axis-1"}]},tooltips:{callbacks:{title:function(t,e){return""},label:function(t,e){return"("+t.xLabel+", "+t.yLabel+")"}}}};t.defaults.scatter=e,t.controllers.scatter=t.controllers.line,t.Scatter=function(e,i){return i.type="scatter",new t(e,i)}}},{}],15:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.bar={hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}},t.controllers.bar=t.DatasetController.extend({initialize:function(e,i){t.DatasetController.prototype.initialize.call(this,e,i),this.getDataset().bar=!0},getBarCount:function(){var t=0;return e.each(this.chart.data.datasets,function(i){e.isDatasetVisible(i)&&i.bar&&++t}),t},addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],e.each(this.getDataset().data,function(e,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new t.elements.Rectangle({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(e){this.getDataset().metaData=this.getDataset().metaData||[];var i=new t.elements.Rectangle({_chart:this.chart.chart,_datasetIndex:this.index,_index:e}),s=this.getBarCount();this.updateElement(i,e,!0,s),this.getDataset().metaData.splice(e,0,i)},update:function(t){var i=this.getBarCount();e.each(this.getDataset().metaData,function(e,s){this.updateElement(e,s,t,i)},this)},updateElement:function(t,i,s,a){var o,n=this.getScaleForId(this.getDataset().xAxisID),r=this.getScaleForId(this.getDataset().yAxisID);o=r.min<0&&r.max<0?r.getPixelForValue(r.max):r.min>0&&r.max>0?r.getPixelForValue(r.min):r.getPixelForValue(0),e.extend(t,{_chart:this.chart.chart,_xScale:n,_yScale:r,_datasetIndex:this.index,_index:i,_model:{x:this.calculateBarX(i,this.index),y:s?o:this.calculateBarY(i,this.index),label:this.chart.data.labels[i],datasetLabel:this.getDataset().label,base:s?o:this.calculateBarBase(this.index,i),width:this.calculateBarWidth(a),backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().backgroundColor,i,this.chart.options.elements.rectangle.backgroundColor),borderSkipped:t.custom&&t.custom.borderSkipped?t.custom.borderSkipped:this.chart.options.elements.rectangle.borderSkipped,borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().borderColor,i,this.chart.options.elements.rectangle.borderColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().borderWidth,i,this.chart.options.elements.rectangle.borderWidth)}}),t.pivot()},calculateBarBase:function(t,i){var s=(this.getScaleForId(this.getDataset().xAxisID),this.getScaleForId(this.getDataset().yAxisID)),a=0;if(s.options.stacked){var o=this.chart.data.datasets[t].data[i];if(0>o)for(var n=0;t>n;n++){var r=this.chart.data.datasets[n];e.isDatasetVisible(r)&&r.yAxisID===s.id&&r.bar&&(a+=r.data[i]<0?r.data[i]:0)}else for(var l=0;t>l;l++){var h=this.chart.data.datasets[l];e.isDatasetVisible(h)&&h.yAxisID===s.id&&h.bar&&(a+=h.data[i]>0?h.data[i]:0)}return s.getPixelForValue(a)}return a=s.getPixelForValue(s.min),s.beginAtZero||s.min<=0&&s.max>=0||s.min>=0&&s.max<=0?a=s.getPixelForValue(0,0):s.min<0&&s.max<0&&(a=s.getPixelForValue(s.max)),a},getRuler:function(){var t=this.getScaleForId(this.getDataset().xAxisID),e=(this.getScaleForId(this.getDataset().yAxisID),this.getBarCount()),i=function(){for(var e=t.getPixelForTick(1)-t.getPixelForTick(0),i=2;is;++s)e.isDatasetVisible(this.chart.data.datasets[s])&&this.chart.data.datasets[s].bar&&++i;return i},calculateBarX:function(t,e){var i=(this.getScaleForId(this.getDataset().yAxisID),this.getScaleForId(this.getDataset().xAxisID)),s=this.getBarIndex(e),a=this.getRuler(),o=i.getPixelForValue(null,t,e,this.chart.isCombo);return o-=this.chart.isCombo?a.tickWidth/2:0,i.options.stacked?o+a.categoryWidth/2+a.categorySpacing:o+a.barWidth/2+a.categorySpacing+a.barWidth*s+a.barSpacing/2+a.barSpacing*s},calculateBarY:function(t,i){var s=(this.getScaleForId(this.getDataset().xAxisID),this.getScaleForId(this.getDataset().yAxisID)),a=this.getDataset().data[t];if(s.options.stacked){for(var o=0,n=0,r=0;i>r;r++){var l=this.chart.data.datasets[r];e.isDatasetVisible(l)&&l.bar&&l.yAxisID===s.id&&(l.data[t]<0?n+=l.data[t]||0:o+=l.data[t]||0)}return 0>a?s.getPixelForValue(n+a):s.getPixelForValue(o+a)}return s.getPixelForValue(a)},draw:function(t){var i=t||1;e.each(this.getDataset().metaData,function(t,e){var s=this.getDataset().data[e];null===s||void 0===s||isNaN(s)||t.transition(i).draw()},this)},setHoverStyle:function(t){var i=this.chart.data.datasets[t._datasetIndex],s=t._index;t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:e.getValueAtIndexOrDefault(i.hoverBackgroundColor,s,e.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:e.getValueAtIndexOrDefault(i.hoverBorderColor,s,e.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:e.getValueAtIndexOrDefault(i.hoverBorderWidth,s,t._model.borderWidth)},removeHoverStyle:function(t){var i=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.backgroundColor=t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().backgroundColor,i,this.chart.options.elements.rectangle.backgroundColor),t._model.borderColor=t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().borderColor,i,this.chart.options.elements.rectangle.borderColor),t._model.borderWidth=t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().borderWidth,i,this.chart.options.elements.rectangle.borderWidth)}})}},{}],16:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.bubble={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(t,e){return""},label:function(t,e){var i=e.datasets[t.datasetIndex].label||"",s=e.datasets[t.datasetIndex].data[t.index];return i+": ("+s.x+", "+s.y+", "+s.r+")"}}}},t.controllers.bubble=t.DatasetController.extend({addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],e.each(this.getDataset().data,function(e,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new t.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(e){this.getDataset().metaData=this.getDataset().metaData||[];var i=new t.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:e});this.updateElement(i,e,!0),this.getDataset().metaData.splice(e,0,i)},update:function(t){var i,s=this.getDataset().metaData,a=this.getScaleForId(this.getDataset().yAxisID);this.getScaleForId(this.getDataset().xAxisID);i=a.min<0&&a.max<0?a.getPixelForValue(a.max):a.min>0&&a.max>0?a.getPixelForValue(a.min):a.getPixelForValue(0),e.each(s,function(e,i){this.updateElement(e,i,t)},this)},updateElement:function(t,i,s){var a,o=this.getScaleForId(this.getDataset().yAxisID),n=this.getScaleForId(this.getDataset().xAxisID);a=o.min<0&&o.max<0?o.getPixelForValue(o.max):o.min>0&&o.max>0?o.getPixelForValue(o.min):o.getPixelForValue(0),e.extend(t,{_chart:this.chart.chart,_xScale:n,_yScale:o,_datasetIndex:this.index,_index:i,_model:{x:s?n.getPixelForDecimal(.5):n.getPixelForValue(this.getDataset().data[i],i,this.index,this.chart.isCombo),y:s?a:o.getPixelForValue(this.getDataset().data[i],i,this.index),radius:s?0:t.custom&&t.custom.radius?t.custom.radius:this.getRadius(this.getDataset().data[i]),backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().backgroundColor,i,this.chart.options.elements.point.backgroundColor),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().borderColor,i,this.chart.options.elements.point.borderColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().borderWidth,i,this.chart.options.elements.point.borderWidth),hitRadius:t.custom&&t.custom.hitRadius?t.custom.hitRadius:e.getValueAtIndexOrDefault(this.getDataset().hitRadius,i,this.chart.options.elements.point.hitRadius)}}),t._model.skip=t.custom&&t.custom.skip?t.custom.skip:isNaN(t._model.x)||isNaN(t._model.y),t.pivot()},getRadius:function(t){return t.r||this.chart.options.elements.point.radius},draw:function(t){var i=t||1;e.each(this.getDataset().metaData,function(t,e){t.transition(i),t.draw()})},setHoverStyle:function(t){var i=this.chart.data.datasets[t._datasetIndex],s=t._index;t._model.radius=t.custom&&t.custom.hoverRadius?t.custom.hoverRadius:e.getValueAtIndexOrDefault(i.hoverRadius,s,this.chart.options.elements.point.hoverRadius)+this.getRadius(this.getDataset().data[t._index]),t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:e.getValueAtIndexOrDefault(i.hoverBackgroundColor,s,e.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:e.getValueAtIndexOrDefault(i.hoverBorderColor,s,e.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:e.getValueAtIndexOrDefault(i.hoverBorderWidth,s,t._model.borderWidth)},removeHoverStyle:function(t){var i=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.radius=t.custom&&t.custom.radius?t.custom.radius:this.getRadius(this.getDataset().data[t._index]),t._model.backgroundColor=t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().backgroundColor,i,this.chart.options.elements.point.backgroundColor),t._model.borderColor=t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().borderColor,i,this.chart.options.elements.point.borderColor),t._model.borderWidth=t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().borderWidth,i,this.chart.options.elements.point.borderWidth)}})}},{}],17:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.doughnut={animation:{animateRotate:!0,animateScale:!1},aspectRatio:1,hover:{mode:"single"},legendCallback:function(t){var e=[];if(e.push('
    '),t.data.datasets.length)for(var i=0;i'),t.data.labels[i]&&e.push(t.data.labels[i]),e.push("");return e.push("
"),e.join("")},legend:{labels:{generateLabels:function(t){return t.labels.length&&t.datasets.length?t.labels.map(function(e,i){return{text:e,fillStyle:t.datasets[0].backgroundColor[i],hidden:isNaN(t.datasets[0].data[i]),index:i}}):[]}},onClick:function(t,i){e.each(this.chart.data.datasets,function(t){t.metaHiddenData=t.metaHiddenData||[];var e=i.index;isNaN(t.data[e])?isNaN(t.metaHiddenData[e])||(t.data[e]=t.metaHiddenData[e]):(t.metaHiddenData[e]=t.data[e],t.data[e]=NaN)}),this.chart.update()}},cutoutPercentage:50,tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+e.datasets[t.datasetIndex].data[t.index]}}}},t.defaults.pie=e.clone(t.defaults.doughnut),e.extend(t.defaults.pie,{cutoutPercentage:0}),t.controllers.doughnut=t.controllers.pie=t.DatasetController.extend({linkScales:function(){},addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],e.each(this.getDataset().data,function(e,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new t.elements.Arc({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(i,s){this.getDataset().metaData=this.getDataset().metaData||[];var a=new t.elements.Arc({_chart:this.chart.chart,_datasetIndex:this.index,_index:i});s&&e.isArray(this.getDataset().backgroundColor)&&this.getDataset().backgroundColor.splice(i,0,s),this.updateElement(a,i,!0),this.getDataset().metaData.splice(i,0,a)},getVisibleDatasetCount:function(){return e.where(this.chart.data.datasets,function(t){return e.isDatasetVisible(t)}).length},getRingIndex:function(t){for(var i=0,s=0;t>s;++s)e.isDatasetVisible(this.chart.data.datasets[s])&&++i;return i},update:function(t){var i=Math.min(this.chart.chartArea.right-this.chart.chartArea.left,this.chart.chartArea.bottom-this.chart.chartArea.top);this.chart.outerRadius=Math.max(i/2-this.chart.options.elements.arc.borderWidth/2,0),this.chart.innerRadius=Math.max(this.chart.options.cutoutPercentage?this.chart.outerRadius/100*this.chart.options.cutoutPercentage:1,0),this.chart.radiusLength=(this.chart.outerRadius-this.chart.innerRadius)/this.getVisibleDatasetCount(),this.getDataset().total=0,e.each(this.getDataset().data,function(t){isNaN(t)||(this.getDataset().total+=Math.abs(t))},this),this.outerRadius=this.chart.outerRadius-this.chart.radiusLength*this.getRingIndex(this.index),this.innerRadius=this.outerRadius-this.chart.radiusLength,e.each(this.getDataset().metaData,function(e,i){this.updateElement(e,i,t)},this)},updateElement:function(t,i,s){var a=(this.chart.chartArea.left+this.chart.chartArea.right)/2,o=(this.chart.chartArea.top+this.chart.chartArea.bottom)/2,n=Math.PI*-.5,r=Math.PI*-.5,l=s&&this.chart.options.animation.animateRotate?0:this.calculateCircumference(this.getDataset().data[i]),h=s&&this.chart.options.animation.animateScale?0:this.innerRadius,c=s&&this.chart.options.animation.animateScale?0:this.outerRadius;e.extend(t,{_chart:this.chart.chart,_datasetIndex:this.index,_index:i,_model:{x:a,y:o,startAngle:n,endAngle:r,circumference:l,outerRadius:c,innerRadius:h,backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().backgroundColor,i,this.chart.options.elements.arc.backgroundColor),hoverBackgroundColor:t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:e.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor,i,this.chart.options.elements.arc.hoverBackgroundColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().borderWidth,i,this.chart.options.elements.arc.borderWidth),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().borderColor,i,this.chart.options.elements.arc.borderColor),label:e.getValueAtIndexOrDefault(this.getDataset().label,i,this.chart.data.labels[i])}}),s||(0===i?t._model.startAngle=Math.PI*-.5:t._model.startAngle=this.getDataset().metaData[i-1]._model.endAngle,t._model.endAngle=t._model.startAngle+t._model.circumference),t.pivot()},draw:function(t){var i=t||1;e.each(this.getDataset().metaData,function(t,e){t.transition(i).draw()})},setHoverStyle:function(t){var i=this.chart.data.datasets[t._datasetIndex],s=t._index;t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:e.getValueAtIndexOrDefault(i.hoverBackgroundColor,s,e.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:e.getValueAtIndexOrDefault(i.hoverBorderColor,s,e.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:e.getValueAtIndexOrDefault(i.hoverBorderWidth,s,t._model.borderWidth)},removeHoverStyle:function(t){var i=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.backgroundColor=t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().backgroundColor,i,this.chart.options.elements.arc.backgroundColor),t._model.borderColor=t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().borderColor,i,this.chart.options.elements.arc.borderColor),t._model.borderWidth=t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().borderWidth,i,this.chart.options.elements.arc.borderWidth)},calculateCircumference:function(t){return this.getDataset().total>0&&!isNaN(t)?1.999999*Math.PI*(t/this.getDataset().total):0}})}},{}],18:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.line={showLines:!0,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}},t.controllers.line=t.DatasetController.extend({addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],this.getDataset().metaDataset=this.getDataset().metaDataset||new t.elements.Line({_chart:this.chart.chart,_datasetIndex:this.index,_points:this.getDataset().metaData}),e.each(this.getDataset().data,function(e,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new t.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(e){this.getDataset().metaData=this.getDataset().metaData||[];var i=new t.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:e});this.updateElement(i,e,!0),this.getDataset().metaData.splice(e,0,i),this.chart.options.showLines&&0!==this.chart.options.elements.line.tension&&this.updateBezierControlPoints()},update:function(t){var i,s=this.getDataset().metaDataset,a=this.getDataset().metaData,o=this.getScaleForId(this.getDataset().yAxisID);this.getScaleForId(this.getDataset().xAxisID);i=o.min<0&&o.max<0?o.getPixelForValue(o.max):o.min>0&&o.max>0?o.getPixelForValue(o.min):o.getPixelForValue(0),this.chart.options.showLines&&(s._scale=o,s._datasetIndex=this.index,s._children=a,s._model={tension:s.custom&&s.custom.tension?s.custom.tension:e.getValueOrDefault(this.getDataset().tension,this.chart.options.elements.line.tension),backgroundColor:s.custom&&s.custom.backgroundColor?s.custom.backgroundColor:this.getDataset().backgroundColor||this.chart.options.elements.line.backgroundColor,borderWidth:s.custom&&s.custom.borderWidth?s.custom.borderWidth:this.getDataset().borderWidth||this.chart.options.elements.line.borderWidth,borderColor:s.custom&&s.custom.borderColor?s.custom.borderColor:this.getDataset().borderColor||this.chart.options.elements.line.borderColor,borderCapStyle:s.custom&&s.custom.borderCapStyle?s.custom.borderCapStyle:this.getDataset().borderCapStyle||this.chart.options.elements.line.borderCapStyle,borderDash:s.custom&&s.custom.borderDash?s.custom.borderDash:this.getDataset().borderDash||this.chart.options.elements.line.borderDash,borderDashOffset:s.custom&&s.custom.borderDashOffset?s.custom.borderDashOffset:this.getDataset().borderDashOffset||this.chart.options.elements.line.borderDashOffset,borderJoinStyle:s.custom&&s.custom.borderJoinStyle?s.custom.borderJoinStyle:this.getDataset().borderJoinStyle||this.chart.options.elements.line.borderJoinStyle,fill:s.custom&&s.custom.fill?s.custom.fill:void 0!==this.getDataset().fill?this.getDataset().fill:this.chart.options.elements.line.fill,scaleTop:o.top,scaleBottom:o.bottom,scaleZero:i},s.pivot()),e.each(a,function(e,i){this.updateElement(e,i,t)},this),this.chart.options.showLines&&0!==this.chart.options.elements.line.tension&&this.updateBezierControlPoints()},getPointBackgroundColor:function(t,i){var s=this.chart.options.elements.point.backgroundColor,a=this.getDataset();return t.custom&&t.custom.backgroundColor?s=t.custom.backgroundColor:a.pointBackgroundColor?s=e.getValueAtIndexOrDefault(a.pointBackgroundColor,i,s):a.backgroundColor&&(s=a.backgroundColor),s},getPointBorderColor:function(t,i){var s=this.chart.options.elements.point.borderColor,a=this.getDataset();return t.custom&&t.custom.borderColor?s=t.custom.borderColor:a.pointBorderColor?s=e.getValueAtIndexOrDefault(this.getDataset().pointBorderColor,i,s):a.borderColor&&(s=a.borderColor),s},getPointBorderWidth:function(t,i){var s=this.chart.options.elements.point.borderWidth,a=this.getDataset();return t.custom&&void 0!==t.custom.borderWidth?s=t.custom.borderWidth:void 0!==a.pointBorderWidth?s=e.getValueAtIndexOrDefault(a.pointBorderWidth,i,s):void 0!==a.borderWidth&&(s=a.borderWidth),s},updateElement:function(t,i,s){var a,o=this.getScaleForId(this.getDataset().yAxisID),n=this.getScaleForId(this.getDataset().xAxisID);a=o.min<0&&o.max<0?o.getPixelForValue(o.max):o.min>0&&o.max>0?o.getPixelForValue(o.min):o.getPixelForValue(0),t._chart=this.chart.chart,t._xScale=n,t._yScale=o,t._datasetIndex=this.index,t._index=i,t._model={x:n.getPixelForValue(this.getDataset().data[i],i,this.index,this.chart.isCombo),y:s?a:this.calculatePointY(this.getDataset().data[i],i,this.index,this.chart.isCombo),tension:t.custom&&t.custom.tension?t.custom.tension:e.getValueOrDefault(this.getDataset().tension,this.chart.options.elements.line.tension),radius:t.custom&&t.custom.radius?t.custom.radius:e.getValueAtIndexOrDefault(this.getDataset().radius,i,this.chart.options.elements.point.radius),pointStyle:t.custom&&t.custom.pointStyle?t.custom.pointStyle:e.getValueAtIndexOrDefault(this.getDataset().pointStyle,i,this.chart.options.elements.point.pointStyle),backgroundColor:this.getPointBackgroundColor(t,i),borderColor:this.getPointBorderColor(t,i),borderWidth:this.getPointBorderWidth(t,i),hitRadius:t.custom&&t.custom.hitRadius?t.custom.hitRadius:e.getValueAtIndexOrDefault(this.getDataset().hitRadius,i,this.chart.options.elements.point.hitRadius)},t._model.skip=t.custom&&t.custom.skip?t.custom.skip:isNaN(t._model.x)||isNaN(t._model.y)},calculatePointY:function(t,i,s,a){var o=(this.getScaleForId(this.getDataset().xAxisID),this.getScaleForId(this.getDataset().yAxisID));if(o.options.stacked){for(var n=0,r=0,l=0;s>l;l++){var h=this.chart.data.datasets[l];"line"===h.type&&e.isDatasetVisible(h)&&(h.data[i]<0?r+=h.data[i]||0:n+=h.data[i]||0)}return 0>t?o.getPixelForValue(r+t):o.getPixelForValue(n+t)}return o.getPixelForValue(t)},updateBezierControlPoints:function(){e.each(this.getDataset().metaData,function(t,i){var s=e.splineCurve(e.previousItem(this.getDataset().metaData,i)._model,t._model,e.nextItem(this.getDataset().metaData,i)._model,t._model.tension);t._model.controlPointPreviousX=Math.max(Math.min(s.previous.x,this.chart.chartArea.right),this.chart.chartArea.left),t._model.controlPointPreviousY=Math.max(Math.min(s.previous.y,this.chart.chartArea.bottom),this.chart.chartArea.top),t._model.controlPointNextX=Math.max(Math.min(s.next.x,this.chart.chartArea.right),this.chart.chartArea.left),t._model.controlPointNextY=Math.max(Math.min(s.next.y,this.chart.chartArea.bottom),this.chart.chartArea.top),t.pivot()},this)},draw:function(t){var i=t||1;e.each(this.getDataset().metaData,function(t){t.transition(i)}),this.chart.options.showLines&&this.getDataset().metaDataset.transition(i).draw(),e.each(this.getDataset().metaData,function(t){t.draw()})},setHoverStyle:function(t){var i=this.chart.data.datasets[t._datasetIndex],s=t._index;t._model.radius=t.custom&&t.custom.hoverRadius?t.custom.hoverRadius:e.getValueAtIndexOrDefault(i.pointHoverRadius,s,this.chart.options.elements.point.hoverRadius),t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:e.getValueAtIndexOrDefault(i.pointHoverBackgroundColor,s,e.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:e.getValueAtIndexOrDefault(i.pointHoverBorderColor,s,e.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:e.getValueAtIndexOrDefault(i.pointHoverBorderWidth,s,t._model.borderWidth)},removeHoverStyle:function(t){var i=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.radius=t.custom&&t.custom.radius?t.custom.radius:e.getValueAtIndexOrDefault(this.getDataset().radius,i,this.chart.options.elements.point.radius),t._model.backgroundColor=this.getPointBackgroundColor(t,i),t._model.borderColor=this.getPointBorderColor(t,i),t._model.borderWidth=this.getPointBorderWidth(t,i)}})}},{}],19:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.polarArea={scale:{type:"radialLinear",lineArc:!0},animateRotate:!0,animateScale:!0,aspectRatio:1,legendCallback:function(t){var e=[];if(e.push('
    '),t.data.datasets.length)for(var i=0;i'),t.data.labels[i]&&e.push(t.data.labels[i]),e.push("");return e.push("
"),e.join("")},legend:{labels:{generateLabels:function(t){return t.labels.length&&t.datasets.length?t.labels.map(function(e,i){return{text:e,fillStyle:t.datasets[0].backgroundColor[i],hidden:isNaN(t.datasets[0].data[i]),index:i}}):[]}},onClick:function(t,i){e.each(this.chart.data.datasets,function(t){t.metaHiddenData=t.metaHiddenData||[];var e=i.index;isNaN(t.data[e])?isNaN(t.metaHiddenData[e])||(t.data[e]=t.metaHiddenData[e]):(t.metaHiddenData[e]=t.data[e],t.data[e]=NaN)}),this.chart.update()}},tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}},t.controllers.polarArea=t.DatasetController.extend({linkScales:function(){},addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],e.each(this.getDataset().data,function(e,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new t.elements.Arc({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(e){this.getDataset().metaData=this.getDataset().metaData||[];var i=new t.elements.Arc({_chart:this.chart.chart,_datasetIndex:this.index,_index:e});this.updateElement(i,e,!0),this.getDataset().metaData.splice(e,0,i)},getVisibleDatasetCount:function(){return e.where(this.chart.data.datasets,function(t){return e.isDatasetVisible(t)}).length},update:function(t){var i=Math.min(this.chart.chartArea.right-this.chart.chartArea.left,this.chart.chartArea.bottom-this.chart.chartArea.top);this.chart.outerRadius=Math.max((i-this.chart.options.elements.arc.borderWidth/2)/2,0),this.chart.innerRadius=Math.max(this.chart.options.cutoutPercentage?this.chart.outerRadius/100*this.chart.options.cutoutPercentage:1,0),this.chart.radiusLength=(this.chart.outerRadius-this.chart.innerRadius)/this.getVisibleDatasetCount(),this.getDataset().total=0,e.each(this.getDataset().data,function(t){this.getDataset().total+=Math.abs(t)},this),this.outerRadius=this.chart.outerRadius-this.chart.radiusLength*this.index,this.innerRadius=this.outerRadius-this.chart.radiusLength,e.each(this.getDataset().metaData,function(e,i){this.updateElement(e,i,t)},this)},updateElement:function(t,i,s){for(var a=this.calculateCircumference(this.getDataset().data[i]),o=(this.chart.chartArea.left+this.chart.chartArea.right)/2,n=(this.chart.chartArea.top+this.chart.chartArea.bottom)/2,r=0,l=0;i>l;++l)isNaN(this.getDataset().data[l])||++r;var h=-.5*Math.PI+a*r,c=h+a,d={x:o,y:n,innerRadius:0,outerRadius:this.chart.options.animateScale?0:this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[i]),startAngle:this.chart.options.animateRotate?Math.PI*-.5:h,endAngle:this.chart.options.animateRotate?Math.PI*-.5:c,backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().backgroundColor,i,this.chart.options.elements.arc.backgroundColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().borderWidth,i,this.chart.options.elements.arc.borderWidth),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().borderColor,i,this.chart.options.elements.arc.borderColor),label:e.getValueAtIndexOrDefault(this.chart.data.labels,i,this.chart.data.labels[i])};e.extend(t,{_chart:this.chart.chart,_datasetIndex:this.index,_index:i,_scale:this.chart.scale,_model:s?d:{x:o,y:n,innerRadius:0, +outerRadius:this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[i]),startAngle:h,endAngle:c,backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().backgroundColor,i,this.chart.options.elements.arc.backgroundColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().borderWidth,i,this.chart.options.elements.arc.borderWidth),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().borderColor,i,this.chart.options.elements.arc.borderColor),label:e.getValueAtIndexOrDefault(this.chart.data.labels,i,this.chart.data.labels[i])}}),t.pivot()},draw:function(t){var i=t||1;e.each(this.getDataset().metaData,function(t,e){t.transition(i).draw()})},setHoverStyle:function(t){var i=this.chart.data.datasets[t._datasetIndex],s=t._index;t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:e.getValueAtIndexOrDefault(i.hoverBackgroundColor,s,e.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:e.getValueAtIndexOrDefault(i.hoverBorderColor,s,e.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:e.getValueAtIndexOrDefault(i.hoverBorderWidth,s,t._model.borderWidth)},removeHoverStyle:function(t){var i=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.backgroundColor=t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().backgroundColor,i,this.chart.options.elements.arc.backgroundColor),t._model.borderColor=t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().borderColor,i,this.chart.options.elements.arc.borderColor),t._model.borderWidth=t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().borderWidth,i,this.chart.options.elements.arc.borderWidth)},calculateCircumference:function(t){if(isNaN(t))return 0;var i=e.where(this.getDataset().data,function(t){return isNaN(t)}).length;return 2*Math.PI/(this.getDataset().data.length-i)}})}},{}],20:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.radar={scale:{type:"radialLinear"},elements:{line:{tension:0}}},t.controllers.radar=t.DatasetController.extend({linkScales:function(){},addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],this.getDataset().metaDataset=this.getDataset().metaDataset||new t.elements.Line({_chart:this.chart.chart,_datasetIndex:this.index,_points:this.getDataset().metaData,_loop:!0}),e.each(this.getDataset().data,function(e,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new t.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:i,_model:{x:0,y:0}})},this)},addElementAndReset:function(e){this.getDataset().metaData=this.getDataset().metaData||[];var i=new t.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:e});this.updateElement(i,e,!0),this.getDataset().metaData.splice(e,0,i),this.updateBezierControlPoints()},update:function(t){var i,s=this.getDataset().metaDataset,a=this.getDataset().metaData,o=this.chart.scale;i=o.min<0&&o.max<0?o.getPointPositionForValue(0,o.max):o.min>0&&o.max>0?o.getPointPositionForValue(0,o.min):o.getPointPositionForValue(0,0),e.extend(this.getDataset().metaDataset,{_datasetIndex:this.index,_children:this.getDataset().metaData,_model:{tension:s.custom&&s.custom.tension?s.custom.tension:e.getValueOrDefault(this.getDataset().tension,this.chart.options.elements.line.tension),backgroundColor:s.custom&&s.custom.backgroundColor?s.custom.backgroundColor:this.getDataset().backgroundColor||this.chart.options.elements.line.backgroundColor,borderWidth:s.custom&&s.custom.borderWidth?s.custom.borderWidth:this.getDataset().borderWidth||this.chart.options.elements.line.borderWidth,borderColor:s.custom&&s.custom.borderColor?s.custom.borderColor:this.getDataset().borderColor||this.chart.options.elements.line.borderColor,fill:s.custom&&s.custom.fill?s.custom.fill:void 0!==this.getDataset().fill?this.getDataset().fill:this.chart.options.elements.line.fill,borderCapStyle:s.custom&&s.custom.borderCapStyle?s.custom.borderCapStyle:this.getDataset().borderCapStyle||this.chart.options.elements.line.borderCapStyle,borderDash:s.custom&&s.custom.borderDash?s.custom.borderDash:this.getDataset().borderDash||this.chart.options.elements.line.borderDash,borderDashOffset:s.custom&&s.custom.borderDashOffset?s.custom.borderDashOffset:this.getDataset().borderDashOffset||this.chart.options.elements.line.borderDashOffset,borderJoinStyle:s.custom&&s.custom.borderJoinStyle?s.custom.borderJoinStyle:this.getDataset().borderJoinStyle||this.chart.options.elements.line.borderJoinStyle,scaleTop:o.top,scaleBottom:o.bottom,scaleZero:i}}),this.getDataset().metaDataset.pivot(),e.each(a,function(e,i){this.updateElement(e,i,t)},this),this.updateBezierControlPoints()},updateElement:function(t,i,s){var a=this.chart.scale.getPointPositionForValue(i,this.getDataset().data[i]);e.extend(t,{_datasetIndex:this.index,_index:i,_scale:this.chart.scale,_model:{x:s?this.chart.scale.xCenter:a.x,y:s?this.chart.scale.yCenter:a.y,tension:t.custom&&t.custom.tension?t.custom.tension:e.getValueOrDefault(this.getDataset().tension,this.chart.options.elements.line.tension),radius:t.custom&&t.custom.radius?t.custom.radius:e.getValueAtIndexOrDefault(this.getDataset().pointRadius,i,this.chart.options.elements.point.radius),backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor,i,this.chart.options.elements.point.backgroundColor),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().pointBorderColor,i,this.chart.options.elements.point.borderColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth,i,this.chart.options.elements.point.borderWidth),pointStyle:t.custom&&t.custom.pointStyle?t.custom.pointStyle:e.getValueAtIndexOrDefault(this.getDataset().pointStyle,i,this.chart.options.elements.point.pointStyle),hitRadius:t.custom&&t.custom.hitRadius?t.custom.hitRadius:e.getValueAtIndexOrDefault(this.getDataset().hitRadius,i,this.chart.options.elements.point.hitRadius)}}),t._model.skip=t.custom&&t.custom.skip?t.custom.skip:isNaN(t._model.x)||isNaN(t._model.y)},updateBezierControlPoints:function(){e.each(this.getDataset().metaData,function(t,i){var s=e.splineCurve(e.previousItem(this.getDataset().metaData,i,!0)._model,t._model,e.nextItem(this.getDataset().metaData,i,!0)._model,t._model.tension);t._model.controlPointPreviousX=Math.max(Math.min(s.previous.x,this.chart.chartArea.right),this.chart.chartArea.left),t._model.controlPointPreviousY=Math.max(Math.min(s.previous.y,this.chart.chartArea.bottom),this.chart.chartArea.top),t._model.controlPointNextX=Math.max(Math.min(s.next.x,this.chart.chartArea.right),this.chart.chartArea.left),t._model.controlPointNextY=Math.max(Math.min(s.next.y,this.chart.chartArea.bottom),this.chart.chartArea.top),t.pivot()},this)},draw:function(t){var i=t||1;e.each(this.getDataset().metaData,function(t,e){t.transition(i)}),this.getDataset().metaDataset.transition(i).draw(),e.each(this.getDataset().metaData,function(t){t.draw()})},setHoverStyle:function(t){var i=this.chart.data.datasets[t._datasetIndex],s=t._index;t._model.radius=t.custom&&t.custom.hoverRadius?t.custom.hoverRadius:e.getValueAtIndexOrDefault(i.pointHoverRadius,s,this.chart.options.elements.point.hoverRadius),t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:e.getValueAtIndexOrDefault(i.pointHoverBackgroundColor,s,e.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:e.getValueAtIndexOrDefault(i.pointHoverBorderColor,s,e.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:e.getValueAtIndexOrDefault(i.pointHoverBorderWidth,s,t._model.borderWidth)},removeHoverStyle:function(t){var i=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.radius=t.custom&&t.custom.radius?t.custom.radius:e.getValueAtIndexOrDefault(this.getDataset().radius,i,this.chart.options.elements.point.radius),t._model.backgroundColor=t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:e.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor,i,this.chart.options.elements.point.backgroundColor),t._model.borderColor=t.custom&&t.custom.borderColor?t.custom.borderColor:e.getValueAtIndexOrDefault(this.getDataset().pointBorderColor,i,this.chart.options.elements.point.borderColor),t._model.borderWidth=t.custom&&t.custom.borderWidth?t.custom.borderWidth:e.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth,i,this.chart.options.elements.point.borderWidth)}})}},{}],21:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.animation={duration:1e3,easing:"easeOutQuart",onProgress:e.noop,onComplete:e.noop},t.Animation=t.Element.extend({currentStep:null,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),t.animationService={frameDuration:17,animations:[],dropFrames:0,addAnimation:function(t,i,s,a){a||(t.animating=!0);for(var o=0;o1&&(i=Math.floor(this.dropFrames),this.dropFrames=this.dropFrames%1);for(var s=0;sthis.animations[s].animationObject.numSteps&&(this.animations[s].animationObject.currentStep=this.animations[s].animationObject.numSteps),this.animations[s].animationObject.render(this.animations[s].chartInstance,this.animations[s].animationObject),this.animations[s].animationObject.onAnimationProgress&&this.animations[s].animationObject.onAnimationProgress.call&&this.animations[s].animationObject.onAnimationProgress.call(this.animations[s].chartInstance,this.animations[s]),this.animations[s].animationObject.currentStep===this.animations[s].animationObject.numSteps?(this.animations[s].animationObject.onAnimationComplete&&this.animations[s].animationObject.onAnimationComplete.call&&this.animations[s].animationObject.onAnimationComplete.call(this.animations[s].chartInstance,this.animations[s]),this.animations[s].chartInstance.animating=!1,this.animations.splice(s,1)):++s;var a=Date.now(),o=(a-t)/this.frameDuration;this.dropFrames+=o,this.animations.length>0&&e.requestAnimFrame.call(window,this.digestWrapper)}}}},{}],22:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.types={},t.instances={},t.controllers={},t.Controller=function(i){return this.chart=i,this.config=i.config,this.options=this.config.options=e.configMerge(t.defaults.global,t.defaults[this.config.type],this.config.options||{}),this.id=e.uid(),Object.defineProperty(this,"data",{get:function(){return this.config.data}}),t.instances[this.id]=this,this.options.responsive&&this.resize(!0),this.initialize(),this},e.extend(t.Controller.prototype,{initialize:function(){return this.bindEvents(),this.ensureScalesHaveIDs(),this.buildOrUpdateControllers(),this.buildScales(),this.buildSurroundingItems(),this.updateLayout(),this.resetElements(),this.initToolTip(),this.update(),this},clear:function(){return e.clear(this.chart),this},stop:function(){return t.animationService.cancelAnimation(this),this},resize:function(t){var i=this.chart.canvas,s=e.getMaximumWidth(this.chart.canvas),a=this.options.maintainAspectRatio&&isNaN(this.chart.aspectRatio)===!1&&isFinite(this.chart.aspectRatio)&&0!==this.chart.aspectRatio?s/this.chart.aspectRatio:e.getMaximumHeight(this.chart.canvas),o=this.chart.width!==s||this.chart.height!==a;return o?(i.width=this.chart.width=s,i.height=this.chart.height=a,e.retinaScale(this.chart),t||(this.stop(),this.update(this.options.responsiveAnimationDuration)),this):this},ensureScalesHaveIDs:function(){var t="x-axis-",i="y-axis-";this.options.scales&&(this.options.scales.xAxes&&this.options.scales.xAxes.length&&e.each(this.options.scales.xAxes,function(e,i){e.id=e.id||t+i}),this.options.scales.yAxes&&this.options.scales.yAxes.length&&e.each(this.options.scales.yAxes,function(t,e){t.id=t.id||i+e}))},buildScales:function(){if(this.scales={},this.options.scales&&(this.options.scales.xAxes&&this.options.scales.xAxes.length&&e.each(this.options.scales.xAxes,function(i,s){var a=e.getValueOrDefault(i.type,"category"),o=t.scaleService.getScaleConstructor(a);if(o){var n=new o({ctx:this.chart.ctx,options:i,chart:this,id:i.id});this.scales[n.id]=n}},this),this.options.scales.yAxes&&this.options.scales.yAxes.length&&e.each(this.options.scales.yAxes,function(i,s){var a=e.getValueOrDefault(i.type,"linear"),o=t.scaleService.getScaleConstructor(a);if(o){var n=new o({ctx:this.chart.ctx,options:i,chart:this,id:i.id});this.scales[n.id]=n}},this)),this.options.scale){var i=t.scaleService.getScaleConstructor(this.options.scale.type);if(i){var s=new i({ctx:this.chart.ctx,options:this.options.scale,chart:this});this.scale=s,this.scales.radialScale=s}}t.scaleService.addScalesToLayout(this)},buildSurroundingItems:function(){this.options.title&&(this.titleBlock=new t.Title({ctx:this.chart.ctx,options:this.options.title,chart:this}),t.layoutService.addBox(this,this.titleBlock)),this.options.legend&&(this.legend=new t.Legend({ctx:this.chart.ctx,options:this.options.legend,chart:this}),t.layoutService.addBox(this,this.legend))},updateLayout:function(){t.layoutService.update(this,this.chart.width,this.chart.height)},buildOrUpdateControllers:function(){var i=[],s=[];if(e.each(this.data.datasets,function(e,a){e.type||(e.type=this.config.type);var o=e.type;i.push(o),e.controller?e.controller.updateIndex(a):(e.controller=new t.controllers[o](this,a),s.push(e.controller))},this),i.length>1)for(var a=1;a0&&(e=this.data.datasets[e[0]._datasetIndex].metaData),e},generateLegend:function(){return this.options.legendCallback(this)},destroy:function(){this.clear(),e.unbindEvents(this,this.events),e.removeResizeListener(this.chart.canvas.parentNode);var i=this.chart.canvas;i.width=this.chart.width,i.height=this.chart.height,void 0!==this.chart.originalDevicePixelRatio&&this.chart.ctx.scale(1/this.chart.originalDevicePixelRatio,1/this.chart.originalDevicePixelRatio),i.style.width=this.chart.originalCanvasStyleWidth,i.style.height=this.chart.originalCanvasStyleHeight,delete t.instances[this.id]},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)},initToolTip:function(){this.tooltip=new t.Tooltip({_chart:this.chart,_chartInstance:this,_data:this.data,_options:this.options},this)},bindEvents:function(){e.bindEvents(this,this.options.events,function(t){this.eventHandler(t)})},eventHandler:function(t){if(this.lastActive=this.lastActive||[],this.lastTooltipActive=this.lastTooltipActive||[],"mouseout"===t.type)this.active=[],this.tooltipActive=[];else{var i=this,s=function(e){switch(e){case"single":return i.getElementAtEvent(t);case"label":return i.getElementsAtEvent(t);case"dataset":return i.getDatasetAtEvent(t);default:return t}};this.active=s(this.options.hover.mode),this.tooltipActive=s(this.options.tooltips.mode)}this.options.hover.onHover&&this.options.hover.onHover.call(this,this.active),"mouseup"!==t.type&&"click"!==t.type||(this.options.onClick&&this.options.onClick.call(this,t,this.active),this.legend&&this.legend.handleEvent&&this.legend.handleEvent(t));if(this.lastActive.length)switch(this.options.hover.mode){case"single":this.data.datasets[this.lastActive[0]._datasetIndex].controller.removeHoverStyle(this.lastActive[0],this.lastActive[0]._datasetIndex,this.lastActive[0]._index);break;case"label":case"dataset":for(var a=0;at)this.getDataset().metaData.splice(t,e-t);else if(t>e)for(var i=e;t>i;++i)this.addElementAndReset(i)},addElements:e.noop,addElementAndReset:e.noop,draw:e.noop,removeHoverStyle:e.noop,setHoverStyle:e.noop,update:e.noop}),t.DatasetController.extend=e.inherits}},{}],24:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.elements={},t.Element=function(t){e.extend(this,t),this.initialize.apply(this,arguments)},e.extend(t.Element.prototype,{initialize:function(){},pivot:function(){return this._view||(this._view=e.clone(this._model)),this._start=e.clone(this._view),this},transition:function(t){return this._view||(this._view=e.clone(this._model)),1===t?(this._view=this._model,this._start=null,this):(this._start||this.pivot(),e.each(this._model,function(i,s){if("_"!==s[0]&&this._model.hasOwnProperty(s))if(this._view.hasOwnProperty(s))if(i===this._view[s]);else if("string"==typeof i)try{var a=e.color(this._start[s]).mix(e.color(this._model[s]),t);this._view[s]=a.rgbString()}catch(o){this._view[s]=i}else if("number"==typeof i){var n=void 0!==this._start[s]&&isNaN(this._start[s])===!1?this._start[s]:0;this._view[s]=(this._model[s]-n)*t+n}else this._view[s]=i;else"number"!=typeof i||isNaN(this._view[s])?this._view[s]=i:this._view[s]=i*t;else;},this),this)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return e.isNumber(this._model.x)&&e.isNumber(this._model.y)}}),t.Element.extend=e.inherits}},{}],25:[function(t,e,i){"use strict";var s=t("chartjs-color");e.exports=function(t){function e(t,e,i){var s;return"string"==typeof t?(s=parseInt(t,10),-1!=t.indexOf("%")&&(s=s/100*e.parentNode[i])):s=t,s}function i(t,i,s){var a,o=document.defaultView.getComputedStyle(t)[i],n=document.defaultView.getComputedStyle(t.parentNode)[i],r=null!==o&&"none"!==o,l=null!==n&&"none"!==n;return(r||l)&&(a=Math.min(r?e(o,t,s):Number.POSITIVE_INFINITY,l?e(n,t.parentNode,s):Number.POSITIVE_INFINITY)),a}var a=t.helpers={};a.each=function(t,e,i,s){var o,n;if(a.isArray(t))if(n=t.length,s)for(o=n-1;o>=0;o--)e.call(i,t[o],o);else for(o=0;n>o;o++)e.call(i,t[o],o);else if("object"==typeof t){var r=Object.keys(t);for(n=r.length,o=0;n>o;o++)e.call(i,t[r[o]],r[o])}},a.clone=function(t){var e={};return a.each(t,function(i,s){t.hasOwnProperty(s)&&(a.isArray(i)?e[s]=i.slice(0):"object"==typeof i&&null!==i?e[s]=a.clone(i):e[s]=i)}),e},a.extend=function(t){for(var e=arguments.length,i=[],s=1;e>s;s++)i.push(arguments[s]);return a.each(i,function(e){a.each(e,function(i,s){e.hasOwnProperty(s)&&(t[s]=i)})}),t},a.configMerge=function(e){var i=a.clone(e);return a.each(Array.prototype.slice.call(arguments,1),function(e){a.each(e,function(s,o){if(e.hasOwnProperty(o))if("scales"===o)i[o]=a.scaleMerge(i.hasOwnProperty(o)?i[o]:{},s);else if("scale"===o)i[o]=a.configMerge(i.hasOwnProperty(o)?i[o]:{},t.scaleService.getScaleDefaults(s.type),s);else if(i.hasOwnProperty(o)&&a.isArray(i[o])&&a.isArray(s)){var n=i[o];a.each(s,function(t,e){e=s[o].length||!s[o][i].type?s[o].push(a.configMerge(r,e)):e.type&&e.type!==s[o][i].type?s[o][i]=a.configMerge(s[o][i],r,e):s[o][i]=a.configMerge(s[o][i],e)}):(s[o]=[],a.each(e,function(e){var i=a.getValueOrDefault(e.type,"xAxes"===o?"category":"linear");s[o].push(a.configMerge(t.scaleService.getScaleDefaults(i),e))})):s.hasOwnProperty(o)&&"object"==typeof s[o]&&null!==s[o]&&"object"==typeof e?s[o]=a.configMerge(s[o],e):s[o]=e)}),s},a.getValueAtIndexOrDefault=function(t,e,i){return void 0===t||null===t?i:a.isArray(t)?e=0;s--){var a=t[s];if(e(a))return a}},a.inherits=function(t){var e=this,i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},s=function(){this.constructor=i};return s.prototype=e.prototype,i.prototype=new s,i.extend=a.inherits,t&&a.extend(i.prototype,t),i.__super__=e.prototype,i},a.noop=function(){},a.uid=function(){var t=0;return function(){return"chart-"+t++}}(),a.warn=function(t){console&&"function"==typeof console.warn&&console.warn(t)},a.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},a.almostEquals=function(t,e,i){return Math.abs(t-e)0?1:-1)},a.log10=function(t){return Math.log10?Math.log10(t):Math.log(t)/Math.LN10},a.toRadians=function(t){return t*(Math.PI/180)},a.toDegrees=function(t){return t*(180/Math.PI)},a.getAngleFromPoint=function(t,e){var i=e.x-t.x,s=e.y-t.y,a=Math.sqrt(i*i+s*s),o=Math.atan2(s,i);return o<-.5*Math.PI&&(o+=2*Math.PI),{angle:o,distance:a}},a.aliasPixel=function(t){return t%2===0?0:.5},a.splineCurve=function(t,e,i,s){var a=t.skip?e:t,o=e,n=i.skip?e:i,r=Math.sqrt(Math.pow(o.x-a.x,2)+Math.pow(o.y-a.y,2)),l=Math.sqrt(Math.pow(n.x-o.x,2)+Math.pow(n.y-o.y,2)),h=r/(r+l),c=l/(r+l);h=isNaN(h)?0:h,c=isNaN(c)?0:c;var d=s*h,u=s*c;return{previous:{x:o.x-d*(n.x-a.x),y:o.y-d*(n.y-a.y)},next:{x:o.x+u*(n.x-a.x),y:o.y+u*(n.y-a.y)}}},a.nextItem=function(t,e,i){return i?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},a.previousItem=function(t,e,i){return i?0>=e?t[t.length-1]:t[e-1]:0>=e?t[0]:t[e-1]},a.niceNum=function(t,e){var i,s=Math.floor(a.log10(t)),o=t/Math.pow(10,s);return i=e?1.5>o?1:3>o?2:7>o?5:10:1>=o?1:2>=o?2:5>=o?5:10,i*Math.pow(10,s)};var o=a.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,i=0,s=1;return 0===t?0:1===(t/=1)?1:(i||(i=.3),st?-.5*(s*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/i)):s*Math.pow(2,-10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/i)*.5+1)},easeInBack:function(t){var e=1.70158;return 1*(t/=1)*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return 1*((t=t/1-1)*t*((e+1)*t+e)+1)},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?.5*(t*t*(((e*=1.525)+1)*t-e)):.5*((t-=2)*t*(((e*=1.525)+1)*t+e)+2)},easeInBounce:function(t){return 1-o.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?1*(7.5625*t*t):2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*o.easeInBounce(2*t):.5*o.easeOutBounce(2*t-1)+.5}};a.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),a.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),a.getRelativePosition=function(t,e){var i,s,o=t.originalEvent||t,n=t.currentTarget||t.srcElement,r=n.getBoundingClientRect();o.touches&&o.touches.length>0?(i=o.touches[0].clientX,s=o.touches[0].clientY):(i=o.clientX,s=o.clientY);var l=parseFloat(a.getStyle(n,"padding-left")),h=parseFloat(a.getStyle(n,"padding-top")),c=parseFloat(a.getStyle(n,"padding-right")),d=parseFloat(a.getStyle(n,"padding-bottom")),u=r.right-r.left-l-c,f=r.bottom-r.top-h-d;return i=Math.round((i-r.left-l)/u*n.width/e.currentDevicePixelRatio),s=Math.round((s-r.top-h)/f*n.height/e.currentDevicePixelRatio),{x:i,y:s}},a.addEvent=function(t,e,i){t.addEventListener?t.addEventListener(e,i):t.attachEvent?t.attachEvent("on"+e,i):t["on"+e]=i; +},a.removeEvent=function(t,e,i){t.removeEventListener?t.removeEventListener(e,i,!1):t.detachEvent?t.detachEvent("on"+e,i):t["on"+e]=a.noop},a.bindEvents=function(t,e,i){t.events||(t.events={}),a.each(e,function(e){t.events[e]=function(){i.apply(t,arguments)},a.addEvent(t.chart.canvas,e,t.events[e])})},a.unbindEvents=function(t,e){a.each(e,function(e,i){a.removeEvent(t.chart.canvas,i,e)})},a.getConstraintWidth=function(t){return i(t,"max-width","clientWidth")},a.getConstraintHeight=function(t){return i(t,"max-height","clientHeight")},a.getMaximumWidth=function(t){var e=t.parentNode,i=parseInt(a.getStyle(e,"padding-left"))+parseInt(a.getStyle(e,"padding-right")),s=e.clientWidth-i,o=a.getConstraintWidth(t);return void 0!==o&&(s=Math.min(s,o)),s},a.getMaximumHeight=function(t){var e=t.parentNode,i=parseInt(a.getStyle(e,"padding-top"))+parseInt(a.getStyle(e,"padding-bottom")),s=e.clientHeight-i,o=a.getConstraintHeight(t);return void 0!==o&&(s=Math.min(s,o)),s},a.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},a.retinaScale=function(t){var e=t.ctx,i=t.canvas.width,s=t.canvas.height,a=t.currentDevicePixelRatio=window.devicePixelRatio||1;1!==a&&(e.canvas.height=s*a,e.canvas.width=i*a,e.scale(a,a),t.originalDevicePixelRatio=t.originalDevicePixelRatio||a),e.canvas.style.width=i+"px",e.canvas.style.height=s+"px"},a.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},a.fontString=function(t,e,i){return e+" "+t+"px "+i},a.longestText=function(t,e,i,s){s=s||{},s.data=s.data||{},s.garbageCollect=s.garbageCollect||[],s.font!==e&&(s.data={},s.garbageCollect=[],s.font=e),t.font=e;var o=0;a.each(i,function(e){var i=s.data[e];i||(i=s.data[e]=t.measureText(e).width,s.garbageCollect.push(e)),i>o&&(o=i)});var n=s.garbageCollect.length/2;if(n>i.length){for(var r=0;n>r;r++)delete s.data[s.garbageCollect[r]];s.garbageCollect.splice(0,n)}return o},a.drawRoundedRectangle=function(t,e,i,s,a,o){t.beginPath(),t.moveTo(e+o,i),t.lineTo(e+s-o,i),t.quadraticCurveTo(e+s,i,e+s,i+o),t.lineTo(e+s,i+a-o),t.quadraticCurveTo(e+s,i+a,e+s-o,i+a),t.lineTo(e+o,i+a),t.quadraticCurveTo(e,i+a,e,i+a-o),t.lineTo(e,i+o),t.quadraticCurveTo(e,i,e+o,i),t.closePath()},a.color=function(t){return s?s(t):(console.log("Color.js not found!"),t)},a.addResizeListener=function(t,e){var i=document.createElement("iframe"),s="chartjs-hidden-iframe";i.classlist?i.classlist.add(s):i.setAttribute("class",s),i.style.width="100%",i.style.display="block",i.style.border=0,i.style.height=0,i.style.margin=0,i.style.position="absolute",i.style.left=0,i.style.right=0,i.style.top=0,i.style.bottom=0,t.insertBefore(i,t.firstChild),(i.contentWindow||i).onresize=function(){e&&e()}},a.removeResizeListener=function(t){var e=t.querySelector(".chartjs-hidden-iframe");e&&e.parentNode.removeChild(e)},a.isArray=function(t){return Array.isArray?Array.isArray(t):"[object Array]"===Object.prototype.toString.call(t)},a.pushAllIfDefined=function(t,e){"undefined"!=typeof t&&(a.isArray(t)?e.push.apply(e,t):e.push(t))},a.isDatasetVisible=function(t){return!t.hidden},a.callCallback=function(t,e,i){t&&"function"==typeof t.call&&t.apply(i,e)}}},{"chartjs-color":1}],26:[function(t,e,i){"use strict";e.exports=function(){var t=function(e,i){this.config=i,e.length&&e[0].getContext&&(e=e[0]),e.getContext&&(e=e.getContext("2d")),this.ctx=e,this.canvas=e.canvas,this.width=e.canvas.width||parseInt(t.helpers.getStyle(e.canvas,"width"))||t.helpers.getMaximumWidth(e.canvas),this.height=e.canvas.height||parseInt(t.helpers.getStyle(e.canvas,"height"))||t.helpers.getMaximumHeight(e.canvas),this.aspectRatio=this.width/this.height,(isNaN(this.aspectRatio)||isFinite(this.aspectRatio)===!1)&&(this.aspectRatio=void 0!==i.aspectRatio?i.aspectRatio:2),this.originalCanvasStyleWidth=e.canvas.style.width,this.originalCanvasStyleHeight=e.canvas.style.height,t.helpers.retinaScale(this),i&&(this.controller=new t.Controller(this));var s=this;return t.helpers.addResizeListener(e.canvas.parentNode,function(){s.controller&&s.controller.config.options.responsive&&s.controller.resize()}),this.controller?this.controller:this};return t.defaults={global:{responsive:!0,responsiveAnimationDuration:0,maintainAspectRatio:!0,events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"single",animationDuration:400},onClick:null,defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",showLines:!0,elements:{},legendCallback:function(t){var e=[];e.push('
    ');for(var i=0;i'),t.data.datasets[i].label&&e.push(t.data.datasets[i].label),e.push("");return e.push("
"),e.join("")}}},t}},{}],27:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.layoutService={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),t.boxes.push(e)},removeBox:function(t,e){t.boxes&&t.boxes.splice(t.boxes.indexOf(e),1)},update:function(t,i,s){function a(t){var e,i=t.isHorizontal();i?(e=t.update(t.options.fullWidth?g:_,y),k-=e.height):(e=t.update(x,v),_-=e.width),D.push({horizontal:i,minSize:e,box:t})}function o(t){var i=e.findNextWhere(D,function(e){return e.box===t});if(i)if(t.isHorizontal()){var s={left:S,right:w,top:0,bottom:0};t.update(t.options.fullWidth?g:_,p/2,s)}else t.update(i.minSize.width,k)}function n(t){var i=e.findNextWhere(D,function(e){return e.box===t}),s={left:0,right:0,top:C,bottom:M};i&&t.update(i.minSize.width,k,s)}function r(t){t.isHorizontal()?(t.left=t.options.fullWidth?l:S,t.right=t.options.fullWidth?i-l:S+_,t.top=F,t.bottom=F+t.height,F=t.bottom):(t.left=I,t.right=I+t.width,t.top=C,t.bottom=C+k,I=t.right)}if(t){var l=0,h=0,c=e.where(t.boxes,function(t){return"left"===t.options.position}),d=e.where(t.boxes,function(t){return"right"===t.options.position}),u=e.where(t.boxes,function(t){return"top"===t.options.position}),f=e.where(t.boxes,function(t){return"bottom"===t.options.position}),m=e.where(t.boxes,function(t){return"chartArea"===t.options.position});u.sort(function(t,e){return(e.options.fullWidth?1:0)-(t.options.fullWidth?1:0)}),f.sort(function(t,e){return(t.options.fullWidth?1:0)-(e.options.fullWidth?1:0)});var g=i-2*l,p=s-2*h,b=g/2,v=p/2,x=(i-b)/(c.length+d.length),y=(s-v)/(u.length+f.length),_=g,k=p,D=[];e.each(c.concat(d,u,f),a);var S=l,w=l,C=h,M=h;e.each(c.concat(d),o),e.each(c,function(t){S+=t.width}),e.each(d,function(t){w+=t.width}),e.each(u.concat(f),o),e.each(u,function(t){C+=t.height}),e.each(f,function(t){M+=t.height}),e.each(c.concat(d),n),S=l,w=l,C=h,M=h,e.each(c,function(t){S+=t.width}),e.each(d,function(t){w+=t.width}),e.each(u,function(t){C+=t.height}),e.each(f,function(t){M+=t.height});var A=s-C-M,T=i-S-w;T===_&&A===k||(e.each(c,function(t){t.height=A}),e.each(d,function(t){t.height=A}),e.each(u,function(t){t.width=T}),e.each(f,function(t){t.width=T}),k=A,_=T);var I=l,F=h;e.each(c.concat(u),r),I+=_,F+=k,e.each(d,r),e.each(f,r),t.chartArea={left:S,top:C,right:S+_,bottom:C+k},e.each(m,function(e){e.left=t.chartArea.left,e.top=t.chartArea.top,e.right=t.chartArea.right,e.bottom=t.chartArea.bottom,e.update(_,k)})}}}}},{}],28:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.legend={display:!0,position:"top",fullWidth:!0,reverse:!1,onClick:function(t,e){var i=this.chart.data.datasets[e.datasetIndex];i.hidden=!i.hidden,this.chart.update()},labels:{boxWidth:40,padding:10,generateLabels:function(t){return e.isArray(t.datasets)?t.datasets.map(function(t,e){return{text:t.label,fillStyle:t.backgroundColor,hidden:t.hidden,lineCap:t.borderCapStyle,lineDash:t.borderDash,lineDashOffset:t.borderDashOffset,lineJoin:t.borderJoinStyle,lineWidth:t.borderWidth,strokeStyle:t.borderColor,datasetIndex:e}},this):[]}}},t.Legend=t.Element.extend({initialize:function(t){e.extend(this,t),this.legendHitBoxes=[],this.doughnutMode=!1},beforeUpdate:e.noop,update:function(t,e,i){return this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this.margins=i,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this.beforeBuildLabels(),this.buildLabels(),this.afterBuildLabels(),this.beforeFit(),this.fit(),this.afterFit(),this.afterUpdate(),this.minSize},afterUpdate:e.noop,beforeSetDimensions:e.noop,setDimensions:function(){this.isHorizontal()?(this.width=this.maxWidth,this.left=0,this.right=this.width):(this.height=this.maxHeight,this.top=0,this.bottom=this.height),this.paddingLeft=0,this.paddingTop=0,this.paddingRight=0,this.paddingBottom=0,this.minSize={width:0,height:0}},afterSetDimensions:e.noop,beforeBuildLabels:e.noop,buildLabels:function(){this.legendItems=this.options.labels.generateLabels.call(this,this.chart.data),this.options.reverse&&this.legendItems.reverse()},afterBuildLabels:e.noop,beforeFit:e.noop,fit:function(){var i=this.ctx,s=e.getValueOrDefault(this.options.labels.fontSize,t.defaults.global.defaultFontSize),a=e.getValueOrDefault(this.options.labels.fontStyle,t.defaults.global.defaultFontStyle),o=e.getValueOrDefault(this.options.labels.fontFamily,t.defaults.global.defaultFontFamily),n=e.fontString(s,a,o);if(this.legendHitBoxes=[],this.isHorizontal()?this.minSize.width=this.maxWidth:this.minSize.width=this.options.display?10:0,this.isHorizontal()?this.minSize.height=this.options.display?10:0:this.minSize.height=this.maxHeight,this.options.display&&this.isHorizontal()){this.lineWidths=[0];var r=this.legendItems.length?s+this.options.labels.padding:0;i.textAlign="left",i.textBaseline="top",i.font=n,e.each(this.legendItems,function(t,e){var a=this.options.labels.boxWidth+s/2+i.measureText(t.text).width;this.lineWidths[this.lineWidths.length-1]+a+this.options.labels.padding>=this.width&&(r+=s+this.options.labels.padding,this.lineWidths[this.lineWidths.length]=this.left),this.legendHitBoxes[e]={left:0,top:0,width:a,height:s},this.lineWidths[this.lineWidths.length-1]+=a+this.options.labels.padding},this),this.minSize.height+=r}this.width=this.minSize.width,this.height=this.minSize.height},afterFit:e.noop,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){if(this.options.display){var i=this.ctx,s={x:this.left+(this.width-this.lineWidths[0])/2,y:this.top+this.options.labels.padding,line:0},a=e.getValueOrDefault(this.options.labels.fontColor,t.defaults.global.defaultFontColor),o=e.getValueOrDefault(this.options.labels.fontSize,t.defaults.global.defaultFontSize),n=e.getValueOrDefault(this.options.labels.fontStyle,t.defaults.global.defaultFontStyle),r=e.getValueOrDefault(this.options.labels.fontFamily,t.defaults.global.defaultFontFamily),l=e.fontString(o,n,r);this.isHorizontal()&&(i.textAlign="left",i.textBaseline="top",i.lineWidth=.5,i.strokeStyle=a,i.fillStyle=a,i.font=l,e.each(this.legendItems,function(e,a){var n=i.measureText(e.text).width,r=this.options.labels.boxWidth+o/2+n;s.x+r>=this.width&&(s.y+=o+this.options.labels.padding,s.line++,s.x=this.left+(this.width-this.lineWidths[s.line])/2),i.save();var l=function(t,e){return void 0!==t?t:e};i.fillStyle=l(e.fillStyle,t.defaults.global.defaultColor),i.lineCap=l(e.lineCap,t.defaults.global.elements.line.borderCapStyle),i.lineDashOffset=l(e.lineDashOffset,t.defaults.global.elements.line.borderDashOffset),i.lineJoin=l(e.lineJoin,t.defaults.global.elements.line.borderJoinStyle),i.lineWidth=l(e.lineWidth,t.defaults.global.elements.line.borderWidth),i.strokeStyle=l(e.strokeStyle,t.defaults.global.defaultColor),i.setLineDash&&i.setLineDash(l(e.lineDash,t.defaults.global.elements.line.borderDash)),i.strokeRect(s.x,s.y,this.options.labels.boxWidth,o),i.fillRect(s.x,s.y,this.options.labels.boxWidth,o),i.restore(),this.legendHitBoxes[a].left=s.x,this.legendHitBoxes[a].top=s.y,i.fillText(e.text,this.options.labels.boxWidth+o/2+s.x,s.y),e.hidden&&(i.beginPath(),i.lineWidth=2,i.moveTo(this.options.labels.boxWidth+o/2+s.x,s.y+o/2),i.lineTo(this.options.labels.boxWidth+o/2+s.x+n,s.y+o/2),i.stroke()),s.x+=r+this.options.labels.padding},this))}},handleEvent:function(t){var i=e.getRelativePosition(t,this.chart.chart);if(i.x>=this.left&&i.x<=this.right&&i.y>=this.top&&i.y<=this.bottom)for(var s=0;s=a.left&&i.x<=a.left+a.width&&i.y>=a.top&&i.y<=a.top+a.height){this.options.onClick&&this.options.onClick.call(this,t,this.legendItems[s]);break}}}})}},{}],29:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.scale={display:!0,gridLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,drawOnChartArea:!0,drawTicks:!0,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",offsetGridLines:!1},scaleLabel:{labelString:"",display:!1},ticks:{beginAtZero:!1,maxRotation:90,mirror:!1,padding:10,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:20,callback:function(t){return""+t}}},t.Scale=t.Element.extend({beforeUpdate:function(){e.callCallback(this.options.beforeUpdate,[this])},update:function(t,i,s){return this.beforeUpdate(),this.maxWidth=t,this.maxHeight=i,this.margins=e.extend({left:0,right:0,top:0,bottom:0},s),this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this.beforeBuildTicks(),this.buildTicks(),this.afterBuildTicks(),this.beforeTickToLabelConversion(),this.convertTicksToLabels(),this.afterTickToLabelConversion(),this.beforeCalculateTickRotation(),this.calculateTickRotation(),this.afterCalculateTickRotation(),this.beforeFit(),this.fit(),this.afterFit(),this.afterUpdate(),this.minSize},afterUpdate:function(){e.callCallback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){e.callCallback(this.options.beforeSetDimensions,[this])},setDimensions:function(){this.isHorizontal()?(this.width=this.maxWidth,this.left=0,this.right=this.width):(this.height=this.maxHeight,this.top=0,this.bottom=this.height),this.paddingLeft=0,this.paddingTop=0,this.paddingRight=0,this.paddingBottom=0},afterSetDimensions:function(){e.callCallback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){e.callCallback(this.options.beforeDataLimits,[this])},determineDataLimits:e.noop,afterDataLimits:function(){e.callCallback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){e.callCallback(this.options.beforeBuildTicks,[this])},buildTicks:e.noop,afterBuildTicks:function(){e.callCallback(this.options.afterBuildTicks,[this])},beforeTickToLabelConversion:function(){e.callCallback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){this.ticks=this.ticks.map(function(t,e,i){return this.options.ticks.userCallback?this.options.ticks.userCallback(t,e,i):this.options.ticks.callback(t,e,i)},this)},afterTickToLabelConversion:function(){e.callCallback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){e.callCallback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var i=e.getValueOrDefault(this.options.ticks.fontSize,t.defaults.global.defaultFontSize),s=e.getValueOrDefault(this.options.ticks.fontStyle,t.defaults.global.defaultFontStyle),a=e.getValueOrDefault(this.options.ticks.fontFamily,t.defaults.global.defaultFontFamily),o=e.fontString(i,s,a);this.ctx.font=o;var n,r=this.ctx.measureText(this.ticks[0]).width,l=this.ctx.measureText(this.ticks[this.ticks.length-1]).width;if(this.labelRotation=0,this.paddingRight=0,this.paddingLeft=0,this.options.display&&this.isHorizontal()){this.paddingRight=l/2+3,this.paddingLeft=r/2+3,this.longestTextCache||(this.longestTextCache={});for(var h,c,d=e.longestText(this.ctx,o,this.ticks,this.longestTextCache),u=d,f=this.getPixelForTick(1)-this.getPixelForTick(0)-6;u>f&&this.labelRotationthis.yLabelWidth&&(this.paddingLeft=n+i/2),this.paddingRight=i/2,c*d>this.maxHeight){this.labelRotation--;break}this.labelRotation++,u=h*d}}this.margins&&(this.paddingLeft=Math.max(this.paddingLeft-this.margins.left,0),this.paddingRight=Math.max(this.paddingRight-this.margins.right,0))},afterCalculateTickRotation:function(){e.callCallback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){e.callCallback(this.options.beforeFit,[this])},fit:function(){this.minSize={width:0,height:0};var i=e.getValueOrDefault(this.options.ticks.fontSize,t.defaults.global.defaultFontSize),s=e.getValueOrDefault(this.options.ticks.fontStyle,t.defaults.global.defaultFontStyle),a=e.getValueOrDefault(this.options.ticks.fontFamily,t.defaults.global.defaultFontFamily),o=e.fontString(i,s,a),n=e.getValueOrDefault(this.options.scaleLabel.fontSize,t.defaults.global.defaultFontSize),r=e.getValueOrDefault(this.options.scaleLabel.fontStyle,t.defaults.global.defaultFontStyle),l=e.getValueOrDefault(this.options.scaleLabel.fontFamily,t.defaults.global.defaultFontFamily);e.fontString(n,r,l);if(this.isHorizontal()?this.minSize.width=this.isFullWidth()?this.maxWidth-this.margins.left-this.margins.right:this.maxWidth:this.minSize.width=this.options.gridLines.display&&this.options.display?10:0,this.isHorizontal()?this.minSize.height=this.options.gridLines.display&&this.options.display?10:0:this.minSize.height=this.maxHeight,this.options.scaleLabel.display&&(this.isHorizontal()?this.minSize.height+=1.5*n:this.minSize.width+=1.5*n),this.options.ticks.display&&this.options.display){this.longestTextCache||(this.longestTextCache={});var h=e.longestText(this.ctx,o,this.ticks,this.longestTextCache);if(this.isHorizontal()){this.longestLabelWidth=h;var c=Math.sin(e.toRadians(this.labelRotation))*this.longestLabelWidth+1.5*i;this.minSize.height=Math.min(this.maxHeight,this.minSize.height+c),this.ctx.font=o;var d=this.ctx.measureText(this.ticks[0]).width,u=this.ctx.measureText(this.ticks[this.ticks.length-1]).width,f=Math.cos(e.toRadians(this.labelRotation)),m=Math.sin(e.toRadians(this.labelRotation));this.paddingLeft=0!==this.labelRotation?f*d+3:d/2+3,this.paddingRight=0!==this.labelRotation?m*(i/2)+3:u/2+3}else{var g=this.maxWidth-this.minSize.width;this.options.ticks.mirror||(h+=this.options.ticks.padding),g>h?this.minSize.width+=h:this.minSize.width=this.maxWidth,this.paddingTop=i/2,this.paddingBottom=i/2}}this.margins&&(this.paddingLeft=Math.max(this.paddingLeft-this.margins.left,0),this.paddingTop=Math.max(this.paddingTop-this.margins.top,0),this.paddingRight=Math.max(this.paddingRight-this.margins.right,0),this.paddingBottom=Math.max(this.paddingBottom-this.margins.bottom,0)),this.width=this.minSize.width,this.height=this.minSize.height},afterFit:function(){e.callCallback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function i(t){return null===t||"undefined"==typeof t?NaN:"number"==typeof t&&isNaN(t)?NaN:"object"==typeof t?t instanceof Date?t:i(this.isHorizontal()?t.x:t.y):t},getLabelForIndex:e.noop,getPixelForValue:e.noop,getPixelForTick:function(t,e){if(this.isHorizontal()){var i=this.width-(this.paddingLeft+this.paddingRight),s=i/Math.max(this.ticks.length-(this.options.gridLines.offsetGridLines?0:1),1),a=s*t+this.paddingLeft;e&&(a+=s/2);var o=this.left+Math.round(a);return o+=this.isFullWidth()?this.margins.left:0}var n=this.height-(this.paddingTop+this.paddingBottom);return this.top+t*(n/(this.ticks.length-1))},getPixelForDecimal:function(t){if(this.isHorizontal()){var e=this.width-(this.paddingLeft+this.paddingRight),i=e*t+this.paddingLeft,s=this.left+Math.round(i);return s+=this.isFullWidth()?this.margins.left:0}return this.top+t*this.height},draw:function(i){if(this.options.display){var s,a,o,n,r,l=0!==this.labelRotation,h=this.options.ticks.autoSkip;this.options.ticks.maxTicksLimit&&(r=this.options.ticks.maxTicksLimit);var c=e.getValueOrDefault(this.options.ticks.fontColor,t.defaults.global.defaultFontColor),d=e.getValueOrDefault(this.options.ticks.fontSize,t.defaults.global.defaultFontSize),u=e.getValueOrDefault(this.options.ticks.fontStyle,t.defaults.global.defaultFontStyle),f=e.getValueOrDefault(this.options.ticks.fontFamily,t.defaults.global.defaultFontFamily),m=e.fontString(d,u,f),g=e.getValueOrDefault(this.options.scaleLabel.fontColor,t.defaults.global.defaultFontColor),p=e.getValueOrDefault(this.options.scaleLabel.fontSize,t.defaults.global.defaultFontSize),b=e.getValueOrDefault(this.options.scaleLabel.fontStyle,t.defaults.global.defaultFontStyle),v=e.getValueOrDefault(this.options.scaleLabel.fontFamily,t.defaults.global.defaultFontFamily),x=e.fontString(p,b,v),y=Math.cos(e.toRadians(this.labelRotation)),_=(Math.sin(e.toRadians(this.labelRotation)),this.longestLabelWidth*y);if(this.ctx.fillStyle=c,this.isHorizontal()){s=!0;var k="bottom"===this.options.position?this.top:this.bottom-10,D="bottom"===this.options.position?this.top+10:this.bottom;if(a=!1,(_/2+this.options.ticks.autoSkipPadding)*this.ticks.length>this.width-(this.paddingLeft+this.paddingRight)&&(a=1+Math.floor((_/2+this.options.ticks.autoSkipPadding)*this.ticks.length/(this.width-(this.paddingLeft+this.paddingRight)))),r&&this.ticks.length>r)for(;!a||this.ticks.length/(a||1)>r;)a||(a=1),a+=1;h||(a=!1),e.each(this.ticks,function(t,o){var n=this.ticks.length===o+1,r=a>1&&o%a>0||o%a===0&&o+a>this.ticks.length;if((!r||n)&&void 0!==t&&null!==t){var h=this.getPixelForTick(o),c=this.getPixelForTick(o,this.options.gridLines.offsetGridLines);this.options.gridLines.display&&(o===("undefined"!=typeof this.zeroLineIndex?this.zeroLineIndex:0)?(this.ctx.lineWidth=this.options.gridLines.zeroLineWidth,this.ctx.strokeStyle=this.options.gridLines.zeroLineColor,s=!0):s&&(this.ctx.lineWidth=this.options.gridLines.lineWidth,this.ctx.strokeStyle=this.options.gridLines.color,s=!1),h+=e.aliasPixel(this.ctx.lineWidth),this.ctx.beginPath(),this.options.gridLines.drawTicks&&(this.ctx.moveTo(h,k),this.ctx.lineTo(h,D)),this.options.gridLines.drawOnChartArea&&(this.ctx.moveTo(h,i.top),this.ctx.lineTo(h,i.bottom)),this.ctx.stroke()),this.options.ticks.display&&(this.ctx.save(),this.ctx.translate(c,l?this.top+12:"top"===this.options.position?this.bottom-10:this.top+10),this.ctx.rotate(-1*e.toRadians(this.labelRotation)),this.ctx.font=m,this.ctx.textAlign=l?"right":"center",this.ctx.textBaseline=l?"middle":"top"===this.options.position?"bottom":"top",this.ctx.fillText(t,0,0),this.ctx.restore())}},this),this.options.scaleLabel.display&&(this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillStyle=g,this.ctx.font=x,o=this.left+(this.right-this.left)/2,n="bottom"===this.options.position?this.bottom-p/2:this.top+p/2,this.ctx.fillText(this.options.scaleLabel.labelString,o,n))}else{s=!0;var S="right"===this.options.position?this.left:this.right-5,w="right"===this.options.position?this.left+5:this.right;if(e.each(this.ticks,function(t,a){if(void 0!==t&&null!==t){var o=this.getPixelForTick(a);if(this.options.gridLines.display&&(a===("undefined"!=typeof this.zeroLineIndex?this.zeroLineIndex:0)?(this.ctx.lineWidth=this.options.gridLines.zeroLineWidth,this.ctx.strokeStyle=this.options.gridLines.zeroLineColor,s=!0):s&&(this.ctx.lineWidth=this.options.gridLines.lineWidth,this.ctx.strokeStyle=this.options.gridLines.color,s=!1),o+=e.aliasPixel(this.ctx.lineWidth),this.ctx.beginPath(),this.options.gridLines.drawTicks&&(this.ctx.moveTo(S,o),this.ctx.lineTo(w,o)),this.options.gridLines.drawOnChartArea&&(this.ctx.moveTo(i.left,o),this.ctx.lineTo(i.right,o)),this.ctx.stroke()),this.options.ticks.display){var n,r=this.getPixelForTick(a,this.options.gridLines.offsetGridLines);this.ctx.save(),"left"===this.options.position?this.options.ticks.mirror?(n=this.right+this.options.ticks.padding,this.ctx.textAlign="left"):(n=this.right-this.options.ticks.padding,this.ctx.textAlign="right"):this.options.ticks.mirror?(n=this.left-this.options.ticks.padding,this.ctx.textAlign="right"):(n=this.left+this.options.ticks.padding,this.ctx.textAlign="left"),this.ctx.translate(n,r),this.ctx.rotate(-1*e.toRadians(this.labelRotation)),this.ctx.font=m,this.ctx.textBaseline="middle",this.ctx.fillText(t,0,0),this.ctx.restore()}}},this),this.options.scaleLabel.display){o="left"===this.options.position?this.left+p/2:this.right-p/2,n=this.top+(this.bottom-this.top)/2;var C="left"===this.options.position?-.5*Math.PI:.5*Math.PI;this.ctx.save(),this.ctx.translate(o,n),this.ctx.rotate(C),this.ctx.textAlign="center",this.ctx.fillStyle=g,this.ctx.font=x,this.ctx.textBaseline="middle",this.ctx.fillText(this.options.scaleLabel.labelString,0,0),this.ctx.restore()}}this.ctx.lineWidth=this.options.gridLines.lineWidth,this.ctx.strokeStyle=this.options.gridLines.color;var M=this.left,A=this.right,T=this.top,I=this.bottom;this.isHorizontal()?(T=I="top"===this.options.position?this.bottom:this.top,T+=e.aliasPixel(this.ctx.lineWidth),I+=e.aliasPixel(this.ctx.lineWidth)):(M=A="left"===this.options.position?this.right:this.left,M+=e.aliasPixel(this.ctx.lineWidth),A+=e.aliasPixel(this.ctx.lineWidth)),this.ctx.beginPath(),this.ctx.moveTo(M,T),this.ctx.lineTo(A,I),this.ctx.stroke()}}})}},{}],30:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.scaleService={constructors:{},defaults:{},registerScaleType:function(t,i,s){this.constructors[t]=i,this.defaults[t]=e.clone(s)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(i){return this.defaults.hasOwnProperty(i)?e.scaleMerge(t.defaults.scale,this.defaults[i]):{}},addScalesToLayout:function(i){e.each(i.scales,function(e){t.layoutService.addBox(i,e)})}}}},{}],31:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.title={display:!1,position:"top",fullWidth:!0,fontStyle:"bold",padding:10,text:""},t.Title=t.Element.extend({initialize:function(i){e.extend(this,i),this.options=e.configMerge(t.defaults.global.title,i.options),this.legendHitBoxes=[]},beforeUpdate:e.noop,update:function(t,e,i){return this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this.margins=i,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this.beforeBuildLabels(),this.buildLabels(),this.afterBuildLabels(),this.beforeFit(),this.fit(),this.afterFit(),this.afterUpdate(),this.minSize},afterUpdate:e.noop,beforeSetDimensions:e.noop,setDimensions:function(){this.isHorizontal()?(this.width=this.maxWidth,this.left=0,this.right=this.width):(this.height=this.maxHeight,this.top=0,this.bottom=this.height),this.paddingLeft=0,this.paddingTop=0,this.paddingRight=0,this.paddingBottom=0,this.minSize={width:0,height:0}},afterSetDimensions:e.noop,beforeBuildLabels:e.noop,buildLabels:e.noop,afterBuildLabels:e.noop,beforeFit:e.noop,fit:function(){var i=(this.ctx,e.getValueOrDefault(this.options.fontSize,t.defaults.global.defaultFontSize)),s=e.getValueOrDefault(this.options.fontStyle,t.defaults.global.defaultFontStyle),a=e.getValueOrDefault(this.options.fontFamily,t.defaults.global.defaultFontFamily);e.fontString(i,s,a);this.isHorizontal()?this.minSize.width=this.maxWidth:this.minSize.width=0,this.isHorizontal()?this.minSize.height=0:this.minSize.height=this.maxHeight,this.isHorizontal()?this.options.display&&(this.minSize.height+=i+2*this.options.padding):this.options.display&&(this.minSize.width+=i+2*this.options.padding),this.width=this.minSize.width,this.height=this.minSize.height},afterFit:e.noop,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){if(this.options.display){var i,s,a=this.ctx,o=e.getValueOrDefault(this.options.fontColor,t.defaults.global.defaultFontColor),n=e.getValueOrDefault(this.options.fontSize,t.defaults.global.defaultFontSize),r=e.getValueOrDefault(this.options.fontStyle,t.defaults.global.defaultFontStyle),l=e.getValueOrDefault(this.options.fontFamily,t.defaults.global.defaultFontFamily),h=e.fontString(n,r,l);if(a.fillStyle=o,a.font=h,this.isHorizontal())a.textAlign="center",a.textBaseline="middle",i=this.left+(this.right-this.left)/2,s=this.top+(this.bottom-this.top)/2,a.fillText(this.options.text,i,s);else{i="left"===this.options.position?this.left+n/2:this.right-n/2,s=this.top+(this.bottom-this.top)/2;var c="left"===this.options.position?-.5*Math.PI:.5*Math.PI;a.save(),a.translate(i,s),a.rotate(c),a.textAlign="center",a.textBaseline="middle",a.fillText(this.options.text,0,0),a.restore()}}}})}},{}],32:[function(t,e,i){"use strict";e.exports=function(t){function e(t,e){return e&&(i.isArray(e)?t=t.concat(e):t.push(e)),t}var i=t.helpers;t.defaults.global.tooltips={enabled:!0,custom:null,mode:"single",backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleColor:"#fff",titleAlign:"left",bodySpacing:2,bodyColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,yAlign:"center",xAlign:"center",caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",callbacks:{beforeTitle:i.noop,title:function(t,e){var i="";return t.length>0&&(t[0].xLabel?i=t[0].xLabel:e.labels.length>0&&t[0].indexthis._chart.height-t.height&&(this._model.yAlign="bottom");var e,i,s,a,o,n=this,r=(this._chartInstance.chartArea.left+this._chartInstance.chartArea.right)/2,l=(this._chartInstance.chartArea.top+this._chartInstance.chartArea.bottom)/2;"center"===this._model.yAlign?(e=function(t){return r>=t},i=function(t){return t>r}):(e=function(e){return e<=t.width/2},i=function(e){return e>=n._chart.width-t.width/2}),s=function(e){return e+t.width>n._chart.width},a=function(e){return e-t.width<0},o=function(t){return l>=t?"top":"bottom"},e(this._model.x)?(this._model.xAlign="left",s(this._model.x)&&(this._model.xAlign="center",this._model.yAlign=o(this._model.y))):i(this._model.x)&&(this._model.xAlign="right",a(this._model.x)&&(this._model.xAlign="center",this._model.yAlign=o(this._model.y)))},getBackgroundPoint:function(t,e){var i={x:t.x,y:t.y};return"right"===t.xAlign?i.x-=e.width:"center"===t.xAlign&&(i.x-=e.width/2),"top"===t.yAlign?i.y+=t.caretPadding+t.caretSize:"bottom"===t.yAlign?i.y-=e.height+t.caretPadding+t.caretSize:i.y-=e.height/2,"center"===t.yAlign?"left"===t.xAlign?i.x+=t.caretPadding+t.caretSize:"right"===t.xAlign&&(i.x-=t.caretPadding+t.caretSize):"left"===t.xAlign?i.x-=t.cornerRadius+t.caretPadding:"right"===t.xAlign&&(i.x+=t.cornerRadius+t.caretPadding),i},drawCaret:function(t,e,s,a){var o,n,r,l,h,c,d=this._view,u=this._chart.ctx;"center"===d.yAlign?("left"===d.xAlign?(o=t.x,n=o-d.caretSize,r=o):(o=t.x+e.width,n=o+d.caretSize,r=o),h=t.y+e.height/2,l=h-d.caretSize,c=h+d.caretSize):("left"===d.xAlign?(o=t.x+d.cornerRadius,n=o+d.caretSize,r=n+d.caretSize):"right"===d.xAlign?(o=t.x+e.width-d.cornerRadius,n=o-d.caretSize,r=n-d.caretSize):(n=t.x+e.width/2,o=n-d.caretSize,r=n+d.caretSize),"top"===d.yAlign?(l=t.y,h=l-d.caretSize,c=l):(l=t.y+e.height,h=l+d.caretSize,c=l));var f=i.color(d.backgroundColor);u.fillStyle=f.alpha(s*f.alpha()).rgbString(),u.beginPath(),u.moveTo(o,l),u.lineTo(n,h),u.lineTo(r,c),u.closePath(),u.fill()},drawTitle:function(t,e,s,a){if(e.title.length){s.textAlign=e._titleAlign,s.textBaseline="top";var o=i.color(e.titleColor);s.fillStyle=o.alpha(a*o.alpha()).rgbString(),s.font=i.fontString(e.titleFontSize,e._titleFontStyle,e._titleFontFamily),i.each(e.title,function(i,a){s.fillText(i,t.x,t.y),t.y+=e.titleFontSize+e.titleSpacing,a+1===e.title.length&&(t.y+=e.titleMarginBottom-e.titleSpacing)})}},drawBody:function(t,e,s,a){s.textAlign=e._bodyAlign,s.textBaseline="top";var o=i.color(e.bodyColor);s.fillStyle=o.alpha(a*o.alpha()).rgbString(),s.font=i.fontString(e.bodyFontSize,e._bodyFontStyle,e._bodyFontFamily),i.each(e.beforeBody,function(i){s.fillText(i,t.x,t.y),t.y+=e.bodyFontSize+e.bodySpacing}),i.each(e.body,function(o,n){"single"!==this._options.tooltips.mode&&(s.fillStyle=i.color(e.legendColorBackground).alpha(a).rgbaString(),s.fillRect(t.x,t.y,e.bodyFontSize,e.bodyFontSize),s.strokeStyle=i.color(e.labelColors[n].borderColor).alpha(a).rgbaString(),s.strokeRect(t.x,t.y,e.bodyFontSize,e.bodyFontSize),s.fillStyle=i.color(e.labelColors[n].backgroundColor).alpha(a).rgbaString(),s.fillRect(t.x+1,t.y+1,e.bodyFontSize-2,e.bodyFontSize-2),s.fillStyle=i.color(e.bodyColor).alpha(a).rgbaString()),s.fillText(o,t.x+("single"!==this._options.tooltips.mode?e.bodyFontSize+2:0),t.y),t.y+=e.bodyFontSize+e.bodySpacing},this),i.each(e.afterBody,function(i){s.fillText(i,t.x,t.y),t.y+=e.bodyFontSize}),t.y-=e.bodySpacing},drawFooter:function(t,e,s,a){if(e.footer.length){t.y+=e.footerMarginTop,s.textAlign=e._footerAlign,s.textBaseline="top";var o=i.color(e.footerColor);s.fillStyle=o.alpha(a*o.alpha()).rgbString(),s.font=i.fontString(e.footerFontSize,e._footerFontStyle,e._footerFontFamily),i.each(e.footer,function(i){s.fillText(i,t.x,t.y),t.y+=e.footerFontSize+e.footerSpacing})}},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var s=e.caretPadding,a=this.getTooltipSize(e),o={x:e.x,y:e.y},n=Math.abs(e.opacity<.001)?0:e.opacity;if(this._options.tooltips.enabled){var r=i.color(e.backgroundColor);t.fillStyle=r.alpha(n*r.alpha()).rgbString(),i.drawRoundedRectangle(t,o.x,o.y,a.width,a.height,e.cornerRadius),t.fill(),this.drawCaret(o,a,n,s),o.x+=e.xPadding,o.y+=e.yPadding,this.drawTitle(o,e,t,n),this.drawBody(o,e,t,n),this.drawFooter(o,e,t,n)}}}})}},{}],33:[function(t,e,i){"use strict";e.exports=function(t,e){var i=t.helpers;t.defaults.global.elements.arc={backgroundColor:t.defaults.global.defaultColor,borderColor:"#fff",borderWidth:2},t.elements.Arc=t.Element.extend({inLabelRange:function(t){var e=this._view;return e?Math.pow(t-e.x,2)1.5*Math.PI?s.startAngle-2*Math.PI:s.startAngle,n=s.endAngle<-.5*Math.PI?s.endAngle+2*Math.PI:s.endAngle>1.5*Math.PI?s.endAngle-2*Math.PI:s.endAngle,r=a.angle>=o&&a.angle<=n,l=a.distance>=s.innerRadius&&a.distance<=s.outerRadius;return r&&l}return!1},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,i=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*i,y:t.y+Math.sin(e)*i}},draw:function(){var t=this._chart.ctx,e=this._view;t.beginPath(),t.arc(e.x,e.y,e.outerRadius,e.startAngle,e.endAngle),t.arc(e.x,e.y,e.innerRadius,e.endAngle,e.startAngle,!0),t.closePath(),t.strokeStyle=e.borderColor,t.lineWidth=e.borderWidth,t.fillStyle=e.backgroundColor,t.fill(),t.lineJoin="bevel",e.borderWidth&&t.stroke()}})}},{}],34:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.elements.line={tension:.4,backgroundColor:t.defaults.global.defaultColor,borderWidth:3,borderColor:t.defaults.global.defaultColor,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",fill:!0},t.elements.Line=t.Element.extend({lineToNextPoint:function(t,e,i,s,a){var o=this._chart.ctx;e._view.skip?s.call(this,t,e,i):t._view.skip?a.call(this,t,e,i):0===e._view.tension?o.lineTo(e._view.x,e._view.y):o.bezierCurveTo(t._view.controlPointNextX,t._view.controlPointNextY,e._view.controlPointPreviousX,e._view.controlPointPreviousY,e._view.x,e._view.y)},draw:function(){function i(t){n._view.skip||r._view.skip?t&&o.lineTo(s._view.scaleZero.x,s._view.scaleZero.y):o.bezierCurveTo(r._view.controlPointNextX,r._view.controlPointNextY,n._view.controlPointPreviousX,n._view.controlPointPreviousY,n._view.x,n._view.y)}var s=this,a=this._view,o=this._chart.ctx,n=this._children[0],r=this._children[this._children.length-1];o.save(),this._children.length>0&&a.fill&&(o.beginPath(),e.each(this._children,function(t,i){var s=e.previousItem(this._children,i),n=e.nextItem(this._children,i);0===i?(this._loop?o.moveTo(a.scaleZero.x,a.scaleZero.y):o.moveTo(t._view.x,a.scaleZero),t._view.skip?this._loop||o.moveTo(n._view.x,this._view.scaleZero):o.lineTo(t._view.x,t._view.y)):this.lineToNextPoint(s,t,n,function(t,e,i){this._loop?o.lineTo(this._view.scaleZero.x,this._view.scaleZero.y):(o.lineTo(t._view.x,this._view.scaleZero),o.moveTo(i._view.x,this._view.scaleZero))},function(t,e){o.lineTo(e._view.x,e._view.y)})},this),this._loop?i(!0):(o.lineTo(this._children[this._children.length-1]._view.x,a.scaleZero),o.lineTo(this._children[0]._view.x,a.scaleZero)),o.fillStyle=a.backgroundColor||t.defaults.global.defaultColor,o.closePath(),o.fill()),o.lineCap=a.borderCapStyle||t.defaults.global.elements.line.borderCapStyle,o.setLineDash&&o.setLineDash(a.borderDash||t.defaults.global.elements.line.borderDash),o.lineDashOffset=a.borderDashOffset||t.defaults.global.elements.line.borderDashOffset,o.lineJoin=a.borderJoinStyle||t.defaults.global.elements.line.borderJoinStyle,o.lineWidth=a.borderWidth||t.defaults.global.elements.line.borderWidth,o.strokeStyle=a.borderColor||t.defaults.global.defaultColor,o.beginPath(),e.each(this._children,function(t,i){var s=e.previousItem(this._children,i),a=e.nextItem(this._children,i);0===i?o.moveTo(t._view.x,t._view.y):this.lineToNextPoint(s,t,a,function(t,e,i){o.moveTo(i._view.x,i._view.y)},function(t,e){o.moveTo(e._view.x,e._view.y)})},this),this._loop&&this._children.length>0&&i(),o.stroke(),o.restore()}})}},{}],35:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.elements.point={radius:3,pointStyle:"circle",backgroundColor:t.defaults.global.defaultColor,borderWidth:1,borderColor:t.defaults.global.defaultColor,hitRadius:1,hoverRadius:4,hoverBorderWidth:1},t.elements.Point=t.Element.extend({inRange:function(t,e){var i=this._view;if(i){var s=i.hitRadius+i.radius;return Math.pow(t-i.x,2)+Math.pow(e-i.y,2)0){s.strokeStyle=i.borderColor||t.defaults.global.defaultColor,s.lineWidth=e.getValueOrDefault(i.borderWidth,t.defaults.global.elements.point.borderWidth),s.fillStyle=i.backgroundColor||t.defaults.global.defaultColor;var a,o,n=i.radius;switch(i.pointStyle){default:s.beginPath(),s.arc(i.x,i.y,n,0,2*Math.PI),s.closePath(),s.fill();break;case"triangle":s.beginPath();var r=3*n/Math.sqrt(3),l=r*Math.sqrt(3)/2;s.moveTo(i.x-r/2,i.y+l/3),s.lineTo(i.x+r/2,i.y+l/3),s.lineTo(i.x,i.y-2*l/3),s.closePath(),s.fill();break;case"rect":s.fillRect(i.x-1/Math.SQRT2*n,i.y-1/Math.SQRT2*n,2/Math.SQRT2*n,2/Math.SQRT2*n),s.strokeRect(i.x-1/Math.SQRT2*n,i.y-1/Math.SQRT2*n,2/Math.SQRT2*n,2/Math.SQRT2*n);break;case"rectRot":s.translate(i.x,i.y),s.rotate(Math.PI/4),s.fillRect(-1/Math.SQRT2*n,-1/Math.SQRT2*n,2/Math.SQRT2*n,2/Math.SQRT2*n),s.strokeRect(-1/Math.SQRT2*n,-1/Math.SQRT2*n,2/Math.SQRT2*n,2/Math.SQRT2*n),s.setTransform(1,0,0,1,0,0);break;case"cross":s.beginPath(),s.moveTo(i.x,i.y+n),s.lineTo(i.x,i.y-n),s.moveTo(i.x-n,i.y),s.lineTo(i.x+n,i.y),s.closePath();break;case"crossRot":s.beginPath(),a=Math.cos(Math.PI/4)*n,o=Math.sin(Math.PI/4)*n,s.moveTo(i.x-a,i.y-o),s.lineTo(i.x+a,i.y+o),s.moveTo(i.x-a,i.y+o),s.lineTo(i.x+a,i.y-o),s.closePath();break;case"star":s.beginPath(),s.moveTo(i.x,i.y+n),s.lineTo(i.x,i.y-n),s.moveTo(i.x-n,i.y),s.lineTo(i.x+n,i.y),a=Math.cos(Math.PI/4)*n,o=Math.sin(Math.PI/4)*n,s.moveTo(i.x-a,i.y-o),s.lineTo(i.x+a,i.y+o),s.moveTo(i.x-a,i.y+o),s.lineTo(i.x+a,i.y-o),s.closePath();break;case"line":s.beginPath(),s.moveTo(i.x-n,i.y),s.lineTo(i.x+n,i.y),s.closePath();break;case"dash":s.beginPath(),s.moveTo(i.x,i.y),s.lineTo(i.x+n,i.y),s.closePath()}s.stroke()}}}})}},{}],36:[function(t,e,i){"use strict";e.exports=function(t){t.helpers;t.defaults.global.elements.rectangle={backgroundColor:t.defaults.global.defaultColor,borderWidth:0,borderColor:t.defaults.global.defaultColor,borderSkipped:"bottom"},t.elements.Rectangle=t.Element.extend({draw:function(){function t(t){return l[(c+t)%4]}var e=this._chart.ctx,i=this._view,s=i.width/2,a=i.x-s,o=i.x+s,n=i.base-(i.base-i.y),r=i.borderWidth/2;i.borderWidth&&(a+=r,o-=r,n+=r),e.beginPath(),e.fillStyle=i.backgroundColor,e.strokeStyle=i.borderColor,e.lineWidth=i.borderWidth;var l=[[a,i.base],[a,n],[o,n],[o,i.base]],h=["bottom","left","top","right"],c=h.indexOf(i.borderSkipped,0);-1===c&&(c=0),e.moveTo.apply(e,t(0));for(var d=1;4>d;d++)e.lineTo.apply(e,t(d));e.fill(),i.borderWidth&&e.stroke()},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){var i=this._view,s=!1;return i&&(s=i.y=i.x-i.width/2&&t<=i.x+i.width/2&&e>=i.y&&e<=i.base:t>=i.x-i.width/2&&t<=i.x+i.width/2&&e>=i.base&&e<=i.y),s},inLabelRange:function(t){var e=this._view;return e?t>=e.x-e.width/2&&t<=e.x+e.width/2:!1},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}})}},{}],37:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers,i={position:"bottom"},s=t.Scale.extend({buildTicks:function(t){this.startIndex=0,this.endIndex=this.chart.data.labels.length;var i;void 0!==this.options.ticks.min&&(i=e.indexOf(this.chart.data.labels,this.options.ticks.min),this.startIndex=-1!==i?i:this.startIndex),void 0!==this.options.ticks.max&&(i=e.indexOf(this.chart.data.labels,this.options.ticks.max),this.endIndex=-1!==i?i:this.endIndex),this.ticks=0===this.startIndex&&this.endIndex===this.chart.data.labels.length?this.chart.data.labels:this.chart.data.labels.slice(this.startIndex,this.endIndex+1)},getLabelForIndex:function(t,e){return this.ticks[t]},getPixelForValue:function(t,e,i,s){var a=Math.max(this.ticks.length-(this.options.gridLines.offsetGridLines?0:1),1);if(this.isHorizontal()){var o=this.width-(this.paddingLeft+this.paddingRight),n=o/a,r=n*(e-this.startIndex)+this.paddingLeft;return this.options.gridLines.offsetGridLines&&s&&(r+=n/2),this.left+Math.round(r)}var l=this.height-(this.paddingTop+this.paddingBottom),h=l/a,c=h*(e-this.startIndex)+this.paddingTop;return this.options.gridLines.offsetGridLines&&s&&(c+=h/2),this.top+Math.round(c)},getPixelForTick:function(t,e){return this.getPixelForValue(this.ticks[t],t+this.startIndex,null,e)}});t.scaleService.registerScaleType("category",s,i)}},{}],38:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers,i={position:"left",ticks:{callback:function(t,i,s){var a=s[1]-s[0];Math.abs(a)>1&&t!==Math.floor(t)&&(a=t-Math.floor(t));var o=e.log10(Math.abs(a)),n="";if(0!==t){var r=-1*Math.floor(o);r=Math.max(Math.min(r,20),0),n=t.toFixed(r)}else n="0";return n}}},s=t.Scale.extend({determineDataLimits:function(){if(this.min=null,this.max=null,this.options.stacked){var t={},i=!1,s=!1;e.each(this.chart.data.datasets,function(a){void 0===t[a.type]&&(t[a.type]={positiveValues:[],negativeValues:[]});var o=t[a.type].positiveValues,n=t[a.type].negativeValues;e.isDatasetVisible(a)&&(this.isHorizontal()?a.xAxisID===this.id:a.yAxisID===this.id)&&e.each(a.data,function(t,e){var a=+this.getRightValue(t);isNaN(a)||(o[e]=o[e]||0,n[e]=n[e]||0,this.options.relativePoints?o[e]=100:0>a?(s=!0,n[e]+=a):(i=!0,o[e]+=a))},this)},this),e.each(t,function(t){var i=t.positiveValues.concat(t.negativeValues),s=e.min(i),a=e.max(i);this.min=null===this.min?s:Math.min(this.min,s),this.max=null===this.max?a:Math.max(this.max,a)},this)}else e.each(this.chart.data.datasets,function(t){e.isDatasetVisible(t)&&(this.isHorizontal()?t.xAxisID===this.id:t.yAxisID===this.id)&&e.each(t.data,function(t,e){var i=+this.getRightValue(t);isNaN(i)||(null===this.min?this.min=i:ithis.max&&(this.max=i))},this)},this);if(this.options.ticks.beginAtZero){var a=e.sign(this.min),o=e.sign(this.max);0>a&&0>o?this.max=0:a>0&&o>0&&(this.min=0)}void 0!==this.options.ticks.min?this.min=this.options.ticks.min:void 0!==this.options.ticks.suggestedMin&&(this.min=Math.min(this.min,this.options.ticks.suggestedMin)),void 0!==this.options.ticks.max?this.max=this.options.ticks.max:void 0!==this.options.ticks.suggestedMax&&(this.max=Math.max(this.max,this.options.ticks.suggestedMax)),this.min===this.max&&(this.min--,this.max++)},buildTicks:function(){this.ticks=[];var i;if(this.isHorizontal())i=Math.min(this.options.ticks.maxTicksLimit?this.options.ticks.maxTicksLimit:11,Math.ceil(this.width/50));else{var s=e.getValueOrDefault(this.options.ticks.fontSize,t.defaults.global.defaultFontSize);i=Math.min(this.options.ticks.maxTicksLimit?this.options.ticks.maxTicksLimit:11,Math.ceil(this.height/(2*s)))}i=Math.max(2,i);var a,o=this.options.ticks.fixedStepSize&&this.options.ticks.fixedStepSize>0||this.options.ticks.stepSize&&this.options.ticks.stepSize>0;if(o)a=e.getValueOrDefault(this.options.ticks.fixedStepSize,this.options.ticks.stepSize);else{var n=e.niceNum(this.max-this.min,!1);a=e.niceNum(n/(i-1),!0)}var r=Math.floor(this.min/a)*a,l=Math.ceil(this.max/a)*a,h=(l-r)/a;h=e.almostEquals(h,Math.round(h),a/1e3)?Math.round(h):Math.ceil(h),this.ticks.push(void 0!==this.options.ticks.min?this.options.ticks.min:r);for(var c=1;h>c;++c)this.ticks.push(r+c*a);this.ticks.push(void 0!==this.options.ticks.max?this.options.ticks.max:l),"left"!==this.options.position&&"right"!==this.options.position||this.ticks.reverse(),this.max=e.max(this.ticks),this.min=e.min(this.ticks),this.options.ticks.reverse?(this.ticks.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},convertTicksToLabels:function(){this.ticksAsNumbers=this.ticks.slice(),this.zeroLineIndex=this.ticks.indexOf(0),t.Scale.prototype.convertTicksToLabels.call(this)},getPixelForValue:function(t,e,i,s){var a,o=+this.getRightValue(t),n=this.end-this.start;if(this.isHorizontal()){var r=this.width-(this.paddingLeft+this.paddingRight);return a=this.left+r/n*(o-this.start),Math.round(a+this.paddingLeft)}var l=this.height-(this.paddingTop+this.paddingBottom);return a=this.bottom-this.paddingBottom-l/n*(o-this.start),Math.round(a)},getPixelForTick:function(t,e){return this.getPixelForValue(this.ticksAsNumbers[t],null,null,e)}});t.scaleService.registerScaleType("linear",s,i)}},{}],39:[function(t,e,i){"use strict";e.exports=function(t){var e=t.helpers,i={position:"left",ticks:{callback:function(e,i,s){var a=e/Math.pow(10,Math.floor(t.helpers.log10(e)));return 1===a||2===a||5===a||0===i||i===s.length-1?e.toExponential():""}}},s=t.Scale.extend({determineDataLimits:function(){if(this.min=null,this.max=null,this.options.stacked){var t={};e.each(this.chart.data.datasets,function(i){e.isDatasetVisible(i)&&(this.isHorizontal()?i.xAxisID===this.id:i.yAxisID===this.id)&&(void 0===t[i.type]&&(t[i.type]=[]),e.each(i.data,function(e,s){var a=t[i.type],o=+this.getRightValue(e);isNaN(o)||(a[s]=a[s]||0,this.options.relativePoints?a[s]=100:a[s]+=o)},this))},this),e.each(t,function(t){var i=e.min(t),s=e.max(t);this.min=null===this.min?i:Math.min(this.min,i),this.max=null===this.max?s:Math.max(this.max,s)},this)}else e.each(this.chart.data.datasets,function(t){e.isDatasetVisible(t)&&(this.isHorizontal()?t.xAxisID===this.id:t.yAxisID===this.id)&&e.each(t.data,function(t,e){var i=+this.getRightValue(t);isNaN(i)||(null===this.min?this.min=i:ithis.max&&(this.max=i))},this)},this);this.min=void 0!==this.options.ticks.min?this.options.ticks.min:this.min,this.max=void 0!==this.options.ticks.max?this.options.ticks.max:this.max,this.min===this.max&&(0!==this.min&&null!==this.min?(this.min=Math.pow(10,Math.floor(e.log10(this.min))-1),this.max=Math.pow(10,Math.floor(e.log10(this.max))+1)):(this.min=1,this.max=10))},buildTicks:function(){this.ticks=[];for(var t=void 0!==this.options.ticks.min?this.options.ticks.min:Math.pow(10,Math.floor(e.log10(this.min)));tthis.max&&(this.max=i))},this)},this),this.options.ticks.beginAtZero){var t=e.sign(this.min),i=e.sign(this.max);0>t&&0>i?this.max=0:t>0&&i>0&&(this.min=0)}void 0!==this.options.ticks.min?this.min=this.options.ticks.min:void 0!==this.options.ticks.suggestedMin&&(this.min=Math.min(this.min,this.options.ticks.suggestedMin)),void 0!==this.options.ticks.max?this.max=this.options.ticks.max:void 0!==this.options.ticks.suggestedMax&&(this.max=Math.max(this.max,this.options.ticks.suggestedMax)),this.min===this.max&&(this.min--,this.max++)},buildTicks:function(){this.ticks=[];var i=e.getValueOrDefault(this.options.ticks.fontSize,t.defaults.global.defaultFontSize),s=Math.min(this.options.ticks.maxTicksLimit?this.options.ticks.maxTicksLimit:11,Math.ceil(this.drawingArea/(1.5*i)));s=Math.max(2,s);var a=e.niceNum(this.max-this.min,!1),o=e.niceNum(a/(s-1),!0),n=Math.floor(this.min/o)*o,r=Math.ceil(this.max/o)*o,l=Math.ceil((r-n)/o);this.ticks.push(void 0!==this.options.ticks.min?this.options.ticks.min:n);for(var h=1;l>h;++h)this.ticks.push(n+h*o);this.ticks.push(void 0!==this.options.ticks.max?this.options.ticks.max:r),this.max=e.max(this.ticks),this.min=e.min(this.ticks),this.options.ticks.reverse?(this.ticks.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),this.zeroLineIndex=this.ticks.indexOf(0)},convertTicksToLabels:function(){t.Scale.prototype.convertTicksToLabels.call(this),this.pointLabels=this.chart.data.labels.map(this.options.pointLabels.callback,this)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},fit:function(){var i,s,a,o,n,r,l,h,c,d,u,f,m=e.getValueOrDefault(this.options.pointLabels.fontSize,t.defaults.global.defaultFontSize),g=e.getValueOrDefault(this.options.pointLabels.fontStyle,t.defaults.global.defaultFontStyle),p=e.getValueOrDefault(this.options.pointLabels.fontFamily,t.defaults.global.defaultFontFamily),b=e.fontString(m,g,p),v=e.min([this.height/2-m-5,this.width/2]),x=this.width,y=0;for(this.ctx.font=b,s=0;sx&&(x=i.x+o,n=s),i.x-ox&&(x=i.x+a,n=s):s>this.getValueCount()/2&&i.x-a0||this.options.reverse){var o=this.getDistanceFromCenterForValue(this.ticks[a]),n=this.yCenter-o;if(this.options.gridLines.display)if(i.strokeStyle=this.options.gridLines.color,i.lineWidth=this.options.gridLines.lineWidth,this.options.lineArc)i.beginPath(),i.arc(this.xCenter,this.yCenter,o,0,2*Math.PI),i.closePath(),i.stroke();else{i.beginPath();for(var r=0;r=0;s--){if(this.options.angleLines.display){var a=this.getPointPosition(s,this.getDistanceFromCenterForValue(this.options.reverse?this.min:this.max));i.beginPath(),i.moveTo(this.xCenter,this.yCenter),i.lineTo(a.x,a.y),i.stroke(),i.closePath()}var o=this.getPointPosition(s,this.getDistanceFromCenterForValue(this.options.reverse?this.min:this.max)+5),n=e.getValueOrDefault(this.options.pointLabels.fontColor,t.defaults.global.defaultFontColor),r=e.getValueOrDefault(this.options.pointLabels.fontSize,t.defaults.global.defaultFontSize),l=e.getValueOrDefault(this.options.pointLabels.fontStyle,t.defaults.global.defaultFontStyle),h=e.getValueOrDefault(this.options.pointLabels.fontFamily,t.defaults.global.defaultFontFamily),c=e.fontString(r,l,h);i.font=c,i.fillStyle=n;var d=this.pointLabels.length,u=this.pointLabels.length/2,f=u/2,m=f>s||s>d-f,g=s===f||s===d-f;0===s?i.textAlign="center":s===u?i.textAlign="center":u>s?i.textAlign="left":i.textAlign="right",g?i.textBaseline="middle":m?i.textBaseline="bottom":i.textBaseline="top",i.fillText(this.pointLabels[s]?this.pointLabels[s]:"",o.x,o.y)}}}}});t.scaleService.registerScaleType("radialLinear",s,i)}},{}],41:[function(t,e,i){"use strict";var s=t("moment");s="function"==typeof s?s:window.moment,e.exports=function(t){var e=t.helpers,i={units:[{name:"millisecond",steps:[1,2,5,10,20,50,100,250,500]},{name:"second",steps:[1,2,5,10,30]},{name:"minute",steps:[1,2,5,10,30]},{name:"hour",steps:[1,2,3,6,12]},{name:"day",steps:[1,2,5]},{name:"week",maxStep:4},{name:"month",maxStep:3},{name:"quarter",maxStep:4},{name:"year",maxStep:!1}]},a={position:"bottom",time:{parser:!1,format:!1,unit:!1,round:!1,displayFormat:!1,displayFormats:{millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm:ss a",hour:"MMM D, hA",day:"ll",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"}},ticks:{autoSkip:!1}},o=t.Scale.extend({initialize:function(){if(!s)throw new Error("Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com");t.Scale.prototype.initialize.call(this)},getLabelMoment:function(t,e){return this.labelMoments[t][e]},determineDataLimits:function(){this.labelMoments=[];var t=[];this.chart.data.labels&&this.chart.data.labels.length>0?(e.each(this.chart.data.labels,function(e,i){var s=this.parseTime(e);this.options.time.round&&s.startOf(this.options.time.round),t.push(s)},this),this.firstTick=s.min.call(this,t), +this.lastTick=s.max.call(this,t)):(this.firstTick=null,this.lastTick=null),e.each(this.chart.data.datasets,function(i,a){var o=[];"object"==typeof i.data[0]?e.each(i.data,function(t,e){var i=this.parseTime(this.getRightValue(t));this.options.time.round&&i.startOf(this.options.time.round),o.push(i),this.firstTick=null!==this.firstTick?s.min(this.firstTick,i):i,this.lastTick=null!==this.lastTick?s.max(this.lastTick,i):i},this):o=t,this.labelMoments.push(o)},this),this.options.time.min&&(this.firstTick=this.parseTime(this.options.time.min)),this.options.time.max&&(this.lastTick=this.parseTime(this.options.time.max)),this.firstTick=(this.firstTick||s()).clone(),this.lastTick=(this.lastTick||s()).clone()},buildTicks:function(s){if(this.ticks=[],this.unitScale=1,this.scaleSizeInUnits=0,this.options.time.unit)this.tickUnit=this.options.time.unit||"day",this.displayFormat=this.options.time.displayFormats[this.tickUnit],this.scaleSizeInUnits=this.lastTick.diff(this.firstTick,this.tickUnit,!0),this.unitScale=e.getValueOrDefault(this.options.time.unitStepSize,1);else{var a=e.getValueOrDefault(this.options.ticks.fontSize,t.defaults.global.defaultFontSize),o=this.isHorizontal()?this.width-(this.paddingLeft+this.paddingRight):this.height-(this.paddingTop+this.paddingBottom),n=this.tickFormatFunction(this.firstTick,0,[]),r=n.length*a,l=Math.cos(e.toRadians(this.options.ticks.maxRotation)),h=Math.sin(e.toRadians(this.options.ticks.maxRotation));r=r*l+a*h;var c=o/(r+10);this.tickUnit="millisecond",this.scaleSizeInUnits=this.lastTick.diff(this.firstTick,this.tickUnit,!0),this.displayFormat=this.options.time.displayFormats[this.tickUnit];for(var d=0,u=i.units[d];dMath.ceil(this.scaleSizeInUnits/c)){this.unitScale=e.getValueOrDefault(this.options.time.unitStepSize,u.steps[f]);break}break}if(u.maxStep===!1||Math.ceil(this.scaleSizeInUnits/c)=0)break;g%this.unitScale===0&&this.ticks.push(p)}0===this.ticks[this.ticks.length-1].diff(this.lastTick,this.tickUnit)&&0!==this.scaleSizeInUnits||(this.options.time.max?(this.ticks.push(this.lastTick.clone()),this.scaleSizeInUnits=this.lastTick.diff(this.ticks[0],this.tickUnit,!0)):(this.scaleSizeInUnits=Math.ceil(this.scaleSizeInUnits/this.unitScale)*this.unitScale,this.ticks.push(this.firstTick.clone().add(this.scaleSizeInUnits,this.tickUnit)),this.lastTick=this.ticks[this.ticks.length-1].clone()))},getLabelForIndex:function(t,e){var i=this.chart.data.labels&&t +``` + +Alternatively, if you're using an AMD loader for JavaScript modules, that is also supported in the Chart.js core. Please note: the library will still occupy a global variable of `Chart`, even if it detects `define` and `define.amd`. If this is a problem, you can call `noConflict` to restore the global Chart variable to it's previous owner. + +```javascript +// Using requirejs +require(['path/to/Chartjs'], function(Chart){ + // Use Chart.js as normal here. + + // Chart.noConflict restores the Chart global variable to it's previous owner + // The function returns what was previously Chart, allowing you to reassign. + var Chartjs = Chart.noConflict(); + +}); +``` + +You can also grab Chart.js using bower: + +```bash +bower install chartjs --save +``` + +###Creating a chart + +To create a chart, we need to instantiate the `Chart` class. To do this, we need to pass in the 2d context of where we want to draw the chart. Here's an example. + +```html + +``` + +```javascript +// Get the context of the canvas element we want to select +var ctx = document.getElementById("myChart").getContext("2d"); +var myNewChart = new Chart(ctx).PolarArea(data); +``` + +We can also get the context of our canvas with jQuery. To do this, we need to get the DOM node out of the jQuery collection, and call the `getContext("2d")` method on that. + +```javascript +// Get context with jQuery - using jQuery's .get() method. +var ctx = $("#myChart").get(0).getContext("2d"); +// This will get the first returned node in the jQuery collection. +var myNewChart = new Chart(ctx); +``` + +After we've instantiated the Chart class on the canvas we want to draw on, Chart.js will handle the scaling for retina displays. + +With the Chart class set up, we can go on to create one of the charts Chart.js has available. In the example below, we would be drawing a Polar area chart. + +```javascript +new Chart(ctx).PolarArea(data, options); +``` + +We call a method of the name of the chart we want to create. We pass in the data for that chart type, and the options for that chart as parameters. Chart.js will merge the global defaults with chart type specific defaults, then merge any options passed in as a second argument after data. + +###Global chart configuration + +This concept was introduced in Chart.js 1.0 to keep configuration DRY, and allow for changing options globally across chart types, avoiding the need to specify options for each instance, or the default for a particular chart type. + +```javascript +Chart.defaults.global = { + // Boolean - Whether to animate the chart + animation: true, + + // Number - Number of animation steps + animationSteps: 60, + + // String - Animation easing effect + animationEasing: "easeOutQuart", + + // Boolean - If we should show the scale at all + showScale: true, + + // Boolean - If we want to override with a hard coded scale + scaleOverride: false, + + // ** Required if scaleOverride is true ** + // Number - The number of steps in a hard coded scale + scaleSteps: null, + // Number - The value jump in the hard coded scale + scaleStepWidth: null, + // Number - The scale starting value + scaleStartValue: null, + + // String - Colour of the scale line + scaleLineColor: "rgba(0,0,0,.1)", + + // Number - Pixel width of the scale line + scaleLineWidth: 1, + + // Boolean - Whether to show labels on the scale + scaleShowLabels: true, + + // Interpolated JS string - can access value + scaleLabel: "<%=value%>", + + // Boolean - Whether the scale should stick to integers, not floats even if drawing space is there + scaleIntegersOnly: true, + + // Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value + scaleBeginAtZero: false, + + // String - Scale label font declaration for the scale label + scaleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + + // Number - Scale label font size in pixels + scaleFontSize: 12, + + // String - Scale label font weight style + scaleFontStyle: "normal", + + // String - Scale label font colour + scaleFontColor: "#666", + + // Boolean - whether or not the chart should be responsive and resize when the browser does. + responsive: false, + + // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container + maintainAspectRatio: true, + + // Boolean - Determines whether to draw tooltips on the canvas or not + showTooltips: true, + + // Array - Array of string names to attach tooltip events + tooltipEvents: ["mousemove", "touchstart", "touchmove"], + + // String - Tooltip background colour + tooltipFillColor: "rgba(0,0,0,0.8)", + + // String - Tooltip label font declaration for the scale label + tooltipFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + + // Number - Tooltip label font size in pixels + tooltipFontSize: 14, + + // String - Tooltip font weight style + tooltipFontStyle: "normal", + + // String - Tooltip label font colour + tooltipFontColor: "#fff", + + // String - Tooltip title font declaration for the scale label + tooltipTitleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + + // Number - Tooltip title font size in pixels + tooltipTitleFontSize: 14, + + // String - Tooltip title font weight style + tooltipTitleFontStyle: "bold", + + // String - Tooltip title font colour + tooltipTitleFontColor: "#fff", + + // Number - pixel width of padding around tooltip text + tooltipYPadding: 6, + + // Number - pixel width of padding around tooltip text + tooltipXPadding: 6, + + // Number - Size of the caret on the tooltip + tooltipCaretSize: 8, + + // Number - Pixel radius of the tooltip border + tooltipCornerRadius: 6, + + // Number - Pixel offset from point x to tooltip edge + tooltipXOffset: 10, + {% raw %} + // String - Template string for single tooltips + tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= value %>", + {% endraw %} + // String - Template string for single tooltips + multiTooltipTemplate: "<%= value %>", + + // Function - Will fire on animation progression. + onAnimationProgress: function(){}, + + // Function - Will fire on animation completion. + onAnimationComplete: function(){} +} +``` + +If for example, you wanted all charts created to be responsive, and resize when the browser window does, the following setting can be changed: + +```javascript +Chart.defaults.global.responsive = true; +``` + +Now, every time we create a chart, `options.responsive` will be `true`. diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/docs/01-Line-Chart.md b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/01-Line-Chart.md new file mode 100755 index 0000000..3dc6063 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/01-Line-Chart.md @@ -0,0 +1,160 @@ +--- +title: Line Chart +anchor: line-chart +--- +###Introduction +A line chart is a way of plotting data points on a line. + +Often, it is used to show trend data, and the comparison of two data sets. + +
+ +
+ +###Example usage +```javascript +var myLineChart = new Chart(ctx).Line(data, options); +``` +###Data structure + +```javascript +var data = { + labels: ["January", "February", "March", "April", "May", "June", "July"], + datasets: [ + { + label: "My First dataset", + fillColor: "rgba(220,220,220,0.2)", + strokeColor: "rgba(220,220,220,1)", + pointColor: "rgba(220,220,220,1)", + pointStrokeColor: "#fff", + pointHighlightFill: "#fff", + pointHighlightStroke: "rgba(220,220,220,1)", + data: [65, 59, 80, 81, 56, 55, 40] + }, + { + label: "My Second dataset", + fillColor: "rgba(151,187,205,0.2)", + strokeColor: "rgba(151,187,205,1)", + pointColor: "rgba(151,187,205,1)", + pointStrokeColor: "#fff", + pointHighlightFill: "#fff", + pointHighlightStroke: "rgba(151,187,205,1)", + data: [28, 48, 40, 19, 86, 27, 90] + } + ] +}; +``` + +The line chart requires an array of labels for each of the data points. This is shown on the X axis. +The data for line charts is broken up into an array of datasets. Each dataset has a colour for the fill, a colour for the line and colours for the points and strokes of the points. These colours are strings just like CSS. You can use RGBA, RGB, HEX or HSL notation. + +The label key on each dataset is optional, and can be used when generating a scale for the chart. + +### Chart options + +These are the customisation options specific to Line charts. These options are merged with the [global chart configuration options](#getting-started-global-chart-configuration), and form the options of the chart. + +```javascript +{ + + ///Boolean - Whether grid lines are shown across the chart + scaleShowGridLines : true, + + //String - Colour of the grid lines + scaleGridLineColor : "rgba(0,0,0,.05)", + + //Number - Width of the grid lines + scaleGridLineWidth : 1, + + //Boolean - Whether the line is curved between points + bezierCurve : true, + + //Number - Tension of the bezier curve between points + bezierCurveTension : 0.4, + + //Boolean - Whether to show a dot for each point + pointDot : true, + + //Number - Radius of each point dot in pixels + pointDotRadius : 4, + + //Number - Pixel width of point dot stroke + pointDotStrokeWidth : 1, + + //Number - amount extra to add to the radius to cater for hit detection outside the drawn point + pointHitDetectionRadius : 20, + + //Boolean - Whether to show a stroke for datasets + datasetStroke : true, + + //Number - Pixel width of dataset stroke + datasetStrokeWidth : 2, + + //Boolean - Whether to fill the dataset with a colour + datasetFill : true, + {% raw %} + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
" + {% endraw %} +}; +``` + +You can override these for your `Chart` instance by passing a second argument into the `Line` method as an object with the keys you want to override. + +For example, we could have a line chart without bezier curves between points by doing the following: + +```javascript +new Chart(ctx).Line(data, { + bezierCurve: false +}); +// This will create a chart with all of the default options, merged from the global config, +// and the Line chart defaults, but this particular instance will have `bezierCurve` set to false. +``` + +We can also change these defaults values for each Line type that is created, this object is available at `Chart.defaults.Line`. + + +### Prototype methods + +#### .getPointsAtEvent( event ) + +Calling `getPointsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the point elements that are at that the same position of that event. + +```javascript +canvas.onclick = function(evt){ + var activePoints = myLineChart.getPointsAtEvent(evt); + // => activePoints is an array of points on the canvas that are at the same position as the click event. +}; +``` + +This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application. + +#### .update( ) + +Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop. + +```javascript +myLineChart.datasets[0].points[2].value = 50; +// Would update the first dataset's value of 'March' to be 50 +myLineChart.update(); +// Calling update now animates the position of March from 90 to 50. +``` + +#### .addData( valuesArray, label ) + +Calling `addData(valuesArray, label)` on your Chart instance passing an array of values for each dataset, along with a label for those points. + +```javascript +// The values array passed into addData should be one for each dataset in the chart +myLineChart.addData([40, 60], "August"); +// This new data will now animate at the end of the chart. +``` + +#### .removeData( ) + +Calling `removeData()` on your Chart instance will remove the first value for all datasets on the chart. + +```javascript +myLineChart.removeData(); +// The chart will remove the first point and animate other points into place +``` diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/docs/02-Bar-Chart.md b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/02-Bar-Chart.md new file mode 100755 index 0000000..b4253e7 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/02-Bar-Chart.md @@ -0,0 +1,143 @@ +--- +title: Bar Chart +anchor: bar-chart +--- + +### Introduction +A bar chart is a way of showing data as bars. + +It is sometimes used to show trend data, and the comparison of multiple data sets side by side. + +
+ +
+ +### Example usage +```javascript +var myBarChart = new Chart(ctx).Bar(data, options); +``` + +### Data structure + +```javascript +var data = { + labels: ["January", "February", "March", "April", "May", "June", "July"], + datasets: [ + { + label: "My First dataset", + fillColor: "rgba(220,220,220,0.5)", + strokeColor: "rgba(220,220,220,0.8)", + highlightFill: "rgba(220,220,220,0.75)", + highlightStroke: "rgba(220,220,220,1)", + data: [65, 59, 80, 81, 56, 55, 40] + }, + { + label: "My Second dataset", + fillColor: "rgba(151,187,205,0.5)", + strokeColor: "rgba(151,187,205,0.8)", + highlightFill: "rgba(151,187,205,0.75)", + highlightStroke: "rgba(151,187,205,1)", + data: [28, 48, 40, 19, 86, 27, 90] + } + ] +}; +``` +The bar chart has the a very similar data structure to the line chart, and has an array of datasets, each with colours and an array of data. Again, colours are in CSS format. +We have an array of labels too for display. In the example, we are showing the same data as the previous line chart example. + +The label key on each dataset is optional, and can be used when generating a scale for the chart. + +### Chart Options + +These are the customisation options specific to Bar charts. These options are merged with the [global chart configuration options](#getting-started-global-chart-configuration), and form the options of the chart. + +```javascript +{ + //Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value + scaleBeginAtZero : true, + + //Boolean - Whether grid lines are shown across the chart + scaleShowGridLines : true, + + //String - Colour of the grid lines + scaleGridLineColor : "rgba(0,0,0,.05)", + + //Number - Width of the grid lines + scaleGridLineWidth : 1, + + //Boolean - If there is a stroke on each bar + barShowStroke : true, + + //Number - Pixel width of the bar stroke + barStrokeWidth : 2, + + //Number - Spacing between each of the X value sets + barValueSpacing : 5, + + //Number - Spacing between data sets within X values + barDatasetSpacing : 1, + {% raw %} + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
" + {% endraw %} +} +``` + +You can override these for your `Chart` instance by passing a second argument into the `Bar` method as an object with the keys you want to override. + +For example, we could have a bar chart without a stroke on each bar by doing the following: + +```javascript +new Chart(ctx).Bar(data, { + barShowStroke: false +}); +// This will create a chart with all of the default options, merged from the global config, +// and the Bar chart defaults but this particular instance will have `barShowStroke` set to false. +``` + +We can also change these defaults values for each Bar type that is created, this object is available at `Chart.defaults.Bar`. + +### Prototype methods + +#### .getBarsAtEvent( event ) + +Calling `getBarsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the bar elements that are at that the same position of that event. + +```javascript +canvas.onclick = function(evt){ + var activeBars = myBarChart.getBarsAtEvent(evt); + // => activeBars is an array of bars on the canvas that are at the same position as the click event. +}; +``` + +This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application. + +#### .update( ) + +Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop. + +```javascript +myBarChart.datasets[0].bars[2].value = 50; +// Would update the first dataset's value of 'March' to be 50 +myBarChart.update(); +// Calling update now animates the position of March from 90 to 50. +``` + +#### .addData( valuesArray, label ) + +Calling `addData(valuesArray, label)` on your Chart instance passing an array of values for each dataset, along with a label for those bars. + +```javascript +// The values array passed into addData should be one for each dataset in the chart +myBarChart.addData([40, 60], "August"); +// The new data will now animate at the end of the chart. +``` + +#### .removeData( ) + +Calling `removeData()` on your Chart instance will remove the first value for all datasets on the chart. + +```javascript +myBarChart.removeData(); +// The chart will now animate and remove the first bar +``` \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/docs/03-Radar-Chart.md b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/03-Radar-Chart.md new file mode 100755 index 0000000..0707444 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/03-Radar-Chart.md @@ -0,0 +1,177 @@ +--- +title: Radar Chart +anchor: radar-chart +--- + +###Introduction +A radar chart is a way of showing multiple data points and the variation between them. + +They are often useful for comparing the points of two or more different data sets. + +
+ +
+ +###Example usage + +```javascript +var myRadarChart = new Chart(ctx).Radar(data, options); +``` + +###Data structure +```javascript +var data = { + labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"], + datasets: [ + { + label: "My First dataset", + fillColor: "rgba(220,220,220,0.2)", + strokeColor: "rgba(220,220,220,1)", + pointColor: "rgba(220,220,220,1)", + pointStrokeColor: "#fff", + pointHighlightFill: "#fff", + pointHighlightStroke: "rgba(220,220,220,1)", + data: [65, 59, 90, 81, 56, 55, 40] + }, + { + label: "My Second dataset", + fillColor: "rgba(151,187,205,0.2)", + strokeColor: "rgba(151,187,205,1)", + pointColor: "rgba(151,187,205,1)", + pointStrokeColor: "#fff", + pointHighlightFill: "#fff", + pointHighlightStroke: "rgba(151,187,205,1)", + data: [28, 48, 40, 19, 96, 27, 100] + } + ] +}; +``` +For a radar chart, to provide context of what each point means, we include an array of strings that show around each point in the chart. +For the radar chart data, we have an array of datasets. Each of these is an object, with a fill colour, a stroke colour, a colour for the fill of each point, and a colour for the stroke of each point. We also have an array of data values. + +The label key on each dataset is optional, and can be used when generating a scale for the chart. + +### Chart options + +These are the customisation options specific to Radar charts. These options are merged with the [global chart configuration options](#getting-started-global-chart-configuration), and form the options of the chart. + + +```javascript +{ + //Boolean - Whether to show lines for each scale point + scaleShowLine : true, + + //Boolean - Whether we show the angle lines out of the radar + angleShowLineOut : true, + + //Boolean - Whether to show labels on the scale + scaleShowLabels : false, + + // Boolean - Whether the scale should begin at zero + scaleBeginAtZero : true, + + //String - Colour of the angle line + angleLineColor : "rgba(0,0,0,.1)", + + //Number - Pixel width of the angle line + angleLineWidth : 1, + + //String - Point label font declaration + pointLabelFontFamily : "'Arial'", + + //String - Point label font weight + pointLabelFontStyle : "normal", + + //Number - Point label font size in pixels + pointLabelFontSize : 10, + + //String - Point label font colour + pointLabelFontColor : "#666", + + //Boolean - Whether to show a dot for each point + pointDot : true, + + //Number - Radius of each point dot in pixels + pointDotRadius : 3, + + //Number - Pixel width of point dot stroke + pointDotStrokeWidth : 1, + + //Number - amount extra to add to the radius to cater for hit detection outside the drawn point + pointHitDetectionRadius : 20, + + //Boolean - Whether to show a stroke for datasets + datasetStroke : true, + + //Number - Pixel width of dataset stroke + datasetStrokeWidth : 2, + + //Boolean - Whether to fill the dataset with a colour + datasetFill : true, + {% raw %} + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
" + {% endraw %} +} +``` + + +You can override these for your `Chart` instance by passing a second argument into the `Radar` method as an object with the keys you want to override. + +For example, we could have a radar chart without a point for each on piece of data by doing the following: + +```javascript +new Chart(ctx).Radar(data, { + pointDot: false +}); +// This will create a chart with all of the default options, merged from the global config, +// and the Bar chart defaults but this particular instance will have `pointDot` set to false. +``` + +We can also change these defaults values for each Radar type that is created, this object is available at `Chart.defaults.Radar`. + + +### Prototype methods + +#### .getPointsAtEvent( event ) + +Calling `getPointsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the point elements that are at that the same position of that event. + +```javascript +canvas.onclick = function(evt){ + var activePoints = myRadarChart.getPointsAtEvent(evt); + // => activePoints is an array of points on the canvas that are at the same position as the click event. +}; +``` + +This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application. + +#### .update( ) + +Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop. + +```javascript +myRadarChart.datasets[0].points[2].value = 50; +// Would update the first dataset's value of 'Sleeping' to be 50 +myRadarChart.update(); +// Calling update now animates the position of Sleeping from 90 to 50. +``` + +#### .addData( valuesArray, label ) + +Calling `addData(valuesArray, label)` on your Chart instance passing an array of values for each dataset, along with a label for those points. + +```javascript +// The values array passed into addData should be one for each dataset in the chart +myRadarChart.addData([40, 60], "Dancing"); +// The new data will now animate at the end of the chart. +``` + +#### .removeData( ) + +Calling `removeData()` on your Chart instance will remove the first value for all datasets on the chart. + +```javascript +myRadarChart.removeData(); +// Other points will now animate to their correct positions. +``` \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/docs/04-Polar-Area-Chart.md b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/04-Polar-Area-Chart.md new file mode 100755 index 0000000..658da54 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/04-Polar-Area-Chart.md @@ -0,0 +1,172 @@ +--- +title: Polar Area Chart +anchor: polar-area-chart +--- +### Introduction +Polar area charts are similar to pie charts, but each segment has the same angle - the radius of the segment differs depending on the value. + +This type of chart is often useful when we want to show a comparison data similar to a pie chart, but also show a scale of values for context. + +
+ +
+ +### Example usage + +```javascript +new Chart(ctx).PolarArea(data, options); +``` + +### Data structure + +```javascript +var data = [ + { + value: 300, + color:"#F7464A", + highlight: "#FF5A5E", + label: "Red" + }, + { + value: 50, + color: "#46BFBD", + highlight: "#5AD3D1", + label: "Green" + }, + { + value: 100, + color: "#FDB45C", + highlight: "#FFC870", + label: "Yellow" + }, + { + value: 40, + color: "#949FB1", + highlight: "#A8B3C5", + label: "Grey" + }, + { + value: 120, + color: "#4D5360", + highlight: "#616774", + label: "Dark Grey" + } + +]; +``` +As you can see, for the chart data you pass in an array of objects, with a value and a colour. The value attribute should be a number, while the color attribute should be a string. Similar to CSS, for this string you can use HEX notation, RGB, RGBA or HSL. + +### Chart options + +These are the customisation options specific to Polar Area charts. These options are merged with the [global chart configuration options](#getting-started-global-chart-configuration), and form the options of the chart. + +```javascript +{ + //Boolean - Show a backdrop to the scale label + scaleShowLabelBackdrop : true, + + //String - The colour of the label backdrop + scaleBackdropColor : "rgba(255,255,255,0.75)", + + // Boolean - Whether the scale should begin at zero + scaleBeginAtZero : true, + + //Number - The backdrop padding above & below the label in pixels + scaleBackdropPaddingY : 2, + + //Number - The backdrop padding to the side of the label in pixels + scaleBackdropPaddingX : 2, + + //Boolean - Show line for each value in the scale + scaleShowLine : true, + + //Boolean - Stroke a line around each segment in the chart + segmentShowStroke : true, + + //String - The colour of the stroke on each segement. + segmentStrokeColor : "#fff", + + //Number - The width of the stroke value in pixels + segmentStrokeWidth : 2, + + //Number - Amount of animation steps + animationSteps : 100, + + //String - Animation easing effect. + animationEasing : "easeOutBounce", + + //Boolean - Whether to animate the rotation of the chart + animateRotate : true, + + //Boolean - Whether to animate scaling the chart from the centre + animateScale : false, + {% raw %} + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(segments[i].label){%><%=segments[i].label%><%}%>
  • <%}%>
" + {% endraw %} +} +``` + +You can override these for your `Chart` instance by passing a second argument into the `PolarArea` method as an object with the keys you want to override. + +For example, we could have a polar area chart with a black stroke on each segment like so: + +```javascript +new Chart(ctx).PolarArea(data, { + segmentStrokeColor: "#000000" +}); +// This will create a chart with all of the default options, merged from the global config, +// and the PolarArea chart defaults but this particular instance will have `segmentStrokeColor` set to `"#000000"`. +``` + +We can also change these defaults values for each PolarArea type that is created, this object is available at `Chart.defaults.PolarArea`. + +### Prototype methods + +#### .getSegmentsAtEvent( event ) + +Calling `getSegmentsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the segment elements that are at that the same position of that event. + +```javascript +canvas.onclick = function(evt){ + var activePoints = myPolarAreaChart.getSegmentsAtEvent(evt); + // => activePoints is an array of segments on the canvas that are at the same position as the click event. +}; +``` + +This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application. + +#### .update( ) + +Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop. + +```javascript +myPolarAreaChart.segments[1].value = 10; +// Would update the first dataset's value of 'Green' to be 10 +myPolarAreaChart.update(); +// Calling update now animates the position of Green from 50 to 10. +``` + +#### .addData( segmentData, index ) + +Calling `addData(segmentData, index)` on your Chart instance passing an object in the same format as in the constructor. There is an option second argument of 'index', this determines at what index the new segment should be inserted into the chart. + +```javascript +// An object in the same format as the original data source +myPolarAreaChart.addData({ + value: 130, + color: "#B48EAD", + highlight: "#C69CBE", + label: "Purple" +}); +// The new segment will now animate in. +``` + +#### .removeData( index ) + +Calling `removeData(index)` on your Chart instance will remove segment at that particular index. If none is provided, it will default to the last segment. + +```javascript +myPolarAreaChart.removeData(); +// Other segments will update to fill the empty space left. +``` \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/docs/05-Pie-Doughnut-Chart.md b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/05-Pie-Doughnut-Chart.md new file mode 100755 index 0000000..9c2b8a7 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/05-Pie-Doughnut-Chart.md @@ -0,0 +1,158 @@ +--- +title: Pie & Doughnut Charts +anchor: doughnut-pie-chart +--- +###Introduction +Pie and doughnut charts are probably the most commonly used chart there are. They are divided into segments, the arc of each segment shows a the proportional value of each piece of data. + +They are excellent at showing the relational proportions between data. + +Pie and doughnut charts in are effectively the same class in Chart.js, but have one different default value - their `percentageInnerCutout`. This equates what percentage of the inner should be cut out. This defaults to `0` for pie charts, and `50` for doughnuts. + +They are also registered under two aliases in the `Chart` core. Other than their different default value, and different alias, they are exactly the same. + +
+ +
+ +
+ +
+ + +### Example usage + +```javascript +// For a pie chart +var myPieChart = new Chart(ctx[0]).Pie(data,options); + +// And for a doughnut chart +var myDoughnutChart = new Chart(ctx[1]).Doughnut(data,options); +``` + +### Data structure + +```javascript +var data = [ + { + value: 300, + color:"#F7464A", + highlight: "#FF5A5E", + label: "Red" + }, + { + value: 50, + color: "#46BFBD", + highlight: "#5AD3D1", + label: "Green" + }, + { + value: 100, + color: "#FDB45C", + highlight: "#FFC870", + label: "Yellow" + } +] +``` + +For a pie chart, you must pass in an array of objects with a value and a color property. The value attribute should be a number, Chart.js will total all of the numbers and calculate the relative proportion of each. The color attribute should be a string. Similar to CSS, for this string you can use HEX notation, RGB, RGBA or HSL. + +### Chart options + +These are the customisation options specific to Pie & Doughnut charts. These options are merged with the [global chart configuration options](#getting-started-global-chart-configuration), and form the options of the chart. + +```javascript +{ + //Boolean - Whether we should show a stroke on each segment + segmentShowStroke : true, + + //String - The colour of each segment stroke + segmentStrokeColor : "#fff", + + //Number - The width of each segment stroke + segmentStrokeWidth : 2, + + //Number - The percentage of the chart that we cut out of the middle + percentageInnerCutout : 50, // This is 0 for Pie charts + + //Number - Amount of animation steps + animationSteps : 100, + + //String - Animation easing effect + animationEasing : "easeOutBounce", + + //Boolean - Whether we animate the rotation of the Doughnut + animateRotate : true, + + //Boolean - Whether we animate scaling the Doughnut from the centre + animateScale : false, + {% raw %} + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(segments[i].label){%><%=segments[i].label%><%}%>
  • <%}%>
" + {% endraw %} +} +``` +You can override these for your `Chart` instance by passing a second argument into the `Doughnut` method as an object with the keys you want to override. + +For example, we could have a doughnut chart that animates by scaling out from the centre like so: + +```javascript +new Chart(ctx).Doughnut(data, { + animateScale: true +}); +// This will create a chart with all of the default options, merged from the global config, +// and the Doughnut chart defaults but this particular instance will have `animateScale` set to `true`. +``` + +We can also change these defaults values for each Doughnut type that is created, this object is available at `Chart.defaults.Doughnut`. Pie charts also have a clone of these defaults available to change at `Chart.defaults.Pie`, with the only difference being `percentageInnerCutout` being set to 0. + +### Prototype methods + +#### .getSegmentsAtEvent( event ) + +Calling `getSegmentsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the segment elements that are at that the same position of that event. + +```javascript +canvas.onclick = function(evt){ + var activePoints = myDoughnutChart.getSegmentsAtEvent(evt); + // => activePoints is an array of segments on the canvas that are at the same position as the click event. +}; +``` + +This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application. + +#### .update( ) + +Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop. + +```javascript +myDoughnutChart.segments[1].value = 10; +// Would update the first dataset's value of 'Green' to be 10 +myDoughnutChart.update(); +// Calling update now animates the circumference of the segment 'Green' from 50 to 10. +// and transitions other segment widths +``` + +#### .addData( segmentData, index ) + +Calling `addData(segmentData, index)` on your Chart instance passing an object in the same format as in the constructor. There is an option second argument of 'index', this determines at what index the new segment should be inserted into the chart. + +```javascript +// An object in the same format as the original data source +myDoughnutChart.addData({ + value: 130, + color: "#B48EAD", + highlight: "#C69CBE", + label: "Purple" +}); +// The new segment will now animate in. +``` + +#### .removeData( index ) + +Calling `removeData(index)` on your Chart instance will remove segment at that particular index. If none is provided, it will default to the last segment. + +```javascript +myDoughnutChart.removeData(); +// Other segments will update to fill the empty space left. +``` \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/docs/06-Advanced.md b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/06-Advanced.md new file mode 100755 index 0000000..f9d696d --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/06-Advanced.md @@ -0,0 +1,151 @@ +--- +title: Advanced usage +anchor: advanced-usage +--- + + +### Prototype methods + +For each chart, there are a set of global prototype methods on the shared `ChartType` which you may find useful. These are available on all charts created with Chart.js, but for the examples, let's use a line chart we've made. + +```javascript +// For example: +var myLineChart = new Chart(ctx).Line(data); +``` + +#### .clear() + +Will clear the chart canvas. Used extensively internally between animation frames, but you might find it useful. + +```javascript +// Will clear the canvas that myLineChart is drawn on +myLineChart.clear(); +// => returns 'this' for chainability +``` + +#### .stop() + +Use this to stop any current animation loop. This will pause the chart during any current animation frame. Call `.render()` to re-animate. + +```javascript +// Stops the charts animation loop at its current frame +myLineChart.stop(); +// => returns 'this' for chainability +``` + +#### .resize() + +Use this to manually resize the canvas element. This is run each time the browser is resized, but you can call this method manually if you change the size of the canvas nodes container element. + +```javascript +// Resizes & redraws to fill its container element +myLineChart.resize(); +// => returns 'this' for chainability +``` + +#### .destroy() + +Use this to destroy any chart instances that are created. This will clean up any references stored to the chart object within Chart.js, along with any associated event listeners attached by Chart.js. + +```javascript +// Destroys a specific chart instance +myLineChart.destroy(); +``` + +#### .toBase64Image() + +This returns a base 64 encoded string of the chart in it's current state. + +```javascript +myLineChart.toBase64Image(); +// => returns png data url of the image on the canvas +``` + +#### .generateLegend() + +Returns an HTML string of a legend for that chart. The template for this legend is at `legendTemplate` in the chart options. + +```javascript +myLineChart.generateLegend(); +// => returns HTML string of a legend for this chart +``` + +### Writing new chart types + +Chart.js 1.0 has been rewritten to provide a platform for developers to create their own custom chart types, and be able to share and utilise them through the Chart.js API. + +The format is relatively simple, there are a set of utility helper methods under `Chart.helpers`, including things such as looping over collections, requesting animation frames, and easing equations. + +On top of this, there are also some simple base classes of Chart elements, these all extend from `Chart.Element`, and include things such as points, bars and scales. + +```javascript +Chart.Type.extend({ + // Passing in a name registers this chart in the Chart namespace + name: "Scatter", + // Providing a defaults will also register the deafults in the chart namespace + defaults : { + options: "Here", + available: "at this.options" + }, + // Initialize is fired when the chart is initialized - Data is passed in as a parameter + // Config is automatically merged by the core of Chart.js, and is available at this.options + initialize: function(data){ + this.chart.ctx // The drawing context for this chart + this.chart.canvas // the canvas node for this chart + }, + // Used to draw something on the canvas + draw: function() { + } +}); + +// Now we can create a new instance of our chart, using the Chart.js API +new Chart(ctx).Scatter(data); +// initialize is now run +``` + +### Extending existing chart types + +We can also extend existing chart types, and expose them to the API in the same way. Let's say for example, we might want to run some more code when we initialize every Line chart. + +```javascript +// Notice now we're extending the particular Line chart type, rather than the base class. +Chart.types.Line.extend({ + // Passing in a name registers this chart in the Chart namespace in the same way + name: "LineAlt", + initialize: function(data){ + console.log('My Line chart extension'); + Chart.types.Line.prototype.initialize.apply(this, arguments); + } +}); + +// Creates a line chart in the same way +new Chart(ctx).LineAlt(data); +// but this logs 'My Line chart extension' in the console. +``` + +### Community extensions + +- Stacked Bar Chart by @Regaddi + +### Creating custom builds + +Chart.js uses gulp to build the library into a single JavaScript file. We can use this same build script with custom parameters in order to build a custom version. + +Firstly, we need to ensure development dependencies are installed. With node and npm installed, after cloning the Chart.js repo to a local directory, and navigating to that directory in the command line, we can run the following: + +```bash +npm install +npm install -g gulp +``` + +This will install the local development dependencies for Chart.js, along with a CLI for the JavaScript task runner gulp. + +Now, we can run the `gulp build` task, and pass in a comma seperated list of types as an argument to build a custom version of Chart.js with only specified chart types. + +Here we will create a version of Chart.js with only Line, Radar and Bar charts included: + +```bash +gulp build --types=Line,Radar,Bar +``` + +This will output to the `/custom` directory, and write two files, Chart.js, and Chart.min.js with only those chart types included. diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/docs/07-Notes.md b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/07-Notes.md new file mode 100755 index 0000000..8ba5a59 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/docs/07-Notes.md @@ -0,0 +1,42 @@ +--- +title: Notes +anchor: notes +--- + +### Browser support +Browser support for the canvas element is available in all modern & major mobile browsers (caniuse.com/canvas). + +For IE8 & below, I would recommend using the polyfill ExplorerCanvas - available at https://code.google.com/p/explorercanvas/. It falls back to Internet explorer's format VML when canvas support is not available. Example use: + +```html + + + +``` + +Usually I would recommend feature detection to choose whether or not to load a polyfill, rather than IE conditional comments, however in this case, VML is a Microsoft proprietary format, so it will only work in IE. + +Some important points to note in my experience using ExplorerCanvas as a fallback. + +- Initialise charts on load rather than DOMContentReady when using the library, as sometimes a race condition will occur, and it will result in an error when trying to get the 2d context of a canvas. +- New VML DOM elements are being created for each animation frame and there is no hardware acceleration. As a result animation is usually slow and jerky, with flashing text. It is a good idea to dynamically turn off animation based on canvas support. I recommend using the excellent Modernizr to do this. +- When declaring fonts, the library explorercanvas requires the font name to be in single quotes inside the string. For example, instead of your scaleFontFamily property being simply "Arial", explorercanvas support, use "'Arial'" instead. Chart.js does this for default values. + +### Bugs & issues + +Please report these on the GitHub page - at github.com/nnnick/Chart.js. If you could include a link to a simple jsbin or similar to demonstrate the issue, that'd be really helpful. + + +### Contributing +New contributions to the library are welcome, just a couple of guidelines: + +- Tabs for indentation, not spaces please. +- Please ensure you're changing the individual files in `/src`, not the concatenated output in the `Chart.js` file in the root of the repo. +- Please check that your code will pass `jshint` code standards, `gulp jshint` will run this for you. +- Please keep pull requests concise, and document new functionality in the relevant `.md` file. +- Consider whether your changes are useful for all users, or if creating a Chart.js extension would be more appropriate. + +### License +Chart.js is open source and available under the MIT license. \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/gulpfile.js b/gridplatform/bootstrap/static/bootstrap/chart.js/gulpfile.js new file mode 100755 index 0000000..4a435bd --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/gulpfile.js @@ -0,0 +1,131 @@ +var gulp = require('gulp'), + concat = require('gulp-concat'), + uglify = require('gulp-uglify'), + util = require('gulp-util'), + jshint = require('gulp-jshint'), + size = require('gulp-size'), + connect = require('gulp-connect'), + replace = require('gulp-replace'), + inquirer = require('inquirer'), + semver = require('semver'), + exec = require('child_process').exec, + fs = require('fs'), + package = require('./package.json'), + bower = require('./bower.json'); + +var srcDir = './src/'; +/* + * Usage : gulp build --types=Bar,Line,Doughnut + * Output: - A built Chart.js file with Core and types Bar, Line and Doughnut concatenated together + * - A minified version of this code, in Chart.min.js + */ + +gulp.task('build', function(){ + + // Default to all of the chart types, with Chart.Core first + var srcFiles = [FileName('Core')], + isCustom = !!(util.env.types), + outputDir = (isCustom) ? 'custom' : '.'; + if (isCustom){ + util.env.types.split(',').forEach(function(type){ return srcFiles.push(FileName(type))}); + } + else{ + // Seems gulp-concat remove duplicates - nice! + // So we can use this to sort out dependency order - aka include Core first! + srcFiles.push(srcDir+'*'); + } + + return gulp.src(srcFiles) + .pipe(concat('Chart.js')) + .pipe(replace('{{ version }}', package.version)) + .pipe(gulp.dest(outputDir)) + .pipe(uglify({preserveComments:'some'})) + .pipe(concat('Chart.min.js')) + .pipe(gulp.dest(outputDir)); + + function FileName(moduleName){ + return srcDir+'Chart.'+moduleName+'.js'; + }; +}); + +/* + * Usage : gulp bump + * Prompts: Version increment to bump + * Output: - New version number written into package.json & bower.json + */ + +gulp.task('bump', function(complete){ + util.log('Current version:', util.colors.cyan(package.version)); + var choices = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'].map(function(versionType){ + return versionType + ' (v' + semver.inc(package.version, versionType) + ')'; + }); + inquirer.prompt({ + type: 'list', + name: 'version', + message: 'What version update would you like?', + choices: choices + }, function(res){ + var increment = res.version.split(' ')[0], + newVersion = semver.inc(package.version, increment); + + // Set the new versions into the bower/package object + package.version = newVersion; + bower.version = newVersion; + + // Write these to their own files, then build the output + fs.writeFileSync('package.json', JSON.stringify(package, null, 2)); + fs.writeFileSync('bower.json', JSON.stringify(bower, null, 2)); + + complete(); + }); +}); + +gulp.task('release', ['build'], function(){ + exec('git tag -a v' + package.version); +}); + +gulp.task('jshint', function(){ + return gulp.src(srcDir + '*.js') + .pipe(jshint()) + .pipe(jshint.reporter('default')); +}); + +gulp.task('library-size', function(){ + return gulp.src('Chart.min.js') + .pipe(size({ + gzip: true + })); +}); + +gulp.task('module-sizes', function(){ + return gulp.src(srcDir + '*.js') + .pipe(uglify({preserveComments:'some'})) + .pipe(size({ + showFiles: true, + gzip: true + })) +}); + +gulp.task('watch', function(){ + gulp.watch('./src/*', ['build']); +}); + +gulp.task('test', ['jshint']); + +gulp.task('size', ['library-size', 'module-sizes']); + +gulp.task('default', ['build', 'watch']); + +gulp.task('server', function(){ + connect.server({ + port: 8000, + }); +}); + +// Convenience task for opening the project straight from the command line +gulp.task('_open', function(){ + exec('open http://localhost:8000'); + exec('subl .'); +}); + +gulp.task('dev', ['server', 'default']); diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/package.json b/gridplatform/bootstrap/static/bootstrap/chart.js/package.json new file mode 100755 index 0000000..2e07575 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/package.json @@ -0,0 +1,24 @@ +{ + "name": "chart.js", + "homepage": "http://www.chartjs.org", + "description": "Simple HTML5 charts using the canvas element.", + "version": "1.0.1-beta.4", + "main": "Chart.js", + "repository": { + "type": "git", + "url": "https://github.com/nnnick/Chart.js.git" + }, + "dependences": {}, + "devDependencies": { + "gulp": "3.5.x", + "gulp-concat": "~2.1.x", + "gulp-connect": "~2.0.5", + "gulp-jshint": "~1.5.1", + "gulp-replace": "^0.4.0", + "gulp-size": "~0.4.0", + "gulp-uglify": "~0.2.x", + "gulp-util": "~2.2.x", + "inquirer": "^0.5.1", + "semver": "^3.0.1" + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/samples/bar.html b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/bar.html new file mode 100755 index 0000000..5bf4b5b --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/bar.html @@ -0,0 +1,45 @@ + + + + Bar Chart + + + +
+ +
+ + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/samples/doughnut.html b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/doughnut.html new file mode 100755 index 0000000..fdf7539 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/doughnut.html @@ -0,0 +1,67 @@ + + + + Doughnut Chart + + + + +
+ +
+ + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/samples/line.html b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/line.html new file mode 100755 index 0000000..ccd0dad --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/line.html @@ -0,0 +1,54 @@ + + + + Line Chart + + + +
+
+ +
+
+ + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/samples/pie.html b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/pie.html new file mode 100755 index 0000000..255a499 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/pie.html @@ -0,0 +1,58 @@ + + + + Pie Chart + + + +
+ +
+ + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/samples/polar-area.html b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/polar-area.html new file mode 100755 index 0000000..d3d3f01 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/polar-area.html @@ -0,0 +1,60 @@ + + + + Polar Area Chart + + + +
+ +
+ + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/samples/radar.html b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/radar.html new file mode 100755 index 0000000..6a04f87 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/samples/radar.html @@ -0,0 +1,53 @@ + + + + Radar Chart + + + + + +
+ +
+ + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Bar.js b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Bar.js new file mode 100755 index 0000000..fafe74a --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Bar.js @@ -0,0 +1,294 @@ +(function(){ + "use strict"; + + var root = this, + Chart = root.Chart, + helpers = Chart.helpers; + + + var defaultConfig = { + //Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value + scaleBeginAtZero : true, + + //Boolean - Whether grid lines are shown across the chart + scaleShowGridLines : true, + + //String - Colour of the grid lines + scaleGridLineColor : "rgba(0,0,0,.05)", + + //Number - Width of the grid lines + scaleGridLineWidth : 1, + + //Boolean - If there is a stroke on each bar + barShowStroke : true, + + //Number - Pixel width of the bar stroke + barStrokeWidth : 2, + + //Number - Spacing between each of the X value sets + barValueSpacing : 5, + + //Number - Spacing between data sets within X values + barDatasetSpacing : 1, + + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
" + + }; + + + Chart.Type.extend({ + name: "Bar", + defaults : defaultConfig, + initialize: function(data){ + + //Expose options as a scope variable here so we can access it in the ScaleClass + var options = this.options; + + this.ScaleClass = Chart.Scale.extend({ + offsetGridLines : true, + calculateBarX : function(datasetCount, datasetIndex, barIndex){ + //Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar + var xWidth = this.calculateBaseWidth(), + xAbsolute = this.calculateX(barIndex) - (xWidth/2), + barWidth = this.calculateBarWidth(datasetCount); + + return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2; + }, + calculateBaseWidth : function(){ + return (this.calculateX(1) - this.calculateX(0)) - (2*options.barValueSpacing); + }, + calculateBarWidth : function(datasetCount){ + //The padding between datasets is to the right of each bar, providing that there are more than 1 dataset + var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing); + + return (baseWidth / datasetCount); + } + }); + + this.datasets = []; + + //Set up tooltip events on the chart + if (this.options.showTooltips){ + helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ + var activeBars = (evt.type !== 'mouseout') ? this.getBarsAtEvent(evt) : []; + + this.eachBars(function(bar){ + bar.restore(['fillColor', 'strokeColor']); + }); + helpers.each(activeBars, function(activeBar){ + activeBar.fillColor = activeBar.highlightFill; + activeBar.strokeColor = activeBar.highlightStroke; + }); + this.showTooltip(activeBars); + }); + } + + //Declare the extension of the default point, to cater for the options passed in to the constructor + this.BarClass = Chart.Rectangle.extend({ + strokeWidth : this.options.barStrokeWidth, + showStroke : this.options.barShowStroke, + ctx : this.chart.ctx + }); + + //Iterate through each of the datasets, and build this into a property of the chart + helpers.each(data.datasets,function(dataset,datasetIndex){ + + var datasetObject = { + label : dataset.label || null, + fillColor : dataset.fillColor, + strokeColor : dataset.strokeColor, + bars : [] + }; + + this.datasets.push(datasetObject); + + helpers.each(dataset.data,function(dataPoint,index){ + //Add a new point for each piece of data, passing any required data to draw. + datasetObject.bars.push(new this.BarClass({ + value : dataPoint, + label : data.labels[index], + datasetLabel: dataset.label, + strokeColor : dataset.strokeColor, + fillColor : dataset.fillColor, + highlightFill : dataset.highlightFill || dataset.fillColor, + highlightStroke : dataset.highlightStroke || dataset.strokeColor + })); + },this); + + },this); + + this.buildScale(data.labels); + + this.BarClass.prototype.base = this.scale.endPoint; + + this.eachBars(function(bar, index, datasetIndex){ + helpers.extend(bar, { + width : this.scale.calculateBarWidth(this.datasets.length), + x: this.scale.calculateBarX(this.datasets.length, datasetIndex, index), + y: this.scale.endPoint + }); + bar.save(); + }, this); + + this.render(); + }, + update : function(){ + this.scale.update(); + // Reset any highlight colours before updating. + helpers.each(this.activeElements, function(activeElement){ + activeElement.restore(['fillColor', 'strokeColor']); + }); + + this.eachBars(function(bar){ + bar.save(); + }); + this.render(); + }, + eachBars : function(callback){ + helpers.each(this.datasets,function(dataset, datasetIndex){ + helpers.each(dataset.bars, callback, this, datasetIndex); + },this); + }, + getBarsAtEvent : function(e){ + var barsArray = [], + eventPosition = helpers.getRelativePosition(e), + datasetIterator = function(dataset){ + barsArray.push(dataset.bars[barIndex]); + }, + barIndex; + + for (var datasetIndex = 0; datasetIndex < this.datasets.length; datasetIndex++) { + for (barIndex = 0; barIndex < this.datasets[datasetIndex].bars.length; barIndex++) { + if (this.datasets[datasetIndex].bars[barIndex].inRange(eventPosition.x,eventPosition.y)){ + helpers.each(this.datasets, datasetIterator); + return barsArray; + } + } + } + + return barsArray; + }, + buildScale : function(labels){ + var self = this; + + var dataTotal = function(){ + var values = []; + self.eachBars(function(bar){ + values.push(bar.value); + }); + return values; + }; + + var scaleOptions = { + templateString : this.options.scaleLabel, + height : this.chart.height, + width : this.chart.width, + ctx : this.chart.ctx, + textColor : this.options.scaleFontColor, + fontSize : this.options.scaleFontSize, + fontStyle : this.options.scaleFontStyle, + fontFamily : this.options.scaleFontFamily, + valuesCount : labels.length, + beginAtZero : this.options.scaleBeginAtZero, + integersOnly : this.options.scaleIntegersOnly, + calculateYRange: function(currentHeight){ + var updatedRanges = helpers.calculateScaleRange( + dataTotal(), + currentHeight, + this.fontSize, + this.beginAtZero, + this.integersOnly + ); + helpers.extend(this, updatedRanges); + }, + xLabels : labels, + font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily), + lineWidth : this.options.scaleLineWidth, + lineColor : this.options.scaleLineColor, + gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0, + gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)", + padding : (this.options.showScale) ? 0 : (this.options.barShowStroke) ? this.options.barStrokeWidth : 0, + showLabels : this.options.scaleShowLabels, + display : this.options.showScale + }; + + if (this.options.scaleOverride){ + helpers.extend(scaleOptions, { + calculateYRange: helpers.noop, + steps: this.options.scaleSteps, + stepValue: this.options.scaleStepWidth, + min: this.options.scaleStartValue, + max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth) + }); + } + + this.scale = new this.ScaleClass(scaleOptions); + }, + addData : function(valuesArray,label){ + //Map the values array for each of the datasets + helpers.each(valuesArray,function(value,datasetIndex){ + //Add a new point for each piece of data, passing any required data to draw. + this.datasets[datasetIndex].bars.push(new this.BarClass({ + value : value, + label : label, + x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1), + y: this.scale.endPoint, + width : this.scale.calculateBarWidth(this.datasets.length), + base : this.scale.endPoint, + strokeColor : this.datasets[datasetIndex].strokeColor, + fillColor : this.datasets[datasetIndex].fillColor + })); + },this); + + this.scale.addXLabel(label); + //Then re-render the chart. + this.update(); + }, + removeData : function(){ + this.scale.removeXLabel(); + //Then re-render the chart. + helpers.each(this.datasets,function(dataset){ + dataset.bars.shift(); + },this); + this.update(); + }, + reflow : function(){ + helpers.extend(this.BarClass.prototype,{ + y: this.scale.endPoint, + base : this.scale.endPoint + }); + var newScaleProps = helpers.extend({ + height : this.chart.height, + width : this.chart.width + }); + this.scale.update(newScaleProps); + }, + draw : function(ease){ + var easingDecimal = ease || 1; + this.clear(); + + var ctx = this.chart.ctx; + + this.scale.draw(easingDecimal); + + //Draw all the bars for each dataset + helpers.each(this.datasets,function(dataset,datasetIndex){ + helpers.each(dataset.bars,function(bar,index){ + if (bar.hasValue()){ + bar.base = this.scale.endPoint; + //Transition then draw + bar.transition({ + x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index), + y : this.scale.calculateY(bar.value), + width : this.scale.calculateBarWidth(this.datasets.length) + }, easingDecimal).draw(); + } + },this); + + },this); + } + }); + + +}).call(this); \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Core.js b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Core.js new file mode 100755 index 0000000..0bfb4c0 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Core.js @@ -0,0 +1,1943 @@ +/*! + * Chart.js + * http://chartjs.org/ + * Version: {{ version }} + * + * Copyright 2014 Nick Downie + * Released under the MIT license + * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md + */ + + +(function(){ + + "use strict"; + + //Declare root variable - window in the browser, global on the server + var root = this, + previous = root.Chart; + + //Occupy the global variable of Chart, and create a simple base class + var Chart = function(context){ + var chart = this; + this.canvas = context.canvas; + + this.ctx = context; + + //Variables global to the chart + var width = this.width = context.canvas.width; + var height = this.height = context.canvas.height; + this.aspectRatio = this.width / this.height; + //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale. + helpers.retinaScale(this); + + return this; + }; + //Globally expose the defaults to allow for user updating/changing + Chart.defaults = { + global: { + // Boolean - Whether to animate the chart + animation: true, + + // Number - Number of animation steps + animationSteps: 60, + + // String - Animation easing effect + animationEasing: "easeOutQuart", + + // Boolean - If we should show the scale at all + showScale: true, + + // Boolean - If we want to override with a hard coded scale + scaleOverride: false, + + // ** Required if scaleOverride is true ** + // Number - The number of steps in a hard coded scale + scaleSteps: null, + // Number - The value jump in the hard coded scale + scaleStepWidth: null, + // Number - The scale starting value + scaleStartValue: null, + + // String - Colour of the scale line + scaleLineColor: "rgba(0,0,0,.1)", + + // Number - Pixel width of the scale line + scaleLineWidth: 1, + + // Boolean - Whether to show labels on the scale + scaleShowLabels: true, + + // Interpolated JS string - can access value + scaleLabel: "<%=value%>", + + // Boolean - Whether the scale should stick to integers, and not show any floats even if drawing space is there + scaleIntegersOnly: true, + + // Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value + scaleBeginAtZero: false, + + // String - Scale label font declaration for the scale label + scaleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + + // Number - Scale label font size in pixels + scaleFontSize: 12, + + // String - Scale label font weight style + scaleFontStyle: "normal", + + // String - Scale label font colour + scaleFontColor: "#666", + + // Boolean - whether or not the chart should be responsive and resize when the browser does. + responsive: false, + + // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container + maintainAspectRatio: true, + + // Boolean - Determines whether to draw tooltips on the canvas or not - attaches events to touchmove & mousemove + showTooltips: true, + + // Array - Array of string names to attach tooltip events + tooltipEvents: ["mousemove", "touchstart", "touchmove", "mouseout"], + + // String - Tooltip background colour + tooltipFillColor: "rgba(0,0,0,0.8)", + + // String - Tooltip label font declaration for the scale label + tooltipFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + + // Number - Tooltip label font size in pixels + tooltipFontSize: 14, + + // String - Tooltip font weight style + tooltipFontStyle: "normal", + + // String - Tooltip label font colour + tooltipFontColor: "#fff", + + // String - Tooltip title font declaration for the scale label + tooltipTitleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + + // Number - Tooltip title font size in pixels + tooltipTitleFontSize: 14, + + // String - Tooltip title font weight style + tooltipTitleFontStyle: "bold", + + // String - Tooltip title font colour + tooltipTitleFontColor: "#fff", + + // Number - pixel width of padding around tooltip text + tooltipYPadding: 6, + + // Number - pixel width of padding around tooltip text + tooltipXPadding: 6, + + // Number - Size of the caret on the tooltip + tooltipCaretSize: 8, + + // Number - Pixel radius of the tooltip border + tooltipCornerRadius: 6, + + // Number - Pixel offset from point x to tooltip edge + tooltipXOffset: 10, + + // String - Template string for single tooltips + tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= value %>", + + // String - Template string for single tooltips + multiTooltipTemplate: "<%= value %>", + + // String - Colour behind the legend colour block + multiTooltipKeyBackground: '#fff', + + // Function - Will fire on animation progression. + onAnimationProgress: function(){}, + + // Function - Will fire on animation completion. + onAnimationComplete: function(){} + + } + }; + + //Create a dictionary of chart types, to allow for extension of existing types + Chart.types = {}; + + //Global Chart helpers object for utility methods and classes + var helpers = Chart.helpers = {}; + + //-- Basic js utility methods + var each = helpers.each = function(loopable,callback,self){ + var additionalArgs = Array.prototype.slice.call(arguments, 3); + // Check to see if null or undefined firstly. + if (loopable){ + if (loopable.length === +loopable.length){ + var i; + for (i=0; i= 0; i--) { + var currentItem = arrayToSearch[i]; + if (filterCallback(currentItem)){ + return currentItem; + } + }; + }, + inherits = helpers.inherits = function(extensions){ + //Basic javascript inheritance based on the model created in Backbone.js + var parent = this; + var ChartElement = (extensions && extensions.hasOwnProperty("constructor")) ? extensions.constructor : function(){ return parent.apply(this, arguments); }; + + var Surrogate = function(){ this.constructor = ChartElement;}; + Surrogate.prototype = parent.prototype; + ChartElement.prototype = new Surrogate(); + + ChartElement.extend = inherits; + + if (extensions) extend(ChartElement.prototype, extensions); + + ChartElement.__super__ = parent.prototype; + + return ChartElement; + }, + noop = helpers.noop = function(){}, + uid = helpers.uid = (function(){ + var id=0; + return function(){ + return "chart-" + id++; + }; + })(), + warn = helpers.warn = function(str){ + //Method for warning of errors + if (window.console && typeof window.console.warn == "function") console.warn(str); + }, + amd = helpers.amd = (typeof root.define == 'function' && root.define.amd), + //-- Math methods + isNumber = helpers.isNumber = function(n){ + return !isNaN(parseFloat(n)) && isFinite(n); + }, + max = helpers.max = function(array){ + return Math.max.apply( Math, array ); + }, + min = helpers.min = function(array){ + return Math.min.apply( Math, array ); + }, + cap = helpers.cap = function(valueToCap,maxValue,minValue){ + if(isNumber(maxValue)) { + if( valueToCap > maxValue ) { + return maxValue; + } + } + else if(isNumber(minValue)){ + if ( valueToCap < minValue ){ + return minValue; + } + } + return valueToCap; + }, + getDecimalPlaces = helpers.getDecimalPlaces = function(num){ + if (num%1!==0 && isNumber(num)){ + return num.toString().split(".")[1].length; + } + else { + return 0; + } + }, + toRadians = helpers.radians = function(degrees){ + return degrees * (Math.PI/180); + }, + // Gets the angle from vertical upright to the point about a centre. + getAngleFromPoint = helpers.getAngleFromPoint = function(centrePoint, anglePoint){ + var distanceFromXCenter = anglePoint.x - centrePoint.x, + distanceFromYCenter = anglePoint.y - centrePoint.y, + radialDistanceFromCenter = Math.sqrt( distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); + + + var angle = Math.PI * 2 + Math.atan2(distanceFromYCenter, distanceFromXCenter); + + //If the segment is in the top left quadrant, we need to add another rotation to the angle + if (distanceFromXCenter < 0 && distanceFromYCenter < 0){ + angle += Math.PI*2; + } + + return { + angle: angle, + distance: radialDistanceFromCenter + }; + }, + aliasPixel = helpers.aliasPixel = function(pixelWidth){ + return (pixelWidth % 2 === 0) ? 0 : 0.5; + }, + splineCurve = helpers.splineCurve = function(FirstPoint,MiddlePoint,AfterPoint,t){ + //Props to Rob Spencer at scaled innovation for his post on splining between points + //http://scaledinnovation.com/analytics/splines/aboutSplines.html + var d01=Math.sqrt(Math.pow(MiddlePoint.x-FirstPoint.x,2)+Math.pow(MiddlePoint.y-FirstPoint.y,2)), + d12=Math.sqrt(Math.pow(AfterPoint.x-MiddlePoint.x,2)+Math.pow(AfterPoint.y-MiddlePoint.y,2)), + fa=t*d01/(d01+d12),// scaling factor for triangle Ta + fb=t*d12/(d01+d12); + return { + inner : { + x : MiddlePoint.x-fa*(AfterPoint.x-FirstPoint.x), + y : MiddlePoint.y-fa*(AfterPoint.y-FirstPoint.y) + }, + outer : { + x: MiddlePoint.x+fb*(AfterPoint.x-FirstPoint.x), + y : MiddlePoint.y+fb*(AfterPoint.y-FirstPoint.y) + } + }; + }, + calculateOrderOfMagnitude = helpers.calculateOrderOfMagnitude = function(val){ + return Math.floor(Math.log(val) / Math.LN10); + }, + calculateScaleRange = helpers.calculateScaleRange = function(valuesArray, drawingSize, textSize, startFromZero, integersOnly){ + + //Set a minimum step of two - a point at the top of the graph, and a point at the base + var minSteps = 2, + maxSteps = Math.floor(drawingSize/(textSize * 1.5)), + skipFitting = (minSteps >= maxSteps); + + var maxValue = max(valuesArray), + minValue = min(valuesArray); + + // We need some degree of seperation here to calculate the scales if all the values are the same + // Adding/minusing 0.5 will give us a range of 1. + if (maxValue === minValue){ + maxValue += 0.5; + // So we don't end up with a graph with a negative start value if we've said always start from zero + if (minValue >= 0.5 && !startFromZero){ + minValue -= 0.5; + } + else{ + // Make up a whole number above the values + maxValue += 0.5; + } + } + + var valueRange = Math.abs(maxValue - minValue), + rangeOrderOfMagnitude = calculateOrderOfMagnitude(valueRange), + graphMax = Math.ceil(maxValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude), + graphMin = (startFromZero) ? 0 : Math.floor(minValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude), + graphRange = graphMax - graphMin, + stepValue = Math.pow(10, rangeOrderOfMagnitude), + numberOfSteps = Math.round(graphRange / stepValue); + + //If we have more space on the graph we'll use it to give more definition to the data + while((numberOfSteps > maxSteps || (numberOfSteps * 2) < maxSteps) && !skipFitting) { + if(numberOfSteps > maxSteps){ + stepValue *=2; + numberOfSteps = Math.round(graphRange/stepValue); + // Don't ever deal with a decimal number of steps - cancel fitting and just use the minimum number of steps. + if (numberOfSteps % 1 !== 0){ + skipFitting = true; + } + } + //We can fit in double the amount of scale points on the scale + else{ + //If user has declared ints only, and the step value isn't a decimal + if (integersOnly && rangeOrderOfMagnitude >= 0){ + //If the user has said integers only, we need to check that making the scale more granular wouldn't make it a float + if(stepValue/2 % 1 === 0){ + stepValue /=2; + numberOfSteps = Math.round(graphRange/stepValue); + } + //If it would make it a float break out of the loop + else{ + break; + } + } + //If the scale doesn't have to be an int, make the scale more granular anyway. + else{ + stepValue /=2; + numberOfSteps = Math.round(graphRange/stepValue); + } + + } + } + + if (skipFitting){ + numberOfSteps = minSteps; + stepValue = graphRange / numberOfSteps; + } + + return { + steps : numberOfSteps, + stepValue : stepValue, + min : graphMin, + max : graphMin + (numberOfSteps * stepValue) + }; + + }, + /* jshint ignore:start */ + // Blows up jshint errors based on the new Function constructor + //Templating methods + //Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/ + template = helpers.template = function(templateString, valuesObject){ + // If templateString is function rather than string-template - call the function for valuesObject + if(templateString instanceof Function){ + return templateString(valuesObject); + } + + var cache = {}; + function tmpl(str, data){ + // Figure out if we're getting a template, or if we need to + // load the template - and be sure to cache the result. + var fn = !/\W/.test(str) ? + cache[str] = cache[str] : + + // Generate a reusable function that will serve as a template + // generator (and which will be cached). + new Function("obj", + "var p=[],print=function(){p.push.apply(p,arguments);};" + + + // Introduce the data as local variables using with(){} + "with(obj){p.push('" + + + // Convert the template into pure JavaScript + str + .replace(/[\r\t\n]/g, " ") + .split("<%").join("\t") + .replace(/((^|%>)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + + "');}return p.join('');" + ); + + // Provide some basic currying to the user + return data ? fn( data ) : fn; + } + return tmpl(templateString,valuesObject); + }, + /* jshint ignore:end */ + generateLabels = helpers.generateLabels = function(templateString,numberOfSteps,graphMin,stepValue){ + var labelsArray = new Array(numberOfSteps); + if (labelTemplateString){ + each(labelsArray,function(val,index){ + labelsArray[index] = template(templateString,{value: (graphMin + (stepValue*(index+1)))}); + }); + } + return labelsArray; + }, + //--Animation methods + //Easing functions adapted from Robert Penner's easing equations + //http://www.robertpenner.com/easing/ + easingEffects = helpers.easingEffects = { + linear: function (t) { + return t; + }, + easeInQuad: function (t) { + return t * t; + }, + easeOutQuad: function (t) { + return -1 * t * (t - 2); + }, + easeInOutQuad: function (t) { + if ((t /= 1 / 2) < 1) return 1 / 2 * t * t; + return -1 / 2 * ((--t) * (t - 2) - 1); + }, + easeInCubic: function (t) { + return t * t * t; + }, + easeOutCubic: function (t) { + return 1 * ((t = t / 1 - 1) * t * t + 1); + }, + easeInOutCubic: function (t) { + if ((t /= 1 / 2) < 1) return 1 / 2 * t * t * t; + return 1 / 2 * ((t -= 2) * t * t + 2); + }, + easeInQuart: function (t) { + return t * t * t * t; + }, + easeOutQuart: function (t) { + return -1 * ((t = t / 1 - 1) * t * t * t - 1); + }, + easeInOutQuart: function (t) { + if ((t /= 1 / 2) < 1) return 1 / 2 * t * t * t * t; + return -1 / 2 * ((t -= 2) * t * t * t - 2); + }, + easeInQuint: function (t) { + return 1 * (t /= 1) * t * t * t * t; + }, + easeOutQuint: function (t) { + return 1 * ((t = t / 1 - 1) * t * t * t * t + 1); + }, + easeInOutQuint: function (t) { + if ((t /= 1 / 2) < 1) return 1 / 2 * t * t * t * t * t; + return 1 / 2 * ((t -= 2) * t * t * t * t + 2); + }, + easeInSine: function (t) { + return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1; + }, + easeOutSine: function (t) { + return 1 * Math.sin(t / 1 * (Math.PI / 2)); + }, + easeInOutSine: function (t) { + return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1); + }, + easeInExpo: function (t) { + return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1)); + }, + easeOutExpo: function (t) { + return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1); + }, + easeInOutExpo: function (t) { + if (t === 0) return 0; + if (t === 1) return 1; + if ((t /= 1 / 2) < 1) return 1 / 2 * Math.pow(2, 10 * (t - 1)); + return 1 / 2 * (-Math.pow(2, -10 * --t) + 2); + }, + easeInCirc: function (t) { + if (t >= 1) return t; + return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1); + }, + easeOutCirc: function (t) { + return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t); + }, + easeInOutCirc: function (t) { + if ((t /= 1 / 2) < 1) return -1 / 2 * (Math.sqrt(1 - t * t) - 1); + return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1); + }, + easeInElastic: function (t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) return 0; + if ((t /= 1) == 1) return 1; + if (!p) p = 1 * 0.3; + if (a < Math.abs(1)) { + a = 1; + s = p / 4; + } else s = p / (2 * Math.PI) * Math.asin(1 / a); + return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)); + }, + easeOutElastic: function (t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) return 0; + if ((t /= 1) == 1) return 1; + if (!p) p = 1 * 0.3; + if (a < Math.abs(1)) { + a = 1; + s = p / 4; + } else s = p / (2 * Math.PI) * Math.asin(1 / a); + return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1; + }, + easeInOutElastic: function (t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) return 0; + if ((t /= 1 / 2) == 2) return 1; + if (!p) p = 1 * (0.3 * 1.5); + if (a < Math.abs(1)) { + a = 1; + s = p / 4; + } else s = p / (2 * Math.PI) * Math.asin(1 / a); + if (t < 1) return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)); + return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1; + }, + easeInBack: function (t) { + var s = 1.70158; + return 1 * (t /= 1) * t * ((s + 1) * t - s); + }, + easeOutBack: function (t) { + var s = 1.70158; + return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1); + }, + easeInOutBack: function (t) { + var s = 1.70158; + if ((t /= 1 / 2) < 1) return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)); + return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); + }, + easeInBounce: function (t) { + return 1 - easingEffects.easeOutBounce(1 - t); + }, + easeOutBounce: function (t) { + if ((t /= 1) < (1 / 2.75)) { + return 1 * (7.5625 * t * t); + } else if (t < (2 / 2.75)) { + return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75); + } else if (t < (2.5 / 2.75)) { + return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375); + } else { + return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375); + } + }, + easeInOutBounce: function (t) { + if (t < 1 / 2) return easingEffects.easeInBounce(t * 2) * 0.5; + return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5; + } + }, + //Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ + requestAnimFrame = helpers.requestAnimFrame = (function(){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback) { + return window.setTimeout(callback, 1000 / 60); + }; + })(), + cancelAnimFrame = helpers.cancelAnimFrame = (function(){ + return window.cancelAnimationFrame || + window.webkitCancelAnimationFrame || + window.mozCancelAnimationFrame || + window.oCancelAnimationFrame || + window.msCancelAnimationFrame || + function(callback) { + return window.clearTimeout(callback, 1000 / 60); + }; + })(), + animationLoop = helpers.animationLoop = function(callback,totalSteps,easingString,onProgress,onComplete,chartInstance){ + + var currentStep = 0, + easingFunction = easingEffects[easingString] || easingEffects.linear; + + var animationFrame = function(){ + currentStep++; + var stepDecimal = currentStep/totalSteps; + var easeDecimal = easingFunction(stepDecimal); + + callback.call(chartInstance,easeDecimal,stepDecimal, currentStep); + onProgress.call(chartInstance,easeDecimal,stepDecimal); + if (currentStep < totalSteps){ + chartInstance.animationFrame = requestAnimFrame(animationFrame); + } else{ + onComplete.apply(chartInstance); + } + }; + requestAnimFrame(animationFrame); + }, + //-- DOM methods + getRelativePosition = helpers.getRelativePosition = function(evt){ + var mouseX, mouseY; + var e = evt.originalEvent || evt, + canvas = evt.currentTarget || evt.srcElement, + boundingRect = canvas.getBoundingClientRect(); + + if (e.touches){ + mouseX = e.touches[0].clientX - boundingRect.left; + mouseY = e.touches[0].clientY - boundingRect.top; + + } + else{ + mouseX = e.clientX - boundingRect.left; + mouseY = e.clientY - boundingRect.top; + } + + return { + x : mouseX, + y : mouseY + }; + + }, + addEvent = helpers.addEvent = function(node,eventType,method){ + if (node.addEventListener){ + node.addEventListener(eventType,method); + } else if (node.attachEvent){ + node.attachEvent("on"+eventType, method); + } else { + node["on"+eventType] = method; + } + }, + removeEvent = helpers.removeEvent = function(node, eventType, handler){ + if (node.removeEventListener){ + node.removeEventListener(eventType, handler, false); + } else if (node.detachEvent){ + node.detachEvent("on"+eventType,handler); + } else{ + node["on" + eventType] = noop; + } + }, + bindEvents = helpers.bindEvents = function(chartInstance, arrayOfEvents, handler){ + // Create the events object if it's not already present + if (!chartInstance.events) chartInstance.events = {}; + + each(arrayOfEvents,function(eventName){ + chartInstance.events[eventName] = function(){ + handler.apply(chartInstance, arguments); + }; + addEvent(chartInstance.chart.canvas,eventName,chartInstance.events[eventName]); + }); + }, + unbindEvents = helpers.unbindEvents = function (chartInstance, arrayOfEvents) { + each(arrayOfEvents, function(handler,eventName){ + removeEvent(chartInstance.chart.canvas, eventName, handler); + }); + }, + getMaximumWidth = helpers.getMaximumWidth = function(domNode){ + var container = domNode.parentNode; + // TODO = check cross browser stuff with this. + return container.clientWidth; + }, + getMaximumHeight = helpers.getMaximumHeight = function(domNode){ + var container = domNode.parentNode; + // TODO = check cross browser stuff with this. + return container.clientHeight; + }, + getMaximumSize = helpers.getMaximumSize = helpers.getMaximumWidth, // legacy support + retinaScale = helpers.retinaScale = function(chart){ + var ctx = chart.ctx, + width = chart.canvas.width, + height = chart.canvas.height; + + if (window.devicePixelRatio) { + ctx.canvas.style.width = width + "px"; + ctx.canvas.style.height = height + "px"; + ctx.canvas.height = height * window.devicePixelRatio; + ctx.canvas.width = width * window.devicePixelRatio; + ctx.scale(window.devicePixelRatio, window.devicePixelRatio); + } + }, + //-- Canvas methods + clear = helpers.clear = function(chart){ + chart.ctx.clearRect(0,0,chart.width,chart.height); + }, + fontString = helpers.fontString = function(pixelSize,fontStyle,fontFamily){ + return fontStyle + " " + pixelSize+"px " + fontFamily; + }, + longestText = helpers.longestText = function(ctx,font,arrayOfStrings){ + ctx.font = font; + var longest = 0; + each(arrayOfStrings,function(string){ + var textWidth = ctx.measureText(string).width; + longest = (textWidth > longest) ? textWidth : longest; + }); + return longest; + }, + drawRoundedRectangle = helpers.drawRoundedRectangle = function(ctx,x,y,width,height,radius){ + ctx.beginPath(); + ctx.moveTo(x + radius, y); + ctx.lineTo(x + width - radius, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius); + ctx.lineTo(x + width, y + height - radius); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); + ctx.lineTo(x + radius, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius); + ctx.lineTo(x, y + radius); + ctx.quadraticCurveTo(x, y, x + radius, y); + ctx.closePath(); + }; + + + //Store a reference to each instance - allowing us to globally resize chart instances on window resize. + //Destroy method on the chart will remove the instance of the chart from this reference. + Chart.instances = {}; + + Chart.Type = function(data,options,chart){ + this.options = options; + this.chart = chart; + this.id = uid(); + //Add the chart instance to the global namespace + Chart.instances[this.id] = this; + + // Initialize is always called when a chart type is created + // By default it is a no op, but it should be extended + if (options.responsive){ + this.resize(); + } + this.initialize.call(this,data); + }; + + //Core methods that'll be a part of every chart type + extend(Chart.Type.prototype,{ + initialize : function(){return this;}, + clear : function(){ + clear(this.chart); + return this; + }, + stop : function(){ + // Stops any current animation loop occuring + helpers.cancelAnimFrame.call(root, this.animationFrame); + return this; + }, + resize : function(callback){ + this.stop(); + var canvas = this.chart.canvas, + newWidth = getMaximumWidth(this.chart.canvas), + newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : getMaximumHeight(this.chart.canvas); + + canvas.width = this.chart.width = newWidth; + canvas.height = this.chart.height = newHeight; + + retinaScale(this.chart); + + if (typeof callback === "function"){ + callback.apply(this, Array.prototype.slice.call(arguments, 1)); + } + return this; + }, + reflow : noop, + render : function(reflow){ + if (reflow){ + this.reflow(); + } + if (this.options.animation && !reflow){ + helpers.animationLoop( + this.draw, + this.options.animationSteps, + this.options.animationEasing, + this.options.onAnimationProgress, + this.options.onAnimationComplete, + this + ); + } + else{ + this.draw(); + this.options.onAnimationComplete.call(this); + } + return this; + }, + generateLegend : function(){ + return template(this.options.legendTemplate,this); + }, + destroy : function(){ + this.clear(); + unbindEvents(this, this.events); + delete Chart.instances[this.id]; + }, + showTooltip : function(ChartElements, forceRedraw){ + // Only redraw the chart if we've actually changed what we're hovering on. + if (typeof this.activeElements === 'undefined') this.activeElements = []; + + var isChanged = (function(Elements){ + var changed = false; + + if (Elements.length !== this.activeElements.length){ + changed = true; + return changed; + } + + each(Elements, function(element, index){ + if (element !== this.activeElements[index]){ + changed = true; + } + }, this); + return changed; + }).call(this, ChartElements); + + if (!isChanged && !forceRedraw){ + return; + } + else{ + this.activeElements = ChartElements; + } + this.draw(); + if (ChartElements.length > 0){ + // If we have multiple datasets, show a MultiTooltip for all of the data points at that index + if (this.datasets && this.datasets.length > 1) { + var dataArray, + dataIndex; + + for (var i = this.datasets.length - 1; i >= 0; i--) { + dataArray = this.datasets[i].points || this.datasets[i].bars || this.datasets[i].segments; + dataIndex = indexOf(dataArray, ChartElements[0]); + if (dataIndex !== -1){ + break; + } + } + var tooltipLabels = [], + tooltipColors = [], + medianPosition = (function(index) { + + // Get all the points at that particular index + var Elements = [], + dataCollection, + xPositions = [], + yPositions = [], + xMax, + yMax, + xMin, + yMin; + helpers.each(this.datasets, function(dataset){ + dataCollection = dataset.points || dataset.bars || dataset.segments; + if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){ + Elements.push(dataCollection[dataIndex]); + } + }); + + helpers.each(Elements, function(element) { + xPositions.push(element.x); + yPositions.push(element.y); + + + //Include any colour information about the element + tooltipLabels.push(helpers.template(this.options.multiTooltipTemplate, element)); + tooltipColors.push({ + fill: element._saved.fillColor || element.fillColor, + stroke: element._saved.strokeColor || element.strokeColor + }); + + }, this); + + yMin = min(yPositions); + yMax = max(yPositions); + + xMin = min(xPositions); + xMax = max(xPositions); + + return { + x: (xMin > this.chart.width/2) ? xMin : xMax, + y: (yMin + yMax)/2 + }; + }).call(this, dataIndex); + + new Chart.MultiTooltip({ + x: medianPosition.x, + y: medianPosition.y, + xPadding: this.options.tooltipXPadding, + yPadding: this.options.tooltipYPadding, + xOffset: this.options.tooltipXOffset, + fillColor: this.options.tooltipFillColor, + textColor: this.options.tooltipFontColor, + fontFamily: this.options.tooltipFontFamily, + fontStyle: this.options.tooltipFontStyle, + fontSize: this.options.tooltipFontSize, + titleTextColor: this.options.tooltipTitleFontColor, + titleFontFamily: this.options.tooltipTitleFontFamily, + titleFontStyle: this.options.tooltipTitleFontStyle, + titleFontSize: this.options.tooltipTitleFontSize, + cornerRadius: this.options.tooltipCornerRadius, + labels: tooltipLabels, + legendColors: tooltipColors, + legendColorBackground : this.options.multiTooltipKeyBackground, + title: ChartElements[0].label, + chart: this.chart, + ctx: this.chart.ctx + }).draw(); + + } else { + each(ChartElements, function(Element) { + var tooltipPosition = Element.tooltipPosition(); + new Chart.Tooltip({ + x: Math.round(tooltipPosition.x), + y: Math.round(tooltipPosition.y), + xPadding: this.options.tooltipXPadding, + yPadding: this.options.tooltipYPadding, + fillColor: this.options.tooltipFillColor, + textColor: this.options.tooltipFontColor, + fontFamily: this.options.tooltipFontFamily, + fontStyle: this.options.tooltipFontStyle, + fontSize: this.options.tooltipFontSize, + caretHeight: this.options.tooltipCaretSize, + cornerRadius: this.options.tooltipCornerRadius, + text: template(this.options.tooltipTemplate, Element), + chart: this.chart + }).draw(); + }, this); + } + } + return this; + }, + toBase64Image : function(){ + return this.chart.canvas.toDataURL.apply(this.chart.canvas, arguments); + } + }); + + Chart.Type.extend = function(extensions){ + + var parent = this; + + var ChartType = function(){ + return parent.apply(this,arguments); + }; + + //Copy the prototype object of the this class + ChartType.prototype = clone(parent.prototype); + //Now overwrite some of the properties in the base class with the new extensions + extend(ChartType.prototype, extensions); + + ChartType.extend = Chart.Type.extend; + + if (extensions.name || parent.prototype.name){ + + var chartName = extensions.name || parent.prototype.name; + //Assign any potential default values of the new chart type + + //If none are defined, we'll use a clone of the chart type this is being extended from. + //I.e. if we extend a line chart, we'll use the defaults from the line chart if our new chart + //doesn't define some defaults of their own. + + var baseDefaults = (Chart.defaults[parent.prototype.name]) ? clone(Chart.defaults[parent.prototype.name]) : {}; + + Chart.defaults[chartName] = extend(baseDefaults,extensions.defaults); + + Chart.types[chartName] = ChartType; + + //Register this new chart type in the Chart prototype + Chart.prototype[chartName] = function(data,options){ + var config = merge(Chart.defaults.global, Chart.defaults[chartName], options || {}); + return new ChartType(data,config,this); + }; + } else{ + warn("Name not provided for this chart, so it hasn't been registered"); + } + return parent; + }; + + Chart.Element = function(configuration){ + extend(this,configuration); + this.initialize.apply(this,arguments); + this.save(); + }; + extend(Chart.Element.prototype,{ + initialize : function(){}, + restore : function(props){ + if (!props){ + extend(this,this._saved); + } else { + each(props,function(key){ + this[key] = this._saved[key]; + },this); + } + return this; + }, + save : function(){ + this._saved = clone(this); + delete this._saved._saved; + return this; + }, + update : function(newProps){ + each(newProps,function(value,key){ + this._saved[key] = this[key]; + this[key] = value; + },this); + return this; + }, + transition : function(props,ease){ + each(props,function(value,key){ + this[key] = ((value - this._saved[key]) * ease) + this._saved[key]; + },this); + return this; + }, + tooltipPosition : function(){ + return { + x : this.x, + y : this.y + }; + }, + hasValue: function(){ + return isNumber(this.value); + } + }); + + Chart.Element.extend = inherits; + + + Chart.Point = Chart.Element.extend({ + display: true, + inRange: function(chartX,chartY){ + var hitDetectionRange = this.hitDetectionRadius + this.radius; + return ((Math.pow(chartX-this.x, 2)+Math.pow(chartY-this.y, 2)) < Math.pow(hitDetectionRange,2)); + }, + draw : function(){ + if (this.display){ + var ctx = this.ctx; + ctx.beginPath(); + + ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2); + ctx.closePath(); + + ctx.strokeStyle = this.strokeColor; + ctx.lineWidth = this.strokeWidth; + + ctx.fillStyle = this.fillColor; + + ctx.fill(); + ctx.stroke(); + } + + + //Quick debug for bezier curve splining + //Highlights control points and the line between them. + //Handy for dev - stripped in the min version. + + // ctx.save(); + // ctx.fillStyle = "black"; + // ctx.strokeStyle = "black" + // ctx.beginPath(); + // ctx.arc(this.controlPoints.inner.x,this.controlPoints.inner.y, 2, 0, Math.PI*2); + // ctx.fill(); + + // ctx.beginPath(); + // ctx.arc(this.controlPoints.outer.x,this.controlPoints.outer.y, 2, 0, Math.PI*2); + // ctx.fill(); + + // ctx.moveTo(this.controlPoints.inner.x,this.controlPoints.inner.y); + // ctx.lineTo(this.x, this.y); + // ctx.lineTo(this.controlPoints.outer.x,this.controlPoints.outer.y); + // ctx.stroke(); + + // ctx.restore(); + + + + } + }); + + Chart.Arc = Chart.Element.extend({ + inRange : function(chartX,chartY){ + + var pointRelativePosition = helpers.getAngleFromPoint(this, { + x: chartX, + y: chartY + }); + + //Check if within the range of the open/close angle + var betweenAngles = (pointRelativePosition.angle >= this.startAngle && pointRelativePosition.angle <= this.endAngle), + withinRadius = (pointRelativePosition.distance >= this.innerRadius && pointRelativePosition.distance <= this.outerRadius); + + return (betweenAngles && withinRadius); + //Ensure within the outside of the arc centre, but inside arc outer + }, + tooltipPosition : function(){ + var centreAngle = this.startAngle + ((this.endAngle - this.startAngle) / 2), + rangeFromCentre = (this.outerRadius - this.innerRadius) / 2 + this.innerRadius; + return { + x : this.x + (Math.cos(centreAngle) * rangeFromCentre), + y : this.y + (Math.sin(centreAngle) * rangeFromCentre) + }; + }, + draw : function(animationPercent){ + + var easingDecimal = animationPercent || 1; + + var ctx = this.ctx; + + ctx.beginPath(); + + ctx.arc(this.x, this.y, this.outerRadius, this.startAngle, this.endAngle); + + ctx.arc(this.x, this.y, this.innerRadius, this.endAngle, this.startAngle, true); + + ctx.closePath(); + ctx.strokeStyle = this.strokeColor; + ctx.lineWidth = this.strokeWidth; + + ctx.fillStyle = this.fillColor; + + ctx.fill(); + ctx.lineJoin = 'bevel'; + + if (this.showStroke){ + ctx.stroke(); + } + } + }); + + Chart.Rectangle = Chart.Element.extend({ + draw : function(){ + var ctx = this.ctx, + halfWidth = this.width/2, + leftX = this.x - halfWidth, + rightX = this.x + halfWidth, + top = this.base - (this.base - this.y), + halfStroke = this.strokeWidth / 2; + + // Canvas doesn't allow us to stroke inside the width so we can + // adjust the sizes to fit if we're setting a stroke on the line + if (this.showStroke){ + leftX += halfStroke; + rightX -= halfStroke; + top += halfStroke; + } + + ctx.beginPath(); + + ctx.fillStyle = this.fillColor; + ctx.strokeStyle = this.strokeColor; + ctx.lineWidth = this.strokeWidth; + + // It'd be nice to keep this class totally generic to any rectangle + // and simply specify which border to miss out. + ctx.moveTo(leftX, this.base); + ctx.lineTo(leftX, top); + ctx.lineTo(rightX, top); + ctx.lineTo(rightX, this.base); + ctx.fill(); + if (this.showStroke){ + ctx.stroke(); + } + }, + height : function(){ + return this.base - this.y; + }, + inRange : function(chartX,chartY){ + return (chartX >= this.x - this.width/2 && chartX <= this.x + this.width/2) && (chartY >= this.y && chartY <= this.base); + } + }); + + Chart.Tooltip = Chart.Element.extend({ + draw : function(){ + + var ctx = this.chart.ctx; + + ctx.font = fontString(this.fontSize,this.fontStyle,this.fontFamily); + + this.xAlign = "center"; + this.yAlign = "above"; + + //Distance between the actual element.y position and the start of the tooltip caret + var caretPadding = 2; + + var tooltipWidth = ctx.measureText(this.text).width + 2*this.xPadding, + tooltipRectHeight = this.fontSize + 2*this.yPadding, + tooltipHeight = tooltipRectHeight + this.caretHeight + caretPadding; + + if (this.x + tooltipWidth/2 >this.chart.width){ + this.xAlign = "left"; + } else if (this.x - tooltipWidth/2 < 0){ + this.xAlign = "right"; + } + + if (this.y - tooltipHeight < 0){ + this.yAlign = "below"; + } + + + var tooltipX = this.x - tooltipWidth/2, + tooltipY = this.y - tooltipHeight; + + ctx.fillStyle = this.fillColor; + + switch(this.yAlign) + { + case "above": + //Draw a caret above the x/y + ctx.beginPath(); + ctx.moveTo(this.x,this.y - caretPadding); + ctx.lineTo(this.x + this.caretHeight, this.y - (caretPadding + this.caretHeight)); + ctx.lineTo(this.x - this.caretHeight, this.y - (caretPadding + this.caretHeight)); + ctx.closePath(); + ctx.fill(); + break; + case "below": + tooltipY = this.y + caretPadding + this.caretHeight; + //Draw a caret below the x/y + ctx.beginPath(); + ctx.moveTo(this.x, this.y + caretPadding); + ctx.lineTo(this.x + this.caretHeight, this.y + caretPadding + this.caretHeight); + ctx.lineTo(this.x - this.caretHeight, this.y + caretPadding + this.caretHeight); + ctx.closePath(); + ctx.fill(); + break; + } + + switch(this.xAlign) + { + case "left": + tooltipX = this.x - tooltipWidth + (this.cornerRadius + this.caretHeight); + break; + case "right": + tooltipX = this.x - (this.cornerRadius + this.caretHeight); + break; + } + + drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,this.cornerRadius); + + ctx.fill(); + + ctx.fillStyle = this.textColor; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.fillText(this.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2); + } + }); + + Chart.MultiTooltip = Chart.Element.extend({ + initialize : function(){ + this.font = fontString(this.fontSize,this.fontStyle,this.fontFamily); + + this.titleFont = fontString(this.titleFontSize,this.titleFontStyle,this.titleFontFamily); + + this.height = (this.labels.length * this.fontSize) + ((this.labels.length-1) * (this.fontSize/2)) + (this.yPadding*2) + this.titleFontSize *1.5; + + this.ctx.font = this.titleFont; + + var titleWidth = this.ctx.measureText(this.title).width, + //Label has a legend square as well so account for this. + labelWidth = longestText(this.ctx,this.font,this.labels) + this.fontSize + 3, + longestTextWidth = max([labelWidth,titleWidth]); + + this.width = longestTextWidth + (this.xPadding*2); + + + var halfHeight = this.height/2; + + //Check to ensure the height will fit on the canvas + //The three is to buffer form the very + if (this.y - halfHeight < 0 ){ + this.y = halfHeight; + } else if (this.y + halfHeight > this.chart.height){ + this.y = this.chart.height - halfHeight; + } + + //Decide whether to align left or right based on position on canvas + if (this.x > this.chart.width/2){ + this.x -= this.xOffset + this.width; + } else { + this.x += this.xOffset; + } + + + }, + getLineHeight : function(index){ + var baseLineHeight = this.y - (this.height/2) + this.yPadding, + afterTitleIndex = index-1; + + //If the index is zero, we're getting the title + if (index === 0){ + return baseLineHeight + this.titleFontSize/2; + } else{ + return baseLineHeight + ((this.fontSize*1.5*afterTitleIndex) + this.fontSize/2) + this.titleFontSize * 1.5; + } + + }, + draw : function(){ + drawRoundedRectangle(this.ctx,this.x,this.y - this.height/2,this.width,this.height,this.cornerRadius); + var ctx = this.ctx; + ctx.fillStyle = this.fillColor; + ctx.fill(); + ctx.closePath(); + + ctx.textAlign = "left"; + ctx.textBaseline = "middle"; + ctx.fillStyle = this.titleTextColor; + ctx.font = this.titleFont; + + ctx.fillText(this.title,this.x + this.xPadding, this.getLineHeight(0)); + + ctx.font = this.font; + helpers.each(this.labels,function(label,index){ + ctx.fillStyle = this.textColor; + ctx.fillText(label,this.x + this.xPadding + this.fontSize + 3, this.getLineHeight(index + 1)); + + //A bit gnarly, but clearing this rectangle breaks when using explorercanvas (clears whole canvas) + //ctx.clearRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize); + //Instead we'll make a white filled block to put the legendColour palette over. + + ctx.fillStyle = this.legendColorBackground; + ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize); + + ctx.fillStyle = this.legendColors[index].fill; + ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize); + + + },this); + } + }); + + Chart.Scale = Chart.Element.extend({ + initialize : function(){ + this.fit(); + }, + buildYLabels : function(){ + this.yLabels = []; + + var stepDecimalPlaces = getDecimalPlaces(this.stepValue); + + for (var i=0; i<=this.steps; i++){ + this.yLabels.push(template(this.templateString,{value:(this.min + (i * this.stepValue)).toFixed(stepDecimalPlaces)})); + } + this.yLabelWidth = (this.display && this.showLabels) ? longestText(this.ctx,this.font,this.yLabels) : 0; + }, + addXLabel : function(label){ + this.xLabels.push(label); + this.valuesCount++; + this.fit(); + }, + removeXLabel : function(){ + this.xLabels.shift(); + this.valuesCount--; + this.fit(); + }, + // Fitting loop to rotate x Labels and figure out what fits there, and also calculate how many Y steps to use + fit: function(){ + // First we need the width of the yLabels, assuming the xLabels aren't rotated + + // To do that we need the base line at the top and base of the chart, assuming there is no x label rotation + this.startPoint = (this.display) ? this.fontSize : 0; + this.endPoint = (this.display) ? this.height - (this.fontSize * 1.5) - 5 : this.height; // -5 to pad labels + + // Apply padding settings to the start and end point. + this.startPoint += this.padding; + this.endPoint -= this.padding; + + // Cache the starting height, so can determine if we need to recalculate the scale yAxis + var cachedHeight = this.endPoint - this.startPoint, + cachedYLabelWidth; + + // Build the current yLabels so we have an idea of what size they'll be to start + /* + * This sets what is returned from calculateScaleRange as static properties of this class: + * + this.steps; + this.stepValue; + this.min; + this.max; + * + */ + this.calculateYRange(cachedHeight); + + // With these properties set we can now build the array of yLabels + // and also the width of the largest yLabel + this.buildYLabels(); + + this.calculateXLabelRotation(); + + while((cachedHeight > this.endPoint - this.startPoint)){ + cachedHeight = this.endPoint - this.startPoint; + cachedYLabelWidth = this.yLabelWidth; + + this.calculateYRange(cachedHeight); + this.buildYLabels(); + + // Only go through the xLabel loop again if the yLabel width has changed + if (cachedYLabelWidth < this.yLabelWidth){ + this.calculateXLabelRotation(); + } + } + + }, + calculateXLabelRotation : function(){ + //Get the width of each grid by calculating the difference + //between x offsets between 0 and 1. + + this.ctx.font = this.font; + + var firstWidth = this.ctx.measureText(this.xLabels[0]).width, + lastWidth = this.ctx.measureText(this.xLabels[this.xLabels.length - 1]).width, + firstRotated, + lastRotated; + + + this.xScalePaddingRight = lastWidth/2 + 3; + this.xScalePaddingLeft = (firstWidth/2 > this.yLabelWidth + 10) ? firstWidth/2 : this.yLabelWidth + 10; + + this.xLabelRotation = 0; + if (this.display){ + var originalLabelWidth = longestText(this.ctx,this.font,this.xLabels), + cosRotation, + firstRotatedWidth; + this.xLabelWidth = originalLabelWidth; + //Allow 3 pixels x2 padding either side for label readability + var xGridWidth = Math.floor(this.calculateX(1) - this.calculateX(0)) - 6; + + //Max label rotate should be 90 - also act as a loop counter + while ((this.xLabelWidth > xGridWidth && this.xLabelRotation === 0) || (this.xLabelWidth > xGridWidth && this.xLabelRotation <= 90 && this.xLabelRotation > 0)){ + cosRotation = Math.cos(toRadians(this.xLabelRotation)); + + firstRotated = cosRotation * firstWidth; + lastRotated = cosRotation * lastWidth; + + // We're right aligning the text now. + if (firstRotated + this.fontSize / 2 > this.yLabelWidth + 8){ + this.xScalePaddingLeft = firstRotated + this.fontSize / 2; + } + this.xScalePaddingRight = this.fontSize/2; + + + this.xLabelRotation++; + this.xLabelWidth = cosRotation * originalLabelWidth; + + } + if (this.xLabelRotation > 0){ + this.endPoint -= Math.sin(toRadians(this.xLabelRotation))*originalLabelWidth + 3; + } + } + else{ + this.xLabelWidth = 0; + this.xScalePaddingRight = this.padding; + this.xScalePaddingLeft = this.padding; + } + + }, + // Needs to be overidden in each Chart type + // Otherwise we need to pass all the data into the scale class + calculateYRange: noop, + drawingArea: function(){ + return this.startPoint - this.endPoint; + }, + calculateY : function(value){ + var scalingFactor = this.drawingArea() / (this.min - this.max); + return this.endPoint - (scalingFactor * (value - this.min)); + }, + calculateX : function(index){ + var isRotated = (this.xLabelRotation > 0), + // innerWidth = (this.offsetGridLines) ? this.width - offsetLeft - this.padding : this.width - (offsetLeft + halfLabelWidth * 2) - this.padding, + innerWidth = this.width - (this.xScalePaddingLeft + this.xScalePaddingRight), + valueWidth = innerWidth/(this.valuesCount - ((this.offsetGridLines) ? 0 : 1)), + valueOffset = (valueWidth * index) + this.xScalePaddingLeft; + + if (this.offsetGridLines){ + valueOffset += (valueWidth/2); + } + + return Math.round(valueOffset); + }, + update : function(newProps){ + helpers.extend(this, newProps); + this.fit(); + }, + draw : function(){ + var ctx = this.ctx, + yLabelGap = (this.endPoint - this.startPoint) / this.steps, + xStart = Math.round(this.xScalePaddingLeft); + if (this.display){ + ctx.fillStyle = this.textColor; + ctx.font = this.font; + each(this.yLabels,function(labelString,index){ + var yLabelCenter = this.endPoint - (yLabelGap * index), + linePositionY = Math.round(yLabelCenter); + + ctx.textAlign = "right"; + ctx.textBaseline = "middle"; + if (this.showLabels){ + ctx.fillText(labelString,xStart - 10,yLabelCenter); + } + ctx.beginPath(); + if (index > 0){ + // This is a grid line in the centre, so drop that + ctx.lineWidth = this.gridLineWidth; + ctx.strokeStyle = this.gridLineColor; + } else { + // This is the first line on the scale + ctx.lineWidth = this.lineWidth; + ctx.strokeStyle = this.lineColor; + } + + linePositionY += helpers.aliasPixel(ctx.lineWidth); + + ctx.moveTo(xStart, linePositionY); + ctx.lineTo(this.width, linePositionY); + ctx.stroke(); + ctx.closePath(); + + ctx.lineWidth = this.lineWidth; + ctx.strokeStyle = this.lineColor; + ctx.beginPath(); + ctx.moveTo(xStart - 5, linePositionY); + ctx.lineTo(xStart, linePositionY); + ctx.stroke(); + ctx.closePath(); + + },this); + + each(this.xLabels,function(label,index){ + var xPos = this.calculateX(index) + aliasPixel(this.lineWidth), + // Check to see if line/bar here and decide where to place the line + linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth), + isRotated = (this.xLabelRotation > 0); + + ctx.beginPath(); + + if (index > 0){ + // This is a grid line in the centre, so drop that + ctx.lineWidth = this.gridLineWidth; + ctx.strokeStyle = this.gridLineColor; + } else { + // This is the first line on the scale + ctx.lineWidth = this.lineWidth; + ctx.strokeStyle = this.lineColor; + } + ctx.moveTo(linePos,this.endPoint); + ctx.lineTo(linePos,this.startPoint - 3); + ctx.stroke(); + ctx.closePath(); + + + ctx.lineWidth = this.lineWidth; + ctx.strokeStyle = this.lineColor; + + + // Small lines at the bottom of the base grid line + ctx.beginPath(); + ctx.moveTo(linePos,this.endPoint); + ctx.lineTo(linePos,this.endPoint + 5); + ctx.stroke(); + ctx.closePath(); + + ctx.save(); + ctx.translate(xPos,(isRotated) ? this.endPoint + 12 : this.endPoint + 8); + ctx.rotate(toRadians(this.xLabelRotation)*-1); + ctx.font = this.font; + ctx.textAlign = (isRotated) ? "right" : "center"; + ctx.textBaseline = (isRotated) ? "middle" : "top"; + ctx.fillText(label, 0, 0); + ctx.restore(); + },this); + + } + } + + }); + + Chart.RadialScale = Chart.Element.extend({ + initialize: function(){ + this.size = min([this.height, this.width]); + this.drawingArea = (this.display) ? (this.size/2) - (this.fontSize/2 + this.backdropPaddingY) : (this.size/2); + }, + calculateCenterOffset: function(value){ + // Take into account half font size + the yPadding of the top value + var scalingFactor = this.drawingArea / (this.max - this.min); + + return (value - this.min) * scalingFactor; + }, + update : function(){ + if (!this.lineArc){ + this.setScaleSize(); + } else { + this.drawingArea = (this.display) ? (this.size/2) - (this.fontSize/2 + this.backdropPaddingY) : (this.size/2); + } + this.buildYLabels(); + }, + buildYLabels: function(){ + this.yLabels = []; + + var stepDecimalPlaces = getDecimalPlaces(this.stepValue); + + for (var i=0; i<=this.steps; i++){ + this.yLabels.push(template(this.templateString,{value:(this.min + (i * this.stepValue)).toFixed(stepDecimalPlaces)})); + } + }, + getCircumference : function(){ + return ((Math.PI*2) / this.valuesCount); + }, + setScaleSize: function(){ + /* + * Right, this is really confusing and there is a lot of maths going on here + * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9 + * + * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif + * + * Solution: + * + * We assume the radius of the polygon is half the size of the canvas at first + * at each index we check if the text overlaps. + * + * Where it does, we store that angle and that index. + * + * After finding the largest index and angle we calculate how much we need to remove + * from the shape radius to move the point inwards by that x. + * + * We average the left and right distances to get the maximum shape radius that can fit in the box + * along with labels. + * + * Once we have that, we can find the centre point for the chart, by taking the x text protrusion + * on each side, removing that from the size, halving it and adding the left x protrusion width. + * + * This will mean we have a shape fitted to the canvas, as large as it can be with the labels + * and position it in the most space efficient manner + * + * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif + */ + + + // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width. + // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points + var largestPossibleRadius = min([(this.height/2 - this.pointLabelFontSize - 5), this.width/2]), + pointPosition, + i, + textWidth, + halfTextWidth, + furthestRight = this.width, + furthestRightIndex, + furthestRightAngle, + furthestLeft = 0, + furthestLeftIndex, + furthestLeftAngle, + xProtrusionLeft, + xProtrusionRight, + radiusReductionRight, + radiusReductionLeft, + maxWidthRadius; + this.ctx.font = fontString(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily); + for (i=0;i furthestRight) { + furthestRight = pointPosition.x + halfTextWidth; + furthestRightIndex = i; + } + if (pointPosition.x - halfTextWidth < furthestLeft) { + furthestLeft = pointPosition.x - halfTextWidth; + furthestLeftIndex = i; + } + } + else if (i < this.valuesCount/2) { + // Less than half the values means we'll left align the text + if (pointPosition.x + textWidth > furthestRight) { + furthestRight = pointPosition.x + textWidth; + furthestRightIndex = i; + } + } + else if (i > this.valuesCount/2){ + // More than half the values means we'll right align the text + if (pointPosition.x - textWidth < furthestLeft) { + furthestLeft = pointPosition.x - textWidth; + furthestLeftIndex = i; + } + } + } + + xProtrusionLeft = furthestLeft; + + xProtrusionRight = Math.ceil(furthestRight - this.width); + + furthestRightAngle = this.getIndexAngle(furthestRightIndex); + + furthestLeftAngle = this.getIndexAngle(furthestLeftIndex); + + radiusReductionRight = xProtrusionRight / Math.sin(furthestRightAngle + Math.PI/2); + + radiusReductionLeft = xProtrusionLeft / Math.sin(furthestLeftAngle + Math.PI/2); + + // Ensure we actually need to reduce the size of the chart + radiusReductionRight = (isNumber(radiusReductionRight)) ? radiusReductionRight : 0; + radiusReductionLeft = (isNumber(radiusReductionLeft)) ? radiusReductionLeft : 0; + + this.drawingArea = largestPossibleRadius - (radiusReductionLeft + radiusReductionRight)/2; + + //this.drawingArea = min([maxWidthRadius, (this.height - (2 * (this.pointLabelFontSize + 5)))/2]) + this.setCenterPoint(radiusReductionLeft, radiusReductionRight); + + }, + setCenterPoint: function(leftMovement, rightMovement){ + + var maxRight = this.width - rightMovement - this.drawingArea, + maxLeft = leftMovement + this.drawingArea; + + this.xCenter = (maxLeft + maxRight)/2; + // Always vertically in the centre as the text height doesn't change + this.yCenter = (this.height/2); + }, + + getIndexAngle : function(index){ + var angleMultiplier = (Math.PI * 2) / this.valuesCount; + // Start from the top instead of right, so remove a quarter of the circle + + return index * angleMultiplier - (Math.PI/2); + }, + getPointPosition : function(index, distanceFromCenter){ + var thisAngle = this.getIndexAngle(index); + return { + x : (Math.cos(thisAngle) * distanceFromCenter) + this.xCenter, + y : (Math.sin(thisAngle) * distanceFromCenter) + this.yCenter + }; + }, + draw: function(){ + if (this.display){ + var ctx = this.ctx; + each(this.yLabels, function(label, index){ + // Don't draw a centre value + if (index > 0){ + var yCenterOffset = index * (this.drawingArea/this.steps), + yHeight = this.yCenter - yCenterOffset, + pointPosition; + + // Draw circular lines around the scale + if (this.lineWidth > 0){ + ctx.strokeStyle = this.lineColor; + ctx.lineWidth = this.lineWidth; + + if(this.lineArc){ + ctx.beginPath(); + ctx.arc(this.xCenter, this.yCenter, yCenterOffset, 0, Math.PI*2); + ctx.closePath(); + ctx.stroke(); + } else{ + ctx.beginPath(); + for (var i=0;i= 0; i--) { + if (this.angleLineWidth > 0){ + var outerPosition = this.getPointPosition(i, this.calculateCenterOffset(this.max)); + ctx.beginPath(); + ctx.moveTo(this.xCenter, this.yCenter); + ctx.lineTo(outerPosition.x, outerPosition.y); + ctx.stroke(); + ctx.closePath(); + } + // Extra 3px out for some label spacing + var pointLabelPosition = this.getPointPosition(i, this.calculateCenterOffset(this.max) + 5); + ctx.font = fontString(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily); + ctx.fillStyle = this.pointLabelFontColor; + + var labelsCount = this.labels.length, + halfLabelsCount = this.labels.length/2, + quarterLabelsCount = halfLabelsCount/2, + upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount), + exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount); + if (i === 0){ + ctx.textAlign = 'center'; + } else if(i === halfLabelsCount){ + ctx.textAlign = 'center'; + } else if (i < halfLabelsCount){ + ctx.textAlign = 'left'; + } else { + ctx.textAlign = 'right'; + } + + // Set the correct text baseline based on outer positioning + if (exactQuarter){ + ctx.textBaseline = 'middle'; + } else if (upperHalf){ + ctx.textBaseline = 'bottom'; + } else { + ctx.textBaseline = 'top'; + } + + ctx.fillText(this.labels[i], pointLabelPosition.x, pointLabelPosition.y); + } + } + } + } + }); + + // Attach global event to resize each chart instance when the browser resizes + helpers.addEvent(window, "resize", (function(){ + // Basic debounce of resize function so it doesn't hurt performance when resizing browser. + var timeout; + return function(){ + clearTimeout(timeout); + timeout = setTimeout(function(){ + each(Chart.instances,function(instance){ + // If the responsive flag is set in the chart instance config + // Cascade the resize event down to the chart. + if (instance.options.responsive){ + instance.resize(instance.render, true); + } + }); + }, 50); + }; + })()); + + + if (amd) { + define(function(){ + return Chart; + }); + } else if (typeof module === 'object' && module.exports) { + module.exports = Chart; + } + + root.Chart = Chart; + + Chart.noConflict = function(){ + root.Chart = previous; + return Chart; + }; + +}).call(this); diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Doughnut.js b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Doughnut.js new file mode 100755 index 0000000..35de93c --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Doughnut.js @@ -0,0 +1,184 @@ +(function(){ + "use strict"; + + var root = this, + Chart = root.Chart, + //Cache a local reference to Chart.helpers + helpers = Chart.helpers; + + var defaultConfig = { + //Boolean - Whether we should show a stroke on each segment + segmentShowStroke : true, + + //String - The colour of each segment stroke + segmentStrokeColor : "#fff", + + //Number - The width of each segment stroke + segmentStrokeWidth : 2, + + //The percentage of the chart that we cut out of the middle. + percentageInnerCutout : 50, + + //Number - Amount of animation steps + animationSteps : 100, + + //String - Animation easing effect + animationEasing : "easeOutBounce", + + //Boolean - Whether we animate the rotation of the Doughnut + animateRotate : true, + + //Boolean - Whether we animate scaling the Doughnut from the centre + animateScale : false, + + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(segments[i].label){%><%=segments[i].label%><%}%>
  • <%}%>
" + + }; + + + Chart.Type.extend({ + //Passing in a name registers this chart in the Chart namespace + name: "Doughnut", + //Providing a defaults will also register the deafults in the chart namespace + defaults : defaultConfig, + //Initialize is fired when the chart is initialized - Data is passed in as a parameter + //Config is automatically merged by the core of Chart.js, and is available at this.options + initialize: function(data){ + + //Declare segments as a static property to prevent inheriting across the Chart type prototype + this.segments = []; + this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2; + + this.SegmentArc = Chart.Arc.extend({ + ctx : this.chart.ctx, + x : this.chart.width/2, + y : this.chart.height/2 + }); + + //Set up tooltip events on the chart + if (this.options.showTooltips){ + helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ + var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : []; + + helpers.each(this.segments,function(segment){ + segment.restore(["fillColor"]); + }); + helpers.each(activeSegments,function(activeSegment){ + activeSegment.fillColor = activeSegment.highlightColor; + }); + this.showTooltip(activeSegments); + }); + } + this.calculateTotal(data); + + helpers.each(data,function(datapoint, index){ + this.addData(datapoint, index, true); + },this); + + this.render(); + }, + getSegmentsAtEvent : function(e){ + var segmentsArray = []; + + var location = helpers.getRelativePosition(e); + + helpers.each(this.segments,function(segment){ + if (segment.inRange(location.x,location.y)) segmentsArray.push(segment); + },this); + return segmentsArray; + }, + addData : function(segment, atIndex, silent){ + var index = atIndex || this.segments.length; + this.segments.splice(index, 0, new this.SegmentArc({ + value : segment.value, + outerRadius : (this.options.animateScale) ? 0 : this.outerRadius, + innerRadius : (this.options.animateScale) ? 0 : (this.outerRadius/100) * this.options.percentageInnerCutout, + fillColor : segment.color, + highlightColor : segment.highlight || segment.color, + showStroke : this.options.segmentShowStroke, + strokeWidth : this.options.segmentStrokeWidth, + strokeColor : this.options.segmentStrokeColor, + startAngle : Math.PI * 1.5, + circumference : (this.options.animateRotate) ? 0 : this.calculateCircumference(segment.value), + label : segment.label + })); + if (!silent){ + this.reflow(); + this.update(); + } + }, + calculateCircumference : function(value){ + return (Math.PI*2)*(value / this.total); + }, + calculateTotal : function(data){ + this.total = 0; + helpers.each(data,function(segment){ + this.total += segment.value; + },this); + }, + update : function(){ + this.calculateTotal(this.segments); + + // Reset any highlight colours before updating. + helpers.each(this.activeElements, function(activeElement){ + activeElement.restore(['fillColor']); + }); + + helpers.each(this.segments,function(segment){ + segment.save(); + }); + this.render(); + }, + + removeData: function(atIndex){ + var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1; + this.segments.splice(indexToDelete, 1); + this.reflow(); + this.update(); + }, + + reflow : function(){ + helpers.extend(this.SegmentArc.prototype,{ + x : this.chart.width/2, + y : this.chart.height/2 + }); + this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2; + helpers.each(this.segments, function(segment){ + segment.update({ + outerRadius : this.outerRadius, + innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout + }); + }, this); + }, + draw : function(easeDecimal){ + var animDecimal = (easeDecimal) ? easeDecimal : 1; + this.clear(); + helpers.each(this.segments,function(segment,index){ + segment.transition({ + circumference : this.calculateCircumference(segment.value), + outerRadius : this.outerRadius, + innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout + },animDecimal); + + segment.endAngle = segment.startAngle + segment.circumference; + + segment.draw(); + if (index === 0){ + segment.startAngle = Math.PI * 1.5; + } + //Check to see if it's the last segment, if not get the next and update the start angle + if (index < this.segments.length-1){ + this.segments[index+1].startAngle = segment.endAngle; + } + },this); + + } + }); + + Chart.types.Doughnut.extend({ + name : "Pie", + defaults : helpers.merge(defaultConfig,{percentageInnerCutout : 0}) + }); + +}).call(this); \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Line.js b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Line.js new file mode 100755 index 0000000..0b3079f --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Line.js @@ -0,0 +1,366 @@ +(function(){ + "use strict"; + + var root = this, + Chart = root.Chart, + helpers = Chart.helpers; + + var defaultConfig = { + + ///Boolean - Whether grid lines are shown across the chart + scaleShowGridLines : true, + + //String - Colour of the grid lines + scaleGridLineColor : "rgba(0,0,0,.05)", + + //Number - Width of the grid lines + scaleGridLineWidth : 1, + + //Boolean - Whether the line is curved between points + bezierCurve : true, + + //Number - Tension of the bezier curve between points + bezierCurveTension : 0.4, + + //Boolean - Whether to show a dot for each point + pointDot : true, + + //Number - Radius of each point dot in pixels + pointDotRadius : 4, + + //Number - Pixel width of point dot stroke + pointDotStrokeWidth : 1, + + //Number - amount extra to add to the radius to cater for hit detection outside the drawn point + pointHitDetectionRadius : 20, + + //Boolean - Whether to show a stroke for datasets + datasetStroke : true, + + //Number - Pixel width of dataset stroke + datasetStrokeWidth : 2, + + //Boolean - Whether to fill the dataset with a colour + datasetFill : true, + + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
" + + }; + + + Chart.Type.extend({ + name: "Line", + defaults : defaultConfig, + initialize: function(data){ + //Declare the extension of the default point, to cater for the options passed in to the constructor + this.PointClass = Chart.Point.extend({ + strokeWidth : this.options.pointDotStrokeWidth, + radius : this.options.pointDotRadius, + display: this.options.pointDot, + hitDetectionRadius : this.options.pointHitDetectionRadius, + ctx : this.chart.ctx, + inRange : function(mouseX){ + return (Math.pow(mouseX-this.x, 2) < Math.pow(this.radius + this.hitDetectionRadius,2)); + } + }); + + this.datasets = []; + + //Set up tooltip events on the chart + if (this.options.showTooltips){ + helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ + var activePoints = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : []; + this.eachPoints(function(point){ + point.restore(['fillColor', 'strokeColor']); + }); + helpers.each(activePoints, function(activePoint){ + activePoint.fillColor = activePoint.highlightFill; + activePoint.strokeColor = activePoint.highlightStroke; + }); + this.showTooltip(activePoints); + }); + } + + //Iterate through each of the datasets, and build this into a property of the chart + helpers.each(data.datasets,function(dataset){ + + var datasetObject = { + label : dataset.label || null, + fillColor : dataset.fillColor, + strokeColor : dataset.strokeColor, + pointColor : dataset.pointColor, + pointStrokeColor : dataset.pointStrokeColor, + points : [] + }; + + this.datasets.push(datasetObject); + + + helpers.each(dataset.data,function(dataPoint,index){ + //Add a new point for each piece of data, passing any required data to draw. + datasetObject.points.push(new this.PointClass({ + value : dataPoint, + label : data.labels[index], + datasetLabel: dataset.label, + strokeColor : dataset.pointStrokeColor, + fillColor : dataset.pointColor, + highlightFill : dataset.pointHighlightFill || dataset.pointColor, + highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor + })); + },this); + + this.buildScale(data.labels); + + + this.eachPoints(function(point, index){ + helpers.extend(point, { + x: this.scale.calculateX(index), + y: this.scale.endPoint + }); + point.save(); + }, this); + + },this); + + + this.render(); + }, + update : function(){ + this.scale.update(); + // Reset any highlight colours before updating. + helpers.each(this.activeElements, function(activeElement){ + activeElement.restore(['fillColor', 'strokeColor']); + }); + this.eachPoints(function(point){ + point.save(); + }); + this.render(); + }, + eachPoints : function(callback){ + helpers.each(this.datasets,function(dataset){ + helpers.each(dataset.points,callback,this); + },this); + }, + getPointsAtEvent : function(e){ + var pointsArray = [], + eventPosition = helpers.getRelativePosition(e); + helpers.each(this.datasets,function(dataset){ + helpers.each(dataset.points,function(point){ + if (point.inRange(eventPosition.x,eventPosition.y)) pointsArray.push(point); + }); + },this); + return pointsArray; + }, + buildScale : function(labels){ + var self = this; + + var dataTotal = function(){ + var values = []; + self.eachPoints(function(point){ + values.push(point.value); + }); + + return values; + }; + + var scaleOptions = { + templateString : this.options.scaleLabel, + height : this.chart.height, + width : this.chart.width, + ctx : this.chart.ctx, + textColor : this.options.scaleFontColor, + fontSize : this.options.scaleFontSize, + fontStyle : this.options.scaleFontStyle, + fontFamily : this.options.scaleFontFamily, + valuesCount : labels.length, + beginAtZero : this.options.scaleBeginAtZero, + integersOnly : this.options.scaleIntegersOnly, + calculateYRange : function(currentHeight){ + var updatedRanges = helpers.calculateScaleRange( + dataTotal(), + currentHeight, + this.fontSize, + this.beginAtZero, + this.integersOnly + ); + helpers.extend(this, updatedRanges); + }, + xLabels : labels, + font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily), + lineWidth : this.options.scaleLineWidth, + lineColor : this.options.scaleLineColor, + gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0, + gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)", + padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth, + showLabels : this.options.scaleShowLabels, + display : this.options.showScale + }; + + if (this.options.scaleOverride){ + helpers.extend(scaleOptions, { + calculateYRange: helpers.noop, + steps: this.options.scaleSteps, + stepValue: this.options.scaleStepWidth, + min: this.options.scaleStartValue, + max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth) + }); + } + + + this.scale = new Chart.Scale(scaleOptions); + }, + addData : function(valuesArray,label){ + //Map the values array for each of the datasets + + helpers.each(valuesArray,function(value,datasetIndex){ + //Add a new point for each piece of data, passing any required data to draw. + this.datasets[datasetIndex].points.push(new this.PointClass({ + value : value, + label : label, + x: this.scale.calculateX(this.scale.valuesCount+1), + y: this.scale.endPoint, + strokeColor : this.datasets[datasetIndex].pointStrokeColor, + fillColor : this.datasets[datasetIndex].pointColor + })); + },this); + + this.scale.addXLabel(label); + //Then re-render the chart. + this.update(); + }, + removeData : function(){ + this.scale.removeXLabel(); + //Then re-render the chart. + helpers.each(this.datasets,function(dataset){ + dataset.points.shift(); + },this); + this.update(); + }, + reflow : function(){ + var newScaleProps = helpers.extend({ + height : this.chart.height, + width : this.chart.width + }); + this.scale.update(newScaleProps); + }, + draw : function(ease){ + var easingDecimal = ease || 1; + this.clear(); + + var ctx = this.chart.ctx; + + // Some helper methods for getting the next/prev points + var hasValue = function(item){ + return item.value !== null; + }, + nextPoint = function(point, collection, index){ + return helpers.findNextWhere(collection, hasValue, index) || point; + }, + previousPoint = function(point, collection, index){ + return helpers.findPreviousWhere(collection, hasValue, index) || point; + }; + + this.scale.draw(easingDecimal); + + + helpers.each(this.datasets,function(dataset){ + var pointsWithValues = helpers.where(dataset.points, hasValue); + + //Transition each point first so that the line and point drawing isn't out of sync + //We can use this extra loop to calculate the control points of this dataset also in this loop + + helpers.each(dataset.points, function(point, index){ + if (point.hasValue()){ + point.transition({ + y : this.scale.calculateY(point.value), + x : this.scale.calculateX(index) + }, easingDecimal); + } + },this); + + + // Control points need to be calculated in a seperate loop, because we need to know the current x/y of the point + // This would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed + if (this.options.bezierCurve){ + helpers.each(pointsWithValues, function(point, index){ + var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0; + point.controlPoints = helpers.splineCurve( + previousPoint(point, pointsWithValues, index), + point, + nextPoint(point, pointsWithValues, index), + tension + ); + + // Prevent the bezier going outside of the bounds of the graph + + // Cap puter bezier handles to the upper/lower scale bounds + if (point.controlPoints.outer.y > this.scale.endPoint){ + point.controlPoints.outer.y = this.scale.endPoint; + } + else if (point.controlPoints.outer.y < this.scale.startPoint){ + point.controlPoints.outer.y = this.scale.startPoint; + } + + // Cap inner bezier handles to the upper/lower scale bounds + if (point.controlPoints.inner.y > this.scale.endPoint){ + point.controlPoints.inner.y = this.scale.endPoint; + } + else if (point.controlPoints.inner.y < this.scale.startPoint){ + point.controlPoints.inner.y = this.scale.startPoint; + } + },this); + } + + + //Draw the line between all the points + ctx.lineWidth = this.options.datasetStrokeWidth; + ctx.strokeStyle = dataset.strokeColor; + ctx.beginPath(); + + helpers.each(pointsWithValues, function(point, index){ + if (index === 0){ + ctx.moveTo(point.x, point.y); + } + else{ + if(this.options.bezierCurve){ + var previous = previousPoint(point, pointsWithValues, index); + + ctx.bezierCurveTo( + previous.controlPoints.outer.x, + previous.controlPoints.outer.y, + point.controlPoints.inner.x, + point.controlPoints.inner.y, + point.x, + point.y + ); + } + else{ + ctx.lineTo(point.x,point.y); + } + } + }, this); + + ctx.stroke(); + + if (this.options.datasetFill && pointsWithValues.length > 0){ + //Round off the line by going to the base of the chart, back to the start, then fill. + ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, this.scale.endPoint); + ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint); + ctx.fillStyle = dataset.fillColor; + ctx.closePath(); + ctx.fill(); + } + + //Now draw the points over the line + //A little inefficient double looping, but better than the line + //lagging behind the point positions + helpers.each(pointsWithValues,function(point){ + point.draw(); + }); + },this); + } + }); + + +}).call(this); \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.PolarArea.js b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.PolarArea.js new file mode 100755 index 0000000..4dbf2eb --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.PolarArea.js @@ -0,0 +1,248 @@ +(function(){ + "use strict"; + + var root = this, + Chart = root.Chart, + //Cache a local reference to Chart.helpers + helpers = Chart.helpers; + + var defaultConfig = { + //Boolean - Show a backdrop to the scale label + scaleShowLabelBackdrop : true, + + //String - The colour of the label backdrop + scaleBackdropColor : "rgba(255,255,255,0.75)", + + // Boolean - Whether the scale should begin at zero + scaleBeginAtZero : true, + + //Number - The backdrop padding above & below the label in pixels + scaleBackdropPaddingY : 2, + + //Number - The backdrop padding to the side of the label in pixels + scaleBackdropPaddingX : 2, + + //Boolean - Show line for each value in the scale + scaleShowLine : true, + + //Boolean - Stroke a line around each segment in the chart + segmentShowStroke : true, + + //String - The colour of the stroke on each segement. + segmentStrokeColor : "#fff", + + //Number - The width of the stroke value in pixels + segmentStrokeWidth : 2, + + //Number - Amount of animation steps + animationSteps : 100, + + //String - Animation easing effect. + animationEasing : "easeOutBounce", + + //Boolean - Whether to animate the rotation of the chart + animateRotate : true, + + //Boolean - Whether to animate scaling the chart from the centre + animateScale : false, + + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(segments[i].label){%><%=segments[i].label%><%}%>
  • <%}%>
" + }; + + + Chart.Type.extend({ + //Passing in a name registers this chart in the Chart namespace + name: "PolarArea", + //Providing a defaults will also register the deafults in the chart namespace + defaults : defaultConfig, + //Initialize is fired when the chart is initialized - Data is passed in as a parameter + //Config is automatically merged by the core of Chart.js, and is available at this.options + initialize: function(data){ + this.segments = []; + //Declare segment class as a chart instance specific class, so it can share props for this instance + this.SegmentArc = Chart.Arc.extend({ + showStroke : this.options.segmentShowStroke, + strokeWidth : this.options.segmentStrokeWidth, + strokeColor : this.options.segmentStrokeColor, + ctx : this.chart.ctx, + innerRadius : 0, + x : this.chart.width/2, + y : this.chart.height/2 + }); + this.scale = new Chart.RadialScale({ + display: this.options.showScale, + fontStyle: this.options.scaleFontStyle, + fontSize: this.options.scaleFontSize, + fontFamily: this.options.scaleFontFamily, + fontColor: this.options.scaleFontColor, + showLabels: this.options.scaleShowLabels, + showLabelBackdrop: this.options.scaleShowLabelBackdrop, + backdropColor: this.options.scaleBackdropColor, + backdropPaddingY : this.options.scaleBackdropPaddingY, + backdropPaddingX: this.options.scaleBackdropPaddingX, + lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0, + lineColor: this.options.scaleLineColor, + lineArc: true, + width: this.chart.width, + height: this.chart.height, + xCenter: this.chart.width/2, + yCenter: this.chart.height/2, + ctx : this.chart.ctx, + templateString: this.options.scaleLabel, + valuesCount: data.length + }); + + this.updateScaleRange(data); + + this.scale.update(); + + helpers.each(data,function(segment,index){ + this.addData(segment,index,true); + },this); + + //Set up tooltip events on the chart + if (this.options.showTooltips){ + helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ + var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : []; + helpers.each(this.segments,function(segment){ + segment.restore(["fillColor"]); + }); + helpers.each(activeSegments,function(activeSegment){ + activeSegment.fillColor = activeSegment.highlightColor; + }); + this.showTooltip(activeSegments); + }); + } + + this.render(); + }, + getSegmentsAtEvent : function(e){ + var segmentsArray = []; + + var location = helpers.getRelativePosition(e); + + helpers.each(this.segments,function(segment){ + if (segment.inRange(location.x,location.y)) segmentsArray.push(segment); + },this); + return segmentsArray; + }, + addData : function(segment, atIndex, silent){ + var index = atIndex || this.segments.length; + + this.segments.splice(index, 0, new this.SegmentArc({ + fillColor: segment.color, + highlightColor: segment.highlight || segment.color, + label: segment.label, + value: segment.value, + outerRadius: (this.options.animateScale) ? 0 : this.scale.calculateCenterOffset(segment.value), + circumference: (this.options.animateRotate) ? 0 : this.scale.getCircumference(), + startAngle: Math.PI * 1.5 + })); + if (!silent){ + this.reflow(); + this.update(); + } + }, + removeData: function(atIndex){ + var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1; + this.segments.splice(indexToDelete, 1); + this.reflow(); + this.update(); + }, + calculateTotal: function(data){ + this.total = 0; + helpers.each(data,function(segment){ + this.total += segment.value; + },this); + this.scale.valuesCount = this.segments.length; + }, + updateScaleRange: function(datapoints){ + var valuesArray = []; + helpers.each(datapoints,function(segment){ + valuesArray.push(segment.value); + }); + + var scaleSizes = (this.options.scaleOverride) ? + { + steps: this.options.scaleSteps, + stepValue: this.options.scaleStepWidth, + min: this.options.scaleStartValue, + max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth) + } : + helpers.calculateScaleRange( + valuesArray, + helpers.min([this.chart.width, this.chart.height])/2, + this.options.scaleFontSize, + this.options.scaleBeginAtZero, + this.options.scaleIntegersOnly + ); + + helpers.extend( + this.scale, + scaleSizes, + { + size: helpers.min([this.chart.width, this.chart.height]), + xCenter: this.chart.width/2, + yCenter: this.chart.height/2 + } + ); + + }, + update : function(){ + this.calculateTotal(this.segments); + + helpers.each(this.segments,function(segment){ + segment.save(); + }); + this.render(); + }, + reflow : function(){ + helpers.extend(this.SegmentArc.prototype,{ + x : this.chart.width/2, + y : this.chart.height/2 + }); + this.updateScaleRange(this.segments); + this.scale.update(); + + helpers.extend(this.scale,{ + xCenter: this.chart.width/2, + yCenter: this.chart.height/2 + }); + + helpers.each(this.segments, function(segment){ + segment.update({ + outerRadius : this.scale.calculateCenterOffset(segment.value) + }); + }, this); + + }, + draw : function(ease){ + var easingDecimal = ease || 1; + //Clear & draw the canvas + this.clear(); + helpers.each(this.segments,function(segment, index){ + segment.transition({ + circumference : this.scale.getCircumference(), + outerRadius : this.scale.calculateCenterOffset(segment.value) + },easingDecimal); + + segment.endAngle = segment.startAngle + segment.circumference; + + // If we've removed the first segment we need to set the first one to + // start at the top. + if (index === 0){ + segment.startAngle = Math.PI * 1.5; + } + + //Check to see if it's the last segment, if not get the next and update the start angle + if (index < this.segments.length - 1){ + this.segments[index+1].startAngle = segment.endAngle; + } + segment.draw(); + }, this); + this.scale.draw(); + } + }); + +}).call(this); \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Radar.js b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Radar.js new file mode 100755 index 0000000..134fd2d --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/chart.js/src/Chart.Radar.js @@ -0,0 +1,343 @@ +(function(){ + "use strict"; + + var root = this, + Chart = root.Chart, + helpers = Chart.helpers; + + + + Chart.Type.extend({ + name: "Radar", + defaults:{ + //Boolean - Whether to show lines for each scale point + scaleShowLine : true, + + //Boolean - Whether we show the angle lines out of the radar + angleShowLineOut : true, + + //Boolean - Whether to show labels on the scale + scaleShowLabels : false, + + // Boolean - Whether the scale should begin at zero + scaleBeginAtZero : true, + + //String - Colour of the angle line + angleLineColor : "rgba(0,0,0,.1)", + + //Number - Pixel width of the angle line + angleLineWidth : 1, + + //String - Point label font declaration + pointLabelFontFamily : "'Arial'", + + //String - Point label font weight + pointLabelFontStyle : "normal", + + //Number - Point label font size in pixels + pointLabelFontSize : 10, + + //String - Point label font colour + pointLabelFontColor : "#666", + + //Boolean - Whether to show a dot for each point + pointDot : true, + + //Number - Radius of each point dot in pixels + pointDotRadius : 3, + + //Number - Pixel width of point dot stroke + pointDotStrokeWidth : 1, + + //Number - amount extra to add to the radius to cater for hit detection outside the drawn point + pointHitDetectionRadius : 20, + + //Boolean - Whether to show a stroke for datasets + datasetStroke : true, + + //Number - Pixel width of dataset stroke + datasetStrokeWidth : 2, + + //Boolean - Whether to fill the dataset with a colour + datasetFill : true, + + //String - A legend template + legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
" + + }, + + initialize: function(data){ + this.PointClass = Chart.Point.extend({ + strokeWidth : this.options.pointDotStrokeWidth, + radius : this.options.pointDotRadius, + display: this.options.pointDot, + hitDetectionRadius : this.options.pointHitDetectionRadius, + ctx : this.chart.ctx + }); + + this.datasets = []; + + this.buildScale(data); + + //Set up tooltip events on the chart + if (this.options.showTooltips){ + helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ + var activePointsCollection = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : []; + + this.eachPoints(function(point){ + point.restore(['fillColor', 'strokeColor']); + }); + helpers.each(activePointsCollection, function(activePoint){ + activePoint.fillColor = activePoint.highlightFill; + activePoint.strokeColor = activePoint.highlightStroke; + }); + + this.showTooltip(activePointsCollection); + }); + } + + //Iterate through each of the datasets, and build this into a property of the chart + helpers.each(data.datasets,function(dataset){ + + var datasetObject = { + label: dataset.label || null, + fillColor : dataset.fillColor, + strokeColor : dataset.strokeColor, + pointColor : dataset.pointColor, + pointStrokeColor : dataset.pointStrokeColor, + points : [] + }; + + this.datasets.push(datasetObject); + + helpers.each(dataset.data,function(dataPoint,index){ + //Add a new point for each piece of data, passing any required data to draw. + var pointPosition; + if (!this.scale.animation){ + pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint)); + } + datasetObject.points.push(new this.PointClass({ + value : dataPoint, + label : data.labels[index], + datasetLabel: dataset.label, + x: (this.options.animation) ? this.scale.xCenter : pointPosition.x, + y: (this.options.animation) ? this.scale.yCenter : pointPosition.y, + strokeColor : dataset.pointStrokeColor, + fillColor : dataset.pointColor, + highlightFill : dataset.pointHighlightFill || dataset.pointColor, + highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor + })); + },this); + + },this); + + this.render(); + }, + eachPoints : function(callback){ + helpers.each(this.datasets,function(dataset){ + helpers.each(dataset.points,callback,this); + },this); + }, + + getPointsAtEvent : function(evt){ + var mousePosition = helpers.getRelativePosition(evt), + fromCenter = helpers.getAngleFromPoint({ + x: this.scale.xCenter, + y: this.scale.yCenter + }, mousePosition); + + var anglePerIndex = (Math.PI * 2) /this.scale.valuesCount, + pointIndex = Math.round((fromCenter.angle - Math.PI * 1.5) / anglePerIndex), + activePointsCollection = []; + + // If we're at the top, make the pointIndex 0 to get the first of the array. + if (pointIndex >= this.scale.valuesCount || pointIndex < 0){ + pointIndex = 0; + } + + if (fromCenter.distance <= this.scale.drawingArea){ + helpers.each(this.datasets, function(dataset){ + activePointsCollection.push(dataset.points[pointIndex]); + }); + } + + return activePointsCollection; + }, + + buildScale : function(data){ + this.scale = new Chart.RadialScale({ + display: this.options.showScale, + fontStyle: this.options.scaleFontStyle, + fontSize: this.options.scaleFontSize, + fontFamily: this.options.scaleFontFamily, + fontColor: this.options.scaleFontColor, + showLabels: this.options.scaleShowLabels, + showLabelBackdrop: this.options.scaleShowLabelBackdrop, + backdropColor: this.options.scaleBackdropColor, + backdropPaddingY : this.options.scaleBackdropPaddingY, + backdropPaddingX: this.options.scaleBackdropPaddingX, + lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0, + lineColor: this.options.scaleLineColor, + angleLineColor : this.options.angleLineColor, + angleLineWidth : (this.options.angleShowLineOut) ? this.options.angleLineWidth : 0, + // Point labels at the edge of each line + pointLabelFontColor : this.options.pointLabelFontColor, + pointLabelFontSize : this.options.pointLabelFontSize, + pointLabelFontFamily : this.options.pointLabelFontFamily, + pointLabelFontStyle : this.options.pointLabelFontStyle, + height : this.chart.height, + width: this.chart.width, + xCenter: this.chart.width/2, + yCenter: this.chart.height/2, + ctx : this.chart.ctx, + templateString: this.options.scaleLabel, + labels: data.labels, + valuesCount: data.datasets[0].data.length + }); + + this.scale.setScaleSize(); + this.updateScaleRange(data.datasets); + this.scale.buildYLabels(); + }, + updateScaleRange: function(datasets){ + var valuesArray = (function(){ + var totalDataArray = []; + helpers.each(datasets,function(dataset){ + if (dataset.data){ + totalDataArray = totalDataArray.concat(dataset.data); + } + else { + helpers.each(dataset.points, function(point){ + totalDataArray.push(point.value); + }); + } + }); + return totalDataArray; + })(); + + + var scaleSizes = (this.options.scaleOverride) ? + { + steps: this.options.scaleSteps, + stepValue: this.options.scaleStepWidth, + min: this.options.scaleStartValue, + max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth) + } : + helpers.calculateScaleRange( + valuesArray, + helpers.min([this.chart.width, this.chart.height])/2, + this.options.scaleFontSize, + this.options.scaleBeginAtZero, + this.options.scaleIntegersOnly + ); + + helpers.extend( + this.scale, + scaleSizes + ); + + }, + addData : function(valuesArray,label){ + //Map the values array for each of the datasets + this.scale.valuesCount++; + helpers.each(valuesArray,function(value,datasetIndex){ + var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value)); + this.datasets[datasetIndex].points.push(new this.PointClass({ + value : value, + label : label, + x: pointPosition.x, + y: pointPosition.y, + strokeColor : this.datasets[datasetIndex].pointStrokeColor, + fillColor : this.datasets[datasetIndex].pointColor + })); + },this); + + this.scale.labels.push(label); + + this.reflow(); + + this.update(); + }, + removeData : function(){ + this.scale.valuesCount--; + this.scale.labels.shift(); + helpers.each(this.datasets,function(dataset){ + dataset.points.shift(); + },this); + this.reflow(); + this.update(); + }, + update : function(){ + this.eachPoints(function(point){ + point.save(); + }); + this.reflow(); + this.render(); + }, + reflow: function(){ + helpers.extend(this.scale, { + width : this.chart.width, + height: this.chart.height, + size : helpers.min([this.chart.width, this.chart.height]), + xCenter: this.chart.width/2, + yCenter: this.chart.height/2 + }); + this.updateScaleRange(this.datasets); + this.scale.setScaleSize(); + this.scale.buildYLabels(); + }, + draw : function(ease){ + var easeDecimal = ease || 1, + ctx = this.chart.ctx; + this.clear(); + this.scale.draw(); + + helpers.each(this.datasets,function(dataset){ + + //Transition each point first so that the line and point drawing isn't out of sync + helpers.each(dataset.points,function(point,index){ + if (point.hasValue()){ + point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal); + } + },this); + + + + //Draw the line between all the points + ctx.lineWidth = this.options.datasetStrokeWidth; + ctx.strokeStyle = dataset.strokeColor; + ctx.beginPath(); + helpers.each(dataset.points,function(point,index){ + if (index === 0){ + ctx.moveTo(point.x,point.y); + } + else{ + ctx.lineTo(point.x,point.y); + } + },this); + ctx.closePath(); + ctx.stroke(); + + ctx.fillStyle = dataset.fillColor; + ctx.fill(); + + //Now draw the points over the line + //A little inefficient double looping, but better than the line + //lagging behind the point positions + helpers.each(dataset.points,function(point){ + if (point.hasValue()){ + point.draw(); + } + }); + + },this); + + } + + }); + + + + + +}).call(this); \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/flotr2.nolibs.js b/gridplatform/bootstrap/static/bootstrap/flotr2.nolibs.js new file mode 100644 index 0000000..dbb0c2d --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/flotr2.nolibs.js @@ -0,0 +1,5865 @@ +/** + * Flotr2 (c) 2012 Carl Sutherland + * MIT License + * Special thanks to: + * Flotr: http://code.google.com/p/flotr/ (fork) + * Flot: https://github.com/flot/flot (original fork) + */ +(function () { + +var + global = this, + previousFlotr = this.Flotr, + Flotr; + +Flotr = { + _: _, + bean: bean, + isIphone: /iphone/i.test(navigator.userAgent), + isIE: (navigator.appVersion.indexOf("MSIE") != -1 ? parseFloat(navigator.appVersion.split("MSIE")[1]) : false), + + /** + * An object of the registered graph types. Use Flotr.addType(type, object) + * to add your own type. + */ + graphTypes: {}, + + /** + * The list of the registered plugins + */ + plugins: {}, + + /** + * Can be used to add your own chart type. + * @param {String} name - Type of chart, like 'pies', 'bars' etc. + * @param {String} graphType - The object containing the basic drawing functions (draw, etc) + */ + addType: function(name, graphType){ + Flotr.graphTypes[name] = graphType; + Flotr.defaultOptions[name] = graphType.options || {}; + Flotr.defaultOptions.defaultType = Flotr.defaultOptions.defaultType || name; + }, + + /** + * Can be used to add a plugin + * @param {String} name - The name of the plugin + * @param {String} plugin - The object containing the plugin's data (callbacks, options, function1, function2, ...) + */ + addPlugin: function(name, plugin){ + Flotr.plugins[name] = plugin; + Flotr.defaultOptions[name] = plugin.options || {}; + }, + + /** + * Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha. + * You could also draw graphs by directly calling Flotr.Graph(element, data, options). + * @param {Element} el - element to insert the graph into + * @param {Object} data - an array or object of dataseries + * @param {Object} options - an object containing options + * @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph + * @return {Object} returns a new graph object and of course draws the graph. + */ + draw: function(el, data, options, GraphKlass){ + GraphKlass = GraphKlass || Flotr.Graph; + return new GraphKlass(el, data, options); + }, + + /** + * Recursively merges two objects. + * @param {Object} src - source object (likely the object with the least properties) + * @param {Object} dest - destination object (optional, object with the most properties) + * @return {Object} recursively merged Object + * @TODO See if we can't remove this. + */ + merge: function(src, dest){ + var i, v, result = dest || {}; + + for (i in src) { + v = src[i]; + if (v && typeof(v) === 'object') { + if (v.constructor === Array) { + result[i] = this._.clone(v); + } else if ( + v.constructor !== RegExp && + !this._.isElement(v) && + !v.jquery + ) { + result[i] = Flotr.merge(v, (dest ? dest[i] : undefined)); + } else { + result[i] = v; + } + } else { + result[i] = v; + } + } + + return result; + }, + + /** + * Recursively clones an object. + * @param {Object} object - The object to clone + * @return {Object} the clone + * @TODO See if we can't remove this. + */ + clone: function(object){ + return Flotr.merge(object, {}); + }, + + /** + * Function calculates the ticksize and returns it. + * @param {Integer} noTicks - number of ticks + * @param {Integer} min - lower bound integer value for the current axis + * @param {Integer} max - upper bound integer value for the current axis + * @param {Integer} decimals - number of decimals for the ticks + * @return {Integer} returns the ticksize in pixels + */ + getTickSize: function(noTicks, min, max, decimals){ + var delta = (max - min) / noTicks, + magn = Flotr.getMagnitude(delta), + tickSize = 10, + norm = delta / magn; // Norm is between 1.0 and 10.0. + + if(norm < 1.5) tickSize = 1; + else if(norm < 2.25) tickSize = 2; + else if(norm < 3) tickSize = ((decimals === 0) ? 2 : 2.5); + else if(norm < 7.5) tickSize = 5; + + return tickSize * magn; + }, + + /** + * Default tick formatter. + * @param {String, Integer} val - tick value integer + * @param {Object} axisOpts - the axis' options + * @return {String} formatted tick string + */ + defaultTickFormatter: function(val, axisOpts){ + return val+''; + }, + + /** + * Formats the mouse tracker values. + * @param {Object} obj - Track value Object {x:..,y:..} + * @return {String} Formatted track string + */ + defaultTrackFormatter: function(obj){ + return '('+obj.x+', '+obj.y+')'; + }, + + /** + * Utility function to convert file size values in bytes to kB, MB, ... + * @param value {Number} - The value to convert + * @param precision {Number} - The number of digits after the comma (default: 2) + * @param base {Number} - The base (default: 1000) + */ + engineeringNotation: function(value, precision, base){ + var sizes = ['Y','Z','E','P','T','G','M','k',''], + fractionSizes = ['y','z','a','f','p','n','µ','m',''], + total = sizes.length; + + base = base || 1000; + precision = Math.pow(10, precision || 2); + + if (value === 0) return 0; + + if (value > 1) { + while (total-- && (value >= base)) value /= base; + } + else { + sizes = fractionSizes; + total = sizes.length; + while (total-- && (value < 1)) value *= base; + } + + return (Math.round(value * precision) / precision) + sizes[total]; + }, + + /** + * Returns the magnitude of the input value. + * @param {Integer, Float} x - integer or float value + * @return {Integer, Float} returns the magnitude of the input value + */ + getMagnitude: function(x){ + return Math.pow(10, Math.floor(Math.log(x) / Math.LN10)); + }, + toPixel: function(val){ + return Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val); + }, + toRad: function(angle){ + return -angle * (Math.PI/180); + }, + floorInBase: function(n, base) { + return base * Math.floor(n / base); + }, + drawText: function(ctx, text, x, y, style) { + if (!ctx.fillText) { + ctx.drawText(text, x, y, style); + return; + } + + style = this._.extend({ + size: Flotr.defaultOptions.fontSize, + color: '#000000', + textAlign: 'left', + textBaseline: 'bottom', + weight: 1, + angle: 0 + }, style); + + ctx.save(); + ctx.translate(x, y); + ctx.rotate(style.angle); + ctx.fillStyle = style.color; + ctx.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif"; + ctx.textAlign = style.textAlign; + ctx.textBaseline = style.textBaseline; + ctx.fillText(text, 0, 0); + ctx.restore(); + }, + getBestTextAlign: function(angle, style) { + style = style || {textAlign: 'center', textBaseline: 'middle'}; + angle += Flotr.getTextAngleFromAlign(style); + + if (Math.abs(Math.cos(angle)) > 10e-3) + style.textAlign = (Math.cos(angle) > 0 ? 'right' : 'left'); + + if (Math.abs(Math.sin(angle)) > 10e-3) + style.textBaseline = (Math.sin(angle) > 0 ? 'top' : 'bottom'); + + return style; + }, + alignTable: { + 'right middle' : 0, + 'right top' : Math.PI/4, + 'center top' : Math.PI/2, + 'left top' : 3*(Math.PI/4), + 'left middle' : Math.PI, + 'left bottom' : -3*(Math.PI/4), + 'center bottom': -Math.PI/2, + 'right bottom' : -Math.PI/4, + 'center middle': 0 + }, + getTextAngleFromAlign: function(style) { + return Flotr.alignTable[style.textAlign+' '+style.textBaseline] || 0; + }, + noConflict : function () { + global.Flotr = previousFlotr; + return this; + } +}; + +global.Flotr = Flotr; + +})(); + +/** + * Flotr Defaults + */ +Flotr.defaultOptions = { + colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated. + ieBackgroundColor: '#FFFFFF', // Background color for excanvas clipping + title: null, // => The graph's title + subtitle: null, // => The graph's subtitle + shadowSize: 4, // => size of the 'fake' shadow + defaultType: null, // => default series type + HtmlText: true, // => wether to draw the text using HTML or on the canvas + fontColor: '#545454', // => default font color + fontSize: 7.5, // => canvas' text font size + resolution: 1, // => resolution of the graph, to have printer-friendly graphs ! + parseFloat: true, // => whether to preprocess data for floats (ie. if input is string) + preventDefault: true, // => preventDefault by default for mobile events. Turn off to enable scroll. + xaxis: { + ticks: null, // => format: either [1, 3] or [[1, 'a'], 3] + minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3] + showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise + showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide + labelsAngle: 0, // => labels' angle, in degrees + title: null, // => axis title + titleAngle: 0, // => axis title's angle, in degrees + noTicks: 5, // => number of ticks for automagically generated ticks + minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks + tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string + tickDecimals: null, // => no. of decimals, null means auto + min: null, // => min. value to show, null means set automatically + max: null, // => max. value to show, null means set automatically + autoscale: false, // => Turns autoscaling on with true + autoscaleMargin: 0, // => margin in % to add if auto-setting min/max + color: null, // => color of the ticks + mode: 'normal', // => can be 'time' or 'normal' + timeFormat: null, + timeMode:'UTC', // => For UTC time ('local' for local time). + timeUnit:'millisecond',// => Unit for time (millisecond, second, minute, hour, day, month, year) + scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic' + base: Math.E, + titleAlign: 'center', + margin: true // => Turn off margins with false + }, + x2axis: {}, + yaxis: { + ticks: null, // => format: either [1, 3] or [[1, 'a'], 3] + minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3] + showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise + showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide + labelsAngle: 0, // => labels' angle, in degrees + title: null, // => axis title + titleAngle: 90, // => axis title's angle, in degrees + noTicks: 5, // => number of ticks for automagically generated ticks + minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks + tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string + tickDecimals: null, // => no. of decimals, null means auto + min: null, // => min. value to show, null means set automatically + max: null, // => max. value to show, null means set automatically + autoscale: false, // => Turns autoscaling on with true + autoscaleMargin: 0, // => margin in % to add if auto-setting min/max + color: null, // => The color of the ticks + scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic' + base: Math.E, + titleAlign: 'center', + margin: true // => Turn off margins with false + }, + y2axis: { + titleAngle: 270 + }, + grid: { + color: '#545454', // => primary color used for outline and labels + backgroundColor: null, // => null for transparent, else color + backgroundImage: null, // => background image. String or object with src, left and top + watermarkAlpha: 0.4, // => + tickColor: '#DDDDDD', // => color used for the ticks + labelMargin: 3, // => margin in pixels + verticalLines: true, // => whether to show gridlines in vertical direction + minorVerticalLines: null, // => whether to show gridlines for minor ticks in vertical dir. + horizontalLines: true, // => whether to show gridlines in horizontal direction + minorHorizontalLines: null, // => whether to show gridlines for minor ticks in horizontal dir. + outlineWidth: 1, // => width of the grid outline/border in pixels + outline : 'nsew', // => walls of the outline to display + circular: false // => if set to true, the grid will be circular, must be used when radars are drawn + }, + mouse: { + track: false, // => true to track the mouse, no tracking otherwise + trackAll: false, + position: 'se', // => position of the value box (default south-east). False disables. + relative: false, // => next to the mouse cursor + trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box + margin: 5, // => margin in pixels of the valuebox + lineColor: '#FF3F19', // => line color of points that are drawn when mouse comes near a value of a series + trackDecimals: 1, // => decimals for the track values + sensibility: 2, // => the lower this number, the more precise you have to aim to show a value + trackY: true, // => whether or not to track the mouse in the y axis + radius: 3, // => radius of the track point + fillColor: null, // => color to fill our select bar with only applies to bar and similar graphs (only bars for now) + fillOpacity: 0.4 // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill + } +}; + +/** + * Flotr Color + */ + +(function () { + +var + _ = Flotr._; + +// Constructor +function Color (r, g, b, a) { + this.rgba = ['r','g','b','a']; + var x = 4; + while(-1<--x){ + this[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0); + } + this.normalize(); +} + +// Constants +var COLOR_NAMES = { + aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255], + brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169], + darkgreen:[0,100,0],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], + darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130], + khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144], + lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255], + maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128], + violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0] +}; + +Color.prototype = { + scale: function(rf, gf, bf, af){ + var x = 4; + while (-1 < --x) { + if (!_.isUndefined(arguments[x])) this[this.rgba[x]] *= arguments[x]; + } + return this.normalize(); + }, + alpha: function(alpha) { + if (!_.isUndefined(alpha) && !_.isNull(alpha)) { + this.a = alpha; + } + return this.normalize(); + }, + clone: function(){ + return new Color(this.r, this.b, this.g, this.a); + }, + limit: function(val,minVal,maxVal){ + return Math.max(Math.min(val, maxVal), minVal); + }, + normalize: function(){ + var limit = this.limit; + this.r = limit(parseInt(this.r, 10), 0, 255); + this.g = limit(parseInt(this.g, 10), 0, 255); + this.b = limit(parseInt(this.b, 10), 0, 255); + this.a = limit(this.a, 0, 1); + return this; + }, + distance: function(color){ + if (!color) return; + color = new Color.parse(color); + var dist = 0, x = 3; + while(-1<--x){ + dist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]); + } + return dist; + }, + toString: function(){ + return (this.a >= 1.0) ? 'rgb('+[this.r,this.g,this.b].join(',')+')' : 'rgba('+[this.r,this.g,this.b,this.a].join(',')+')'; + }, + contrast: function () { + var + test = 1 - ( 0.299 * this.r + 0.587 * this.g + 0.114 * this.b) / 255; + return (test < 0.5 ? '#000000' : '#ffffff'); + } +}; + +_.extend(Color, { + /** + * Parses a color string and returns a corresponding Color. + * The different tests are in order of probability to improve speed. + * @param {String, Color} str - string thats representing a color + * @return {Color} returns a Color object or false + */ + parse: function(color){ + if (color instanceof Color) return color; + + var result; + + // #a0b1c2 + if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))) + return new Color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)); + + // rgb(num,num,num) + if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))) + return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10)); + + // #fff + if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))) + return new Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)); + + // rgba(num,num,num,num) + if((result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(color))) + return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10), parseFloat(result[4])); + + // rgb(num%,num%,num%) + if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))) + return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55); + + // rgba(num%,num%,num%,num) + if((result = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(color))) + return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4])); + + // Otherwise, we're most likely dealing with a named color. + var name = (color+'').replace(/^\s*([\S\s]*?)\s*$/, '$1').toLowerCase(); + if(name == 'transparent'){ + return new Color(255, 255, 255, 0); + } + return (result = COLOR_NAMES[name]) ? new Color(result[0], result[1], result[2]) : new Color(0, 0, 0, 0); + }, + + /** + * Process color and options into color style. + */ + processColor: function(color, options) { + + var opacity = options.opacity; + if (!color) return 'rgba(0, 0, 0, 0)'; + if (color instanceof Color) return color.alpha(opacity).toString(); + if (_.isString(color)) return Color.parse(color).alpha(opacity).toString(); + + var grad = color.colors ? color : {colors: color}; + + if (!options.ctx) { + if (!_.isArray(grad.colors)) return 'rgba(0, 0, 0, 0)'; + return Color.parse(_.isArray(grad.colors[0]) ? grad.colors[0][1] : grad.colors[0]).alpha(opacity).toString(); + } + grad = _.extend({start: 'top', end: 'bottom'}, grad); + + if (/top/i.test(grad.start)) options.x1 = 0; + if (/left/i.test(grad.start)) options.y1 = 0; + if (/bottom/i.test(grad.end)) options.x2 = 0; + if (/right/i.test(grad.end)) options.y2 = 0; + + var i, c, stop, gradient = options.ctx.createLinearGradient(options.x1, options.y1, options.x2, options.y2); + for (i = 0; i < grad.colors.length; i++) { + c = grad.colors[i]; + if (_.isArray(c)) { + stop = c[0]; + c = c[1]; + } + else stop = i / (grad.colors.length-1); + gradient.addColorStop(stop, Color.parse(c).alpha(opacity)); + } + return gradient; + } +}); + +Flotr.Color = Color; + +})(); + +/** + * Flotr Date + */ +Flotr.Date = { + + set : function (date, name, mode, value) { + mode = mode || 'UTC'; + name = 'set' + (mode === 'UTC' ? 'UTC' : '') + name; + date[name](value); + }, + + get : function (date, name, mode) { + mode = mode || 'UTC'; + name = 'get' + (mode === 'UTC' ? 'UTC' : '') + name; + return date[name](); + }, + + format: function(d, format, mode) { + if (!d) return; + + // We should maybe use an "official" date format spec, like PHP date() or ColdFusion + // http://fr.php.net/manual/en/function.date.php + // http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_c-d_29.html + var + get = this.get, + tokens = { + h: get(d, 'Hours', mode).toString(), + H: leftPad(get(d, 'Hours', mode)), + M: leftPad(get(d, 'Minutes', mode)), + S: leftPad(get(d, 'Seconds', mode)), + s: get(d, 'Milliseconds', mode), + d: get(d, 'Date', mode).toString(), + m: (get(d, 'Month', mode) + 1).toString(), + y: get(d, 'FullYear', mode).toString(), + b: Flotr.Date.monthNames[get(d, 'Month', mode)] + }; + + function leftPad(n){ + n += ''; + return n.length == 1 ? "0" + n : n; + } + + var r = [], c, + escape = false; + + for (var i = 0; i < format.length; ++i) { + c = format.charAt(i); + + if (escape) { + r.push(tokens[c] || c); + escape = false; + } + else if (c == "%") + escape = true; + else + r.push(c); + } + return r.join(''); + }, + getFormat: function(time, span) { + var tu = Flotr.Date.timeUnits; + if (time < tu.second) return "%h:%M:%S.%s"; + else if (time < tu.minute) return "%h:%M:%S"; + else if (time < tu.day) return (span < 2 * tu.day) ? "%h:%M" : "%b %d %h:%M"; + else if (time < tu.month) return "%b %d"; + else if (time < tu.year) return (span < tu.year) ? "%b" : "%b %y"; + else return "%y"; + }, + formatter: function (v, axis) { + var + options = axis.options, + scale = Flotr.Date.timeUnits[options.timeUnit], + d = new Date(v * scale); + + // first check global format + if (axis.options.timeFormat) + return Flotr.Date.format(d, options.timeFormat, options.timeMode); + + var span = (axis.max - axis.min) * scale, + t = axis.tickSize * Flotr.Date.timeUnits[axis.tickUnit]; + + return Flotr.Date.format(d, Flotr.Date.getFormat(t, span), options.timeMode); + }, + generator: function(axis) { + + var + set = this.set, + get = this.get, + timeUnits = this.timeUnits, + spec = this.spec, + options = axis.options, + mode = options.timeMode, + scale = timeUnits[options.timeUnit], + min = axis.min * scale, + max = axis.max * scale, + delta = (max - min) / options.noTicks, + ticks = [], + tickSize = axis.tickSize, + tickUnit, + formatter, i; + + // Use custom formatter or time tick formatter + formatter = (options.tickFormatter === Flotr.defaultTickFormatter ? + this.formatter : options.tickFormatter + ); + + for (i = 0; i < spec.length - 1; ++i) { + var d = spec[i][0] * timeUnits[spec[i][1]]; + if (delta < (d + spec[i+1][0] * timeUnits[spec[i+1][1]]) / 2 && d >= tickSize) + break; + } + tickSize = spec[i][0]; + tickUnit = spec[i][1]; + + // special-case the possibility of several years + if (tickUnit == "year") { + tickSize = Flotr.getTickSize(options.noTicks*timeUnits.year, min, max, 0); + + // Fix for 0.5 year case + if (tickSize == 0.5) { + tickUnit = "month"; + tickSize = 6; + } + } + + axis.tickUnit = tickUnit; + axis.tickSize = tickSize; + + var step = tickSize * timeUnits[tickUnit]; + d = new Date(min); + + function setTick (name) { + set(d, name, mode, Flotr.floorInBase( + get(d, name, mode), tickSize + )); + } + + switch (tickUnit) { + case "millisecond": setTick('Milliseconds'); break; + case "second": setTick('Seconds'); break; + case "minute": setTick('Minutes'); break; + case "hour": setTick('Hours'); break; + case "month": setTick('Month'); break; + case "year": setTick('FullYear'); break; + } + + // reset smaller components + if (step >= timeUnits.second) set(d, 'Milliseconds', mode, 0); + if (step >= timeUnits.minute) set(d, 'Seconds', mode, 0); + if (step >= timeUnits.hour) set(d, 'Minutes', mode, 0); + if (step >= timeUnits.day) set(d, 'Hours', mode, 0); + if (step >= timeUnits.day * 4) set(d, 'Date', mode, 1); + if (step >= timeUnits.year) set(d, 'Month', mode, 0); + + var carry = 0, v = NaN, prev; + do { + prev = v; + v = d.getTime(); + ticks.push({ v: v / scale, label: formatter(v / scale, axis) }); + if (tickUnit == "month") { + if (tickSize < 1) { + /* a bit complicated - we'll divide the month up but we need to take care of fractions + so we don't end up in the middle of a day */ + set(d, 'Date', mode, 1); + var start = d.getTime(); + set(d, 'Month', mode, get(d, 'Month', mode) + 1); + var end = d.getTime(); + d.setTime(v + carry * timeUnits.hour + (end - start) * tickSize); + carry = get(d, 'Hours', mode); + set(d, 'Hours', mode, 0); + } + else + set(d, 'Month', mode, get(d, 'Month', mode) + tickSize); + } + else if (tickUnit == "year") { + set(d, 'FullYear', mode, get(d, 'FullYear', mode) + tickSize); + } + else + d.setTime(v + step); + + } while (v < max && v != prev); + + return ticks; + }, + timeUnits: { + millisecond: 1, + second: 1000, + minute: 1000 * 60, + hour: 1000 * 60 * 60, + day: 1000 * 60 * 60 * 24, + month: 1000 * 60 * 60 * 24 * 30, + year: 1000 * 60 * 60 * 24 * 365.2425 + }, + // the allowed tick sizes, after 1 year we use an integer algorithm + spec: [ + [1, "millisecond"], [20, "millisecond"], [50, "millisecond"], [100, "millisecond"], [200, "millisecond"], [500, "millisecond"], + [1, "second"], [2, "second"], [5, "second"], [10, "second"], [30, "second"], + [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], [30, "minute"], + [1, "hour"], [2, "hour"], [4, "hour"], [8, "hour"], [12, "hour"], + [1, "day"], [2, "day"], [3, "day"], + [0.25, "month"], [0.5, "month"], [1, "month"], [2, "month"], [3, "month"], [6, "month"], + [1, "year"] + ], + monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] +}; + +(function () { + +var _ = Flotr._; + +function getEl (el) { + return (el && el.jquery) ? el[0] : el; +} + +Flotr.DOM = { + addClass: function(element, name){ + element = getEl(element); + var classList = (element.className ? element.className : ''); + if (_.include(classList.split(/\s+/g), name)) return; + element.className = (classList ? classList + ' ' : '') + name; + }, + /** + * Create an element. + */ + create: function(tag){ + return document.createElement(tag); + }, + node: function(html) { + var div = Flotr.DOM.create('div'), n; + div.innerHTML = html; + n = div.children[0]; + div.innerHTML = ''; + return n; + }, + /** + * Remove all children. + */ + empty: function(element){ + element = getEl(element); + element.innerHTML = ''; + /* + if (!element) return; + _.each(element.childNodes, function (e) { + Flotr.DOM.empty(e); + element.removeChild(e); + }); + */ + }, + remove: function (element) { + element = getEl(element); + element.parentNode.removeChild(element); + }, + hide: function(element){ + element = getEl(element); + Flotr.DOM.setStyles(element, {display:'none'}); + }, + /** + * Insert a child. + * @param {Element} element + * @param {Element|String} Element or string to be appended. + */ + insert: function(element, child){ + element = getEl(element); + if(_.isString(child)) + element.innerHTML += child; + else if (_.isElement(child)) + element.appendChild(child); + }, + // @TODO find xbrowser implementation + opacity: function(element, opacity) { + element = getEl(element); + element.style.opacity = opacity; + }, + position: function(element, p){ + element = getEl(element); + if (!element.offsetParent) + return {left: (element.offsetLeft || 0), top: (element.offsetTop || 0)}; + + p = this.position(element.offsetParent); + p.left += element.offsetLeft; + p.top += element.offsetTop; + return p; + }, + removeClass: function(element, name) { + var classList = (element.className ? element.className : ''); + element = getEl(element); + element.className = _.filter(classList.split(/\s+/g), function (c) { + if (c != name) return true; } + ).join(' '); + }, + setStyles: function(element, o) { + element = getEl(element); + _.each(o, function (value, key) { + element.style[key] = value; + }); + }, + show: function(element){ + element = getEl(element); + Flotr.DOM.setStyles(element, {display:''}); + }, + /** + * Return element size. + */ + size: function(element){ + element = getEl(element); + return { + height : element.offsetHeight, + width : element.offsetWidth }; + } +}; + +})(); + +/** + * Flotr Event Adapter + */ +(function () { +var + F = Flotr, + bean = F.bean; +F.EventAdapter = { + observe: function(object, name, callback) { + bean.add(object, name, callback); + return this; + }, + fire: function(object, name, args) { + bean.fire(object, name, args); + if (typeof(Prototype) != 'undefined') + Event.fire(object, name, args); + // @TODO Someone who uses mootools, add mootools adapter for existing applciations. + return this; + }, + stopObserving: function(object, name, callback) { + bean.remove(object, name, callback); + return this; + }, + eventPointer: function(e) { + if (!F._.isUndefined(e.touches) && e.touches.length > 0) { + return { + x : e.touches[0].pageX, + y : e.touches[0].pageY + }; + } else if (!F._.isUndefined(e.changedTouches) && e.changedTouches.length > 0) { + return { + x : e.changedTouches[0].pageX, + y : e.changedTouches[0].pageY + }; + } else if (e.pageX || e.pageY) { + return { + x : e.pageX, + y : e.pageY + }; + } else if (e.clientX || e.clientY) { + var + d = document, + b = d.body, + de = d.documentElement; + return { + x: e.clientX + b.scrollLeft + de.scrollLeft, + y: e.clientY + b.scrollTop + de.scrollTop + }; + } + } +}; +})(); + +/** + * Text Utilities + */ +(function () { + +var + F = Flotr, + D = F.DOM, + _ = F._, + +Text = function (o) { + this.o = o; +}; + +Text.prototype = { + + dimensions : function (text, canvasStyle, htmlStyle, className) { + + if (!text) return { width : 0, height : 0 }; + + return (this.o.html) ? + this.html(text, this.o.element, htmlStyle, className) : + this.canvas(text, canvasStyle); + }, + + canvas : function (text, style) { + + if (!this.o.textEnabled) return; + style = style || {}; + + var + metrics = this.measureText(text, style), + width = metrics.width, + height = style.size || F.defaultOptions.fontSize, + angle = style.angle || 0, + cosAngle = Math.cos(angle), + sinAngle = Math.sin(angle), + widthPadding = 2, + heightPadding = 6, + bounds; + + bounds = { + width: Math.abs(cosAngle * width) + Math.abs(sinAngle * height) + widthPadding, + height: Math.abs(sinAngle * width) + Math.abs(cosAngle * height) + heightPadding + }; + + return bounds; + }, + + html : function (text, element, style, className) { + + var div = D.create('div'); + + D.setStyles(div, { 'position' : 'absolute', 'top' : '-10000px' }); + D.insert(div, '
' + text + '
'); + D.insert(this.o.element, div); + + return D.size(div); + }, + + measureText : function (text, style) { + + var + context = this.o.ctx, + metrics; + + if (!context.fillText || (F.isIphone && context.measure)) { + return { width : context.measure(text, style)}; + } + + style = _.extend({ + size: F.defaultOptions.fontSize, + weight: 1, + angle: 0 + }, style); + + context.save(); + context.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif"; + metrics = context.measureText(text); + context.restore(); + + return metrics; + } +}; + +Flotr.Text = Text; + +})(); + +/** + * Flotr Graph class that plots a graph on creation. + */ +(function () { + +var + D = Flotr.DOM, + E = Flotr.EventAdapter, + _ = Flotr._, + flotr = Flotr; +/** + * Flotr Graph constructor. + * @param {Element} el - element to insert the graph into + * @param {Object} data - an array or object of dataseries + * @param {Object} options - an object containing options + */ +Graph = function(el, data, options){ +// Let's see if we can get away with out this [JS] +// try { + this._setEl(el); + this._initMembers(); + this._initPlugins(); + + E.fire(this.el, 'flotr:beforeinit', [this]); + + this.data = data; + this.series = flotr.Series.getSeries(data); + this._initOptions(options); + this._initGraphTypes(); + this._initCanvas(); + this._text = new flotr.Text({ + element : this.el, + ctx : this.ctx, + html : this.options.HtmlText, + textEnabled : this.textEnabled + }); + E.fire(this.el, 'flotr:afterconstruct', [this]); + this._initEvents(); + + this.findDataRanges(); + this.calculateSpacing(); + + this.draw(_.bind(function() { + E.fire(this.el, 'flotr:afterinit', [this]); + }, this)); +/* + try { + } catch (e) { + try { + console.error(e); + } catch (e2) {} + }*/ +}; + +function observe (object, name, callback) { + E.observe.apply(this, arguments); + this._handles.push(arguments); + return this; +} + +Graph.prototype = { + + destroy: function () { + E.fire(this.el, 'flotr:destroy'); + _.each(this._handles, function (handle) { + E.stopObserving.apply(this, handle); + }); + this._handles = []; + this.el.graph = null; + }, + + observe : observe, + + /** + * @deprecated + */ + _observe : observe, + + processColor: function(color, options){ + var o = { x1: 0, y1: 0, x2: this.plotWidth, y2: this.plotHeight, opacity: 1, ctx: this.ctx }; + _.extend(o, options); + return flotr.Color.processColor(color, o); + }, + /** + * Function determines the min and max values for the xaxis and yaxis. + * + * TODO logarithmic range validation (consideration of 0) + */ + findDataRanges: function(){ + var a = this.axes, + xaxis, yaxis, range; + + _.each(this.series, function (series) { + range = series.getRange(); + if (range) { + xaxis = series.xaxis; + yaxis = series.yaxis; + xaxis.datamin = Math.min(range.xmin, xaxis.datamin); + xaxis.datamax = Math.max(range.xmax, xaxis.datamax); + yaxis.datamin = Math.min(range.ymin, yaxis.datamin); + yaxis.datamax = Math.max(range.ymax, yaxis.datamax); + xaxis.used = (xaxis.used || range.xused); + yaxis.used = (yaxis.used || range.yused); + } + }, this); + + // Check for empty data, no data case (none used) + if (!a.x.used && !a.x2.used) a.x.used = true; + if (!a.y.used && !a.y2.used) a.y.used = true; + + _.each(a, function (axis) { + axis.calculateRange(); + }); + + var + types = _.keys(flotr.graphTypes), + drawn = false; + + _.each(this.series, function (series) { + if (series.hide) return; + _.each(types, function (type) { + if (series[type] && series[type].show) { + this.extendRange(type, series); + drawn = true; + } + }, this); + if (!drawn) { + this.extendRange(this.options.defaultType, series); + } + }, this); + }, + + extendRange : function (type, series) { + if (this[type].extendRange) this[type].extendRange(series, series.data, series[type], this[type]); + if (this[type].extendYRange) this[type].extendYRange(series.yaxis, series.data, series[type], this[type]); + if (this[type].extendXRange) this[type].extendXRange(series.xaxis, series.data, series[type], this[type]); + }, + + /** + * Calculates axis label sizes. + */ + calculateSpacing: function(){ + + var a = this.axes, + options = this.options, + series = this.series, + margin = options.grid.labelMargin, + T = this._text, + x = a.x, + x2 = a.x2, + y = a.y, + y2 = a.y2, + maxOutset = options.grid.outlineWidth, + i, j, l, dim; + + // TODO post refactor, fix this + _.each(a, function (axis) { + axis.calculateTicks(); + axis.calculateTextDimensions(T, options); + }); + + // Title height + dim = T.dimensions( + options.title, + {size: options.fontSize*1.5}, + 'font-size:1em;font-weight:bold;', + 'flotr-title' + ); + this.titleHeight = dim.height; + + // Subtitle height + dim = T.dimensions( + options.subtitle, + {size: options.fontSize}, + 'font-size:smaller;', + 'flotr-subtitle' + ); + this.subtitleHeight = dim.height; + + for(j = 0; j < options.length; ++j){ + if (series[j].points.show){ + maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth/2); + } + } + + var p = this.plotOffset; + if (x.options.margin === false) { + p.bottom = 0; + p.top = 0; + } else + if (x.options.margin === true) { + p.bottom += (options.grid.circular ? 0 : (x.used && x.options.showLabels ? (x.maxLabel.height + margin) : 0)) + + (x.used && x.options.title ? (x.titleSize.height + margin) : 0) + maxOutset; + + p.top += (options.grid.circular ? 0 : (x2.used && x2.options.showLabels ? (x2.maxLabel.height + margin) : 0)) + + (x2.used && x2.options.title ? (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight + maxOutset; + } else { + p.bottom = x.options.margin; + p.top = x.options.margin; + } + if (y.options.margin === false) { + p.left = 0; + p.right = 0; + } else + if (y.options.margin === true) { + p.left += (options.grid.circular ? 0 : (y.used && y.options.showLabels ? (y.maxLabel.width + margin) : 0)) + + (y.used && y.options.title ? (y.titleSize.width + margin) : 0) + maxOutset; + + p.right += (options.grid.circular ? 0 : (y2.used && y2.options.showLabels ? (y2.maxLabel.width + margin) : 0)) + + (y2.used && y2.options.title ? (y2.titleSize.width + margin) : 0) + maxOutset; + } else { + p.left = y.options.margin; + p.right = y.options.margin; + } + + p.top = Math.floor(p.top); // In order the outline not to be blured + + this.plotWidth = this.canvasWidth - p.left - p.right; + this.plotHeight = this.canvasHeight - p.bottom - p.top; + + // TODO post refactor, fix this + x.length = x2.length = this.plotWidth; + y.length = y2.length = this.plotHeight; + y.offset = y2.offset = this.plotHeight; + x.setScale(); + x2.setScale(); + y.setScale(); + y2.setScale(); + }, + /** + * Draws grid, labels, series and outline. + */ + draw: function(after) { + + var + context = this.ctx, + i; + + E.fire(this.el, 'flotr:beforedraw', [this.series, this]); + + if (this.series.length) { + + context.save(); + context.translate(this.plotOffset.left, this.plotOffset.top); + + for (i = 0; i < this.series.length; i++) { + if (!this.series[i].hide) this.drawSeries(this.series[i]); + } + + context.restore(); + this.clip(); + } + + E.fire(this.el, 'flotr:afterdraw', [this.series, this]); + if (after) after(); + }, + /** + * Actually draws the graph. + * @param {Object} series - series to draw + */ + drawSeries: function(series){ + + function drawChart (series, typeKey) { + var options = this.getOptions(series, typeKey); + this[typeKey].draw(options); + } + + var drawn = false; + series = series || this.series; + + _.each(flotr.graphTypes, function (type, typeKey) { + if (series[typeKey] && series[typeKey].show && this[typeKey]) { + drawn = true; + drawChart.call(this, series, typeKey); + } + }, this); + + if (!drawn) drawChart.call(this, series, this.options.defaultType); + }, + + getOptions : function (series, typeKey) { + var + type = series[typeKey], + graphType = this[typeKey], + xaxis = series.xaxis, + yaxis = series.yaxis, + options = { + context : this.ctx, + width : this.plotWidth, + height : this.plotHeight, + fontSize : this.options.fontSize, + fontColor : this.options.fontColor, + textEnabled : this.textEnabled, + htmlText : this.options.HtmlText, + text : this._text, // TODO Is this necessary? + element : this.el, + data : series.data, + color : series.color, + shadowSize : series.shadowSize, + xScale : xaxis.d2p, + yScale : yaxis.d2p, + xInverse : xaxis.p2d, + yInverse : yaxis.p2d + }; + + options = flotr.merge(type, options); + + // Fill + options.fillStyle = this.processColor( + type.fillColor || series.color, + {opacity: type.fillOpacity} + ); + + return options; + }, + /** + * Calculates the coordinates from a mouse event object. + * @param {Event} event - Mouse Event object. + * @return {Object} Object with coordinates of the mouse. + */ + getEventPosition: function (e){ + + var + d = document, + b = d.body, + de = d.documentElement, + axes = this.axes, + plotOffset = this.plotOffset, + lastMousePos = this.lastMousePos, + pointer = E.eventPointer(e), + dx = pointer.x - lastMousePos.pageX, + dy = pointer.y - lastMousePos.pageY, + r, rx, ry; + + if ('ontouchstart' in this.el) { + r = D.position(this.overlay); + rx = pointer.x - r.left - plotOffset.left; + ry = pointer.y - r.top - plotOffset.top; + } else { + r = this.overlay.getBoundingClientRect(); + rx = e.clientX - r.left - plotOffset.left - b.scrollLeft - de.scrollLeft; + ry = e.clientY - r.top - plotOffset.top - b.scrollTop - de.scrollTop; + } + + return { + x: axes.x.p2d(rx), + x2: axes.x2.p2d(rx), + y: axes.y.p2d(ry), + y2: axes.y2.p2d(ry), + relX: rx, + relY: ry, + dX: dx, + dY: dy, + absX: pointer.x, + absY: pointer.y, + pageX: pointer.x, + pageY: pointer.y + }; + }, + /** + * Observes the 'click' event and fires the 'flotr:click' event. + * @param {Event} event - 'click' Event object. + */ + clickHandler: function(event){ + if(this.ignoreClick){ + this.ignoreClick = false; + return this.ignoreClick; + } + E.fire(this.el, 'flotr:click', [this.getEventPosition(event), this]); + }, + /** + * Observes mouse movement over the graph area. Fires the 'flotr:mousemove' event. + * @param {Event} event - 'mousemove' Event object. + */ + mouseMoveHandler: function(event){ + if (this.mouseDownMoveHandler) return; + var pos = this.getEventPosition(event); + E.fire(this.el, 'flotr:mousemove', [event, pos, this]); + this.lastMousePos = pos; + }, + /** + * Observes the 'mousedown' event. + * @param {Event} event - 'mousedown' Event object. + */ + mouseDownHandler: function (event){ + + /* + // @TODO Context menu? + if(event.isRightClick()) { + event.stop(); + + var overlay = this.overlay; + overlay.hide(); + + function cancelContextMenu () { + overlay.show(); + E.stopObserving(document, 'mousemove', cancelContextMenu); + } + E.observe(document, 'mousemove', cancelContextMenu); + return; + } + */ + + if (this.mouseUpHandler) return; + this.mouseUpHandler = _.bind(function (e) { + E.stopObserving(document, 'mouseup', this.mouseUpHandler); + E.stopObserving(document, 'mousemove', this.mouseDownMoveHandler); + this.mouseDownMoveHandler = null; + this.mouseUpHandler = null; + // @TODO why? + //e.stop(); + E.fire(this.el, 'flotr:mouseup', [e, this]); + }, this); + this.mouseDownMoveHandler = _.bind(function (e) { + var pos = this.getEventPosition(e); + E.fire(this.el, 'flotr:mousemove', [event, pos, this]); + this.lastMousePos = pos; + }, this); + E.observe(document, 'mouseup', this.mouseUpHandler); + E.observe(document, 'mousemove', this.mouseDownMoveHandler); + E.fire(this.el, 'flotr:mousedown', [event, this]); + this.ignoreClick = false; + }, + drawTooltip: function(content, x, y, options) { + var mt = this.getMouseTrack(), + style = 'opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;', + p = options.position, + m = options.margin, + plotOffset = this.plotOffset; + + if(x !== null && y !== null){ + if (!options.relative) { // absolute to the canvas + if(p.charAt(0) == 'n') style += 'top:' + (m + plotOffset.top) + 'px;bottom:auto;'; + else if(p.charAt(0) == 's') style += 'bottom:' + (m + plotOffset.bottom) + 'px;top:auto;'; + if(p.charAt(1) == 'e') style += 'right:' + (m + plotOffset.right) + 'px;left:auto;'; + else if(p.charAt(1) == 'w') style += 'left:' + (m + plotOffset.left) + 'px;right:auto;'; + } + else { // relative to the mouse + if(p.charAt(0) == 'n') style += 'bottom:' + (m - plotOffset.top - y + this.canvasHeight) + 'px;top:auto;'; + else if(p.charAt(0) == 's') style += 'top:' + (m + plotOffset.top + y) + 'px;bottom:auto;'; + if(p.charAt(1) == 'e') style += 'left:' + (m + plotOffset.left + x) + 'px;right:auto;'; + else if(p.charAt(1) == 'w') style += 'right:' + (m - plotOffset.left - x + this.canvasWidth) + 'px;left:auto;'; + } + + mt.style.cssText = style; + D.empty(mt); + D.insert(mt, content); + D.show(mt); + } + else { + D.hide(mt); + } + }, + + clip: function (ctx) { + + var + o = this.plotOffset, + w = this.canvasWidth, + h = this.canvasHeight; + + ctx = ctx || this.ctx; + + if ( + flotr.isIE && flotr.isIE < 9 && // IE w/o canvas + !flotr.isFlashCanvas // But not flash canvas + ) { + + // Do not clip excanvas on overlay context + // Allow hits to overflow. + if (ctx === this.octx) { + return; + } + + // Clipping for excanvas :-( + ctx.save(); + ctx.fillStyle = this.processColor(this.options.ieBackgroundColor); + ctx.fillRect(0, 0, w, o.top); + ctx.fillRect(0, 0, o.left, h); + ctx.fillRect(0, h - o.bottom, w, o.bottom); + ctx.fillRect(w - o.right, 0, o.right,h); + ctx.restore(); + } else { + ctx.clearRect(0, 0, w, o.top); + ctx.clearRect(0, 0, o.left, h); + ctx.clearRect(0, h - o.bottom, w, o.bottom); + ctx.clearRect(w - o.right, 0, o.right,h); + } + }, + + _initMembers: function() { + this._handles = []; + this.lastMousePos = {pageX: null, pageY: null }; + this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0}; + this.ignoreClick = true; + this.prevHit = null; + }, + + _initGraphTypes: function() { + _.each(flotr.graphTypes, function(handler, graphType){ + this[graphType] = flotr.clone(handler); + }, this); + }, + + _initEvents: function () { + + var + el = this.el, + touchendHandler, movement, touchend; + + if ('ontouchstart' in el) { + + touchendHandler = _.bind(function (e) { + touchend = true; + E.stopObserving(document, 'touchend', touchendHandler); + E.fire(el, 'flotr:mouseup', [event, this]); + this.multitouches = null; + + if (!movement) { + this.clickHandler(e); + } + }, this); + + this.observe(this.overlay, 'touchstart', _.bind(function (e) { + movement = false; + touchend = false; + this.ignoreClick = false; + + if (e.touches && e.touches.length > 1) { + this.multitouches = e.touches; + } + + E.fire(el, 'flotr:mousedown', [event, this]); + this.observe(document, 'touchend', touchendHandler); + }, this)); + + this.observe(this.overlay, 'touchmove', _.bind(function (e) { + + var pos = this.getEventPosition(e); + + if (this.options.preventDefault) { + e.preventDefault(); + } + + movement = true; + + if (this.multitouches || (e.touches && e.touches.length > 1)) { + this.multitouches = e.touches; + } else { + if (!touchend) { + E.fire(el, 'flotr:mousemove', [event, pos, this]); + } + } + this.lastMousePos = pos; + }, this)); + + } else { + this. + observe(this.overlay, 'mousedown', _.bind(this.mouseDownHandler, this)). + observe(el, 'mousemove', _.bind(this.mouseMoveHandler, this)). + observe(this.overlay, 'click', _.bind(this.clickHandler, this)). + observe(el, 'mouseout', function (e) { + E.fire(el, 'flotr:mouseout', e); + }); + } + }, + + /** + * Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use + * of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements + * are created, the elements are inserted into the container element. + */ + _initCanvas: function(){ + var el = this.el, + o = this.options, + children = el.children, + removedChildren = [], + child, i, + size, style; + + // Empty the el + for (i = children.length; i--;) { + child = children[i]; + if (!this.canvas && child.className === 'flotr-canvas') { + this.canvas = child; + } else if (!this.overlay && child.className === 'flotr-overlay') { + this.overlay = child; + } else { + removedChildren.push(child); + } + } + for (i = removedChildren.length; i--;) { + el.removeChild(removedChildren[i]); + } + + D.setStyles(el, {position: 'relative'}); // For positioning labels and overlay. + size = {}; + size.width = el.clientWidth; + size.height = el.clientHeight; + + if(size.width <= 0 || size.height <= 0 || o.resolution <= 0){ + throw 'Invalid dimensions for plot, width = ' + size.width + ', height = ' + size.height + ', resolution = ' + o.resolution; + } + + // Main canvas for drawing graph types + this.canvas = getCanvas(this.canvas, 'canvas'); + // Overlay canvas for interactive features + this.overlay = getCanvas(this.overlay, 'overlay'); + this.ctx = getContext(this.canvas); + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.octx = getContext(this.overlay); + this.octx.clearRect(0, 0, this.overlay.width, this.overlay.height); + this.canvasHeight = size.height; + this.canvasWidth = size.width; + this.textEnabled = !!this.ctx.drawText || !!this.ctx.fillText; // Enable text functions + + function getCanvas(canvas, name){ + if(!canvas){ + canvas = D.create('canvas'); + if (typeof FlashCanvas != "undefined" && typeof canvas.getContext === 'function') { + FlashCanvas.initElement(canvas); + this.isFlashCanvas = true; + } + canvas.className = 'flotr-'+name; + canvas.style.cssText = 'position:absolute;left:0px;top:0px;'; + D.insert(el, canvas); + } + _.each(size, function(size, attribute){ + D.show(canvas); + if (name == 'canvas' && canvas.getAttribute(attribute) === size) { + return; + } + canvas.setAttribute(attribute, size * o.resolution); + canvas.style[attribute] = size + 'px'; + }); + canvas.context_ = null; // Reset the ExCanvas context + return canvas; + } + + function getContext(canvas){ + if(window.G_vmlCanvasManager) window.G_vmlCanvasManager.initElement(canvas); // For ExCanvas + var context = canvas.getContext('2d'); + if(!window.G_vmlCanvasManager) context.scale(o.resolution, o.resolution); + return context; + } + }, + + _initPlugins: function(){ + // TODO Should be moved to flotr and mixed in. + _.each(flotr.plugins, function(plugin, name){ + _.each(plugin.callbacks, function(fn, c){ + this.observe(this.el, c, _.bind(fn, this)); + }, this); + this[name] = flotr.clone(plugin); + _.each(this[name], function(fn, p){ + if (_.isFunction(fn)) + this[name][p] = _.bind(fn, this); + }, this); + }, this); + }, + + /** + * Sets options and initializes some variables and color specific values, used by the constructor. + * @param {Object} opts - options object + */ + _initOptions: function(opts){ + var options = flotr.clone(flotr.defaultOptions); + options.x2axis = _.extend(_.clone(options.xaxis), options.x2axis); + options.y2axis = _.extend(_.clone(options.yaxis), options.y2axis); + this.options = flotr.merge(opts || {}, options); + + if (this.options.grid.minorVerticalLines === null && + this.options.xaxis.scaling === 'logarithmic') { + this.options.grid.minorVerticalLines = true; + } + if (this.options.grid.minorHorizontalLines === null && + this.options.yaxis.scaling === 'logarithmic') { + this.options.grid.minorHorizontalLines = true; + } + + E.fire(this.el, 'flotr:afterinitoptions', [this]); + + this.axes = flotr.Axis.getAxes(this.options); + + // Initialize some variables used throughout this function. + var assignedColors = [], + colors = [], + ln = this.series.length, + neededColors = this.series.length, + oc = this.options.colors, + usedColors = [], + variation = 0, + c, i, j, s; + + // Collect user-defined colors from series. + for(i = neededColors - 1; i > -1; --i){ + c = this.series[i].color; + if(c){ + --neededColors; + if(_.isNumber(c)) assignedColors.push(c); + else usedColors.push(flotr.Color.parse(c)); + } + } + + // Calculate the number of colors that need to be generated. + for(i = assignedColors.length - 1; i > -1; --i) + neededColors = Math.max(neededColors, assignedColors[i] + 1); + + // Generate needed number of colors. + for(i = 0; colors.length < neededColors;){ + c = (oc.length == i) ? new flotr.Color(100, 100, 100) : flotr.Color.parse(oc[i]); + + // Make sure each serie gets a different color. + var sign = variation % 2 == 1 ? -1 : 1, + factor = 1 + sign * Math.ceil(variation / 2) * 0.2; + c.scale(factor, factor, factor); + + /** + * @todo if we're getting too close to something else, we should probably skip this one + */ + colors.push(c); + + if(++i >= oc.length){ + i = 0; + ++variation; + } + } + + // Fill the options with the generated colors. + for(i = 0, j = 0; i < ln; ++i){ + s = this.series[i]; + + // Assign the color. + if (!s.color){ + s.color = colors[j++].toString(); + }else if(_.isNumber(s.color)){ + s.color = colors[s.color].toString(); + } + + // Every series needs an axis + if (!s.xaxis) s.xaxis = this.axes.x; + if (s.xaxis == 1) s.xaxis = this.axes.x; + else if (s.xaxis == 2) s.xaxis = this.axes.x2; + + if (!s.yaxis) s.yaxis = this.axes.y; + if (s.yaxis == 1) s.yaxis = this.axes.y; + else if (s.yaxis == 2) s.yaxis = this.axes.y2; + + // Apply missing options to the series. + for (var t in flotr.graphTypes){ + s[t] = _.extend(_.clone(this.options[t]), s[t]); + } + s.mouse = _.extend(_.clone(this.options.mouse), s.mouse); + + if (_.isUndefined(s.shadowSize)) s.shadowSize = this.options.shadowSize; + } + }, + + _setEl: function(el) { + if (!el) throw 'The target container doesn\'t exist'; + else if (el.graph instanceof Graph) el.graph.destroy(); + else if (!el.clientWidth) throw 'The target container must be visible'; + + el.graph = this; + this.el = el; + } +}; + +Flotr.Graph = Graph; + +})(); + +/** + * Flotr Axis Library + */ + +(function () { + +var + _ = Flotr._, + LOGARITHMIC = 'logarithmic'; + +function Axis (o) { + + this.orientation = 1; + this.offset = 0; + this.datamin = Number.MAX_VALUE; + this.datamax = -Number.MAX_VALUE; + + _.extend(this, o); +} + + +// Prototype +Axis.prototype = { + + setScale : function () { + var + length = this.length, + max = this.max, + min = this.min, + offset = this.offset, + orientation = this.orientation, + options = this.options, + logarithmic = options.scaling === LOGARITHMIC, + scale; + + if (logarithmic) { + scale = length / (log(max, options.base) - log(min, options.base)); + } else { + scale = length / (max - min); + } + this.scale = scale; + + // Logarithmic? + if (logarithmic) { + this.d2p = function (dataValue) { + return offset + orientation * (log(dataValue, options.base) - log(min, options.base)) * scale; + }; + this.p2d = function (pointValue) { + return exp((offset + orientation * pointValue) / scale + log(min, options.base), options.base); + }; + } else { + this.d2p = function (dataValue) { + return offset + orientation * (dataValue - min) * scale; + }; + this.p2d = function (pointValue) { + return (offset + orientation * pointValue) / scale + min; + }; + } + }, + + calculateTicks : function () { + var options = this.options; + + this.ticks = []; + this.minorTicks = []; + + // User Ticks + if(options.ticks){ + this._cleanUserTicks(options.ticks, this.ticks); + this._cleanUserTicks(options.minorTicks || [], this.minorTicks); + } + else { + if (options.mode == 'time') { + this._calculateTimeTicks(); + } else if (options.scaling === 'logarithmic') { + this._calculateLogTicks(); + } else { + this._calculateTicks(); + } + } + + // Ticks to strings + _.each(this.ticks, function (tick) { tick.label += ''; }); + _.each(this.minorTicks, function (tick) { tick.label += ''; }); + }, + + /** + * Calculates the range of an axis to apply autoscaling. + */ + calculateRange: function () { + + if (!this.used) return; + + var axis = this, + o = axis.options, + min = o.min !== null ? o.min : axis.datamin, + max = o.max !== null ? o.max : axis.datamax, + margin = o.autoscaleMargin; + + if (o.scaling == 'logarithmic') { + if (min <= 0) min = axis.datamin; + + // Let it widen later on + if (max <= 0) max = min; + } + + if (max == min) { + var widen = max ? 0.01 : 1.00; + if (o.min === null) min -= widen; + if (o.max === null) max += widen; + } + + if (o.scaling === 'logarithmic') { + if (min < 0) min = max / o.base; // Could be the result of widening + + var maxexp = Math.log(max); + if (o.base != Math.E) maxexp /= Math.log(o.base); + maxexp = Math.ceil(maxexp); + + var minexp = Math.log(min); + if (o.base != Math.E) minexp /= Math.log(o.base); + minexp = Math.ceil(minexp); + + axis.tickSize = Flotr.getTickSize(o.noTicks, minexp, maxexp, o.tickDecimals === null ? 0 : o.tickDecimals); + + // Try to determine a suitable amount of miniticks based on the length of a decade + if (o.minorTickFreq === null) { + if (maxexp - minexp > 10) + o.minorTickFreq = 0; + else if (maxexp - minexp > 5) + o.minorTickFreq = 2; + else + o.minorTickFreq = 5; + } + } else { + axis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals); + } + + axis.min = min; + axis.max = max; //extendRange may use axis.min or axis.max, so it should be set before it is caled + + // Autoscaling. @todo This probably fails with log scale. Find a testcase and fix it + if(o.min === null && o.autoscale){ + axis.min -= axis.tickSize * margin; + // Make sure we don't go below zero if all values are positive. + if(axis.min < 0 && axis.datamin >= 0) axis.min = 0; + axis.min = axis.tickSize * Math.floor(axis.min / axis.tickSize); + } + + if(o.max === null && o.autoscale){ + axis.max += axis.tickSize * margin; + if(axis.max > 0 && axis.datamax <= 0 && axis.datamax != axis.datamin) axis.max = 0; + axis.max = axis.tickSize * Math.ceil(axis.max / axis.tickSize); + } + + if (axis.min == axis.max) axis.max = axis.min + 1; + }, + + calculateTextDimensions : function (T, options) { + + var maxLabel = '', + length, + i; + + if (this.options.showLabels) { + for (i = 0; i < this.ticks.length; ++i) { + length = this.ticks[i].label.length; + if (length > maxLabel.length){ + maxLabel = this.ticks[i].label; + } + } + } + + this.maxLabel = T.dimensions( + maxLabel, + {size:options.fontSize, angle: Flotr.toRad(this.options.labelsAngle)}, + 'font-size:smaller;', + 'flotr-grid-label' + ); + + this.titleSize = T.dimensions( + this.options.title, + {size:options.fontSize*1.2, angle: Flotr.toRad(this.options.titleAngle)}, + 'font-weight:bold;', + 'flotr-axis-title' + ); + }, + + _cleanUserTicks : function (ticks, axisTicks) { + + var axis = this, options = this.options, + v, i, label, tick; + + if(_.isFunction(ticks)) ticks = ticks({min : axis.min, max : axis.max}); + + for(i = 0; i < ticks.length; ++i){ + tick = ticks[i]; + if(typeof(tick) === 'object'){ + v = tick[0]; + label = (tick.length > 1) ? tick[1] : options.tickFormatter(v, {min : axis.min, max : axis.max}); + } else { + v = tick; + label = options.tickFormatter(v, {min : this.min, max : this.max}); + } + axisTicks[i] = { v: v, label: label }; + } + }, + + _calculateTimeTicks : function () { + this.ticks = Flotr.Date.generator(this); + }, + + _calculateLogTicks : function () { + + var axis = this, + o = axis.options, + v, + decadeStart; + + var max = Math.log(axis.max); + if (o.base != Math.E) max /= Math.log(o.base); + max = Math.ceil(max); + + var min = Math.log(axis.min); + if (o.base != Math.E) min /= Math.log(o.base); + min = Math.ceil(min); + + for (i = min; i < max; i += axis.tickSize) { + decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i); + // Next decade begins here: + var decadeEnd = decadeStart * ((o.base == Math.E) ? Math.exp(axis.tickSize) : Math.pow(o.base, axis.tickSize)); + var stepSize = (decadeEnd - decadeStart) / o.minorTickFreq; + + axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})}); + for (v = decadeStart + stepSize; v < decadeEnd; v += stepSize) + axis.minorTicks.push({v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max})}); + } + + // Always show the value at the would-be start of next decade (end of this decade) + decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i); + axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})}); + }, + + _calculateTicks : function () { + + var axis = this, + o = axis.options, + tickSize = axis.tickSize, + min = axis.min, + max = axis.max, + start = tickSize * Math.ceil(min / tickSize), // Round to nearest multiple of tick size. + decimals, + minorTickSize, + v, v2, + i, j; + + if (o.minorTickFreq) + minorTickSize = tickSize / o.minorTickFreq; + + // Then store all possible ticks. + for (i = 0; (v = v2 = start + i * tickSize) <= max; ++i){ + + // Round (this is always needed to fix numerical instability). + decimals = o.tickDecimals; + if (decimals === null) decimals = 1 - Math.floor(Math.log(tickSize) / Math.LN10); + if (decimals < 0) decimals = 0; + + v = v.toFixed(decimals); + axis.ticks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) }); + + if (o.minorTickFreq) { + for (j = 0; j < o.minorTickFreq && (i * tickSize + j * minorTickSize) < max; ++j) { + v = v2 + j * minorTickSize; + axis.minorTicks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) }); + } + } + } + + } +}; + + +// Static Methods +_.extend(Axis, { + getAxes : function (options) { + return { + x: new Axis({options: options.xaxis, n: 1, length: this.plotWidth}), + x2: new Axis({options: options.x2axis, n: 2, length: this.plotWidth}), + y: new Axis({options: options.yaxis, n: 1, length: this.plotHeight, offset: this.plotHeight, orientation: -1}), + y2: new Axis({options: options.y2axis, n: 2, length: this.plotHeight, offset: this.plotHeight, orientation: -1}) + }; + } +}); + + +// Helper Methods + + +function log (value, base) { + value = Math.log(Math.max(value, Number.MIN_VALUE)); + if (base !== Math.E) + value /= Math.log(base); + return value; +} + +function exp (value, base) { + return (base === Math.E) ? Math.exp(value) : Math.pow(base, value); +} + +Flotr.Axis = Axis; + +})(); + +/** + * Flotr Series Library + */ + +(function () { + +var + _ = Flotr._; + +function Series (o) { + _.extend(this, o); +} + +Series.prototype = { + + getRange: function () { + + var + data = this.data, + length = data.length, + xmin = Number.MAX_VALUE, + ymin = Number.MAX_VALUE, + xmax = -Number.MAX_VALUE, + ymax = -Number.MAX_VALUE, + xused = false, + yused = false, + x, y, i; + + if (length < 0 || this.hide) return false; + + for (i = 0; i < length; i++) { + x = data[i][0]; + y = data[i][1]; + if (x !== null) { + if (x < xmin) { xmin = x; xused = true; } + if (x > xmax) { xmax = x; xused = true; } + } + if (y !== null) { + if (y < ymin) { ymin = y; yused = true; } + if (y > ymax) { ymax = y; yused = true; } + } + } + + return { + xmin : xmin, + xmax : xmax, + ymin : ymin, + ymax : ymax, + xused : xused, + yused : yused + }; + } +}; + +_.extend(Series, { + /** + * Collects dataseries from input and parses the series into the right format. It returns an Array + * of Objects each having at least the 'data' key set. + * @param {Array, Object} data - Object or array of dataseries + * @return {Array} Array of Objects parsed into the right format ({(...,) data: [[x1,y1], [x2,y2], ...] (, ...)}) + */ + getSeries: function(data){ + return _.map(data, function(s){ + var series; + if (s.data) { + series = new Series(); + _.extend(series, s); + } else { + series = new Series({data:s}); + } + return series; + }); + } +}); + +Flotr.Series = Series; + +})(); + +/** Lines **/ +Flotr.addType('lines', { + options: { + show: false, // => setting to true will show lines, false will hide + lineWidth: 2, // => line width in pixels + fill: false, // => true to fill the area from the line to the x axis, false for (transparent) no fill + fillBorder: false, // => draw a border around the fill + fillColor: null, // => fill color + fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill + steps: false, // => draw steps + stacked: false // => setting to true will show stacked lines, false will show normal lines + }, + + stack : { + values : [] + }, + + /** + * Draws lines series in the canvas element. + * @param {Object} options + */ + draw : function (options) { + + var + context = options.context, + lineWidth = options.lineWidth, + shadowSize = options.shadowSize, + offset; + + context.save(); + context.lineJoin = 'round'; + + if (shadowSize) { + + context.lineWidth = shadowSize / 2; + offset = lineWidth / 2 + context.lineWidth / 2; + + // @TODO do this instead with a linear gradient + context.strokeStyle = "rgba(0,0,0,0.1)"; + this.plot(options, offset + shadowSize / 2, false); + + context.strokeStyle = "rgba(0,0,0,0.2)"; + this.plot(options, offset, false); + } + + context.lineWidth = lineWidth; + context.strokeStyle = options.color; + + this.plot(options, 0, true); + + context.restore(); + }, + + plot : function (options, shadowOffset, incStack) { + + var + context = options.context, + width = options.width, + height = options.height, + xScale = options.xScale, + yScale = options.yScale, + data = options.data, + stack = options.stacked ? this.stack : false, + length = data.length - 1, + prevx = null, + prevy = null, + zero = yScale(0), + start = null, + x1, x2, y1, y2, stack1, stack2, i; + + if (length < 1) return; + + context.beginPath(); + + for (i = 0; i < length; ++i) { + + // To allow empty values + if (data[i][1] === null || data[i+1][1] === null) { + if (options.fill) { + if (i > 0 && data[i][1] !== null) { + context.stroke(); + fill(); + start = null; + context.closePath(); + context.beginPath(); + } + } + continue; + } + + // Zero is infinity for log scales + // TODO handle zero for logarithmic + // if (xa.options.scaling === 'logarithmic' && (data[i][0] <= 0 || data[i+1][0] <= 0)) continue; + // if (ya.options.scaling === 'logarithmic' && (data[i][1] <= 0 || data[i+1][1] <= 0)) continue; + + x1 = xScale(data[i][0]); + x2 = xScale(data[i+1][0]); + + if (start === null) start = data[i]; + + if (stack) { + stack1 = stack.values[data[i][0]] || 0; + stack2 = stack.values[data[i+1][0]] || stack.values[data[i][0]] || 0; + y1 = yScale(data[i][1] + stack1); + y2 = yScale(data[i+1][1] + stack2); + if (incStack) { + data[i].y0 = stack1; + stack.values[data[i][0]] = data[i][1] + stack1; + if (i == length-1) { + data[i+1].y0 = stack2; + stack.values[data[i+1][0]] = data[i+1][1] + stack2; + } + } + } else { + y1 = yScale(data[i][1]); + y2 = yScale(data[i+1][1]); + } + + if ( + (y1 > height && y2 > height) || + (y1 < 0 && y2 < 0) || + (x1 < 0 && x2 < 0) || + (x1 > width && x2 > width) + ) continue; + + if ((prevx != x1) || (prevy != y1 + shadowOffset)) { + context.moveTo(x1, y1 + shadowOffset); + } + + prevx = x2; + prevy = y2 + shadowOffset; + if (options.steps) { + context.lineTo(prevx + shadowOffset / 2, y1 + shadowOffset); + context.lineTo(prevx + shadowOffset / 2, prevy); + } else { + context.lineTo(prevx, prevy); + } + } + + if (!options.fill || options.fill && !options.fillBorder) context.stroke(); + + fill(); + + function fill () { + // TODO stacked lines + if(!shadowOffset && options.fill && start){ + x1 = xScale(start[0]); + context.fillStyle = options.fillStyle; + context.lineTo(x2, zero); + context.lineTo(x1, zero); + context.lineTo(x1, yScale(start[1])); + context.fill(); + if (options.fillBorder) { + context.stroke(); + } + } + } + + context.closePath(); + }, + + // Perform any pre-render precalculations (this should be run on data first) + // - Pie chart total for calculating measures + // - Stacks for lines and bars + // precalculate : function () { + // } + // + // + // Get any bounds after pre calculation (axis can fetch this if does not have explicit min/max) + // getBounds : function () { + // } + // getMin : function () { + // } + // getMax : function () { + // } + // + // + // Padding around rendered elements + // getPadding : function () { + // } + + extendYRange : function (axis, data, options, lines) { + + var o = axis.options; + + // If stacked and auto-min + if (options.stacked && ((!o.max && o.max !== 0) || (!o.min && o.min !== 0))) { + + var + newmax = axis.max, + newmin = axis.min, + positiveSums = lines.positiveSums || {}, + negativeSums = lines.negativeSums || {}, + x, j; + + for (j = 0; j < data.length; j++) { + + x = data[j][0] + ''; + + // Positive + if (data[j][1] > 0) { + positiveSums[x] = (positiveSums[x] || 0) + data[j][1]; + newmax = Math.max(newmax, positiveSums[x]); + } + + // Negative + else { + negativeSums[x] = (negativeSums[x] || 0) + data[j][1]; + newmin = Math.min(newmin, negativeSums[x]); + } + } + + lines.negativeSums = negativeSums; + lines.positiveSums = positiveSums; + + axis.max = newmax; + axis.min = newmin; + } + + if (options.steps) { + + this.hit = function (options) { + var + data = options.data, + args = options.args, + yScale = options.yScale, + mouse = args[0], + length = data.length, + n = args[1], + x = options.xInverse(mouse.relX), + relY = mouse.relY, + i; + + for (i = 0; i < length - 1; i++) { + if (x >= data[i][0] && x <= data[i+1][0]) { + if (Math.abs(yScale(data[i][1]) - relY) < 8) { + n.x = data[i][0]; + n.y = data[i][1]; + n.index = i; + n.seriesIndex = options.index; + } + break; + } + } + }; + + this.drawHit = function (options) { + var + context = options.context, + args = options.args, + data = options.data, + xScale = options.xScale, + index = args.index, + x = xScale(args.x), + y = options.yScale(args.y), + x2; + + if (data.length - 1 > index) { + x2 = options.xScale(data[index + 1][0]); + context.save(); + context.strokeStyle = options.color; + context.lineWidth = options.lineWidth; + context.beginPath(); + context.moveTo(x, y); + context.lineTo(x2, y); + context.stroke(); + context.closePath(); + context.restore(); + } + }; + + this.clearHit = function (options) { + var + context = options.context, + args = options.args, + data = options.data, + xScale = options.xScale, + width = options.lineWidth, + index = args.index, + x = xScale(args.x), + y = options.yScale(args.y), + x2; + + if (data.length - 1 > index) { + x2 = options.xScale(data[index + 1][0]); + context.clearRect(x - width, y - width, x2 - x + 2 * width, 2 * width); + } + }; + } + } + +}); + +/** Bars **/ +Flotr.addType('bars', { + + options: { + show: false, // => setting to true will show bars, false will hide + lineWidth: 2, // => in pixels + barWidth: 1, // => in units of the x axis + fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill + fillColor: null, // => fill color + fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill + horizontal: false, // => horizontal bars (x and y inverted) + stacked: false, // => stacked bar charts + centered: true, // => center the bars to their x axis value + topPadding: 0.1, // => top padding in percent + grouped: false // => groups bars together which share x value, hit not supported. + }, + + stack : { + positive : [], + negative : [], + _positive : [], // Shadow + _negative : [] // Shadow + }, + + draw : function (options) { + var + context = options.context; + + this.current += 1; + + context.save(); + context.lineJoin = 'miter'; + // @TODO linewidth not interpreted the right way. + context.lineWidth = options.lineWidth; + context.strokeStyle = options.color; + if (options.fill) context.fillStyle = options.fillStyle; + + this.plot(options); + + context.restore(); + }, + + plot : function (options) { + + var + data = options.data, + context = options.context, + shadowSize = options.shadowSize, + i, geometry, left, top, width, height; + + if (data.length < 1) return; + + this.translate(context, options.horizontal); + + for (i = 0; i < data.length; i++) { + + geometry = this.getBarGeometry(data[i][0], data[i][1], options); + if (geometry === null) continue; + + left = geometry.left; + top = geometry.top; + width = geometry.width; + height = geometry.height; + + if (options.fill) context.fillRect(left, top, width, height); + if (shadowSize) { + context.save(); + context.fillStyle = 'rgba(0,0,0,0.05)'; + context.fillRect(left + shadowSize, top + shadowSize, width, height); + context.restore(); + } + if (options.lineWidth) { + context.strokeRect(left, top, width, height); + } + } + }, + + translate : function (context, horizontal) { + if (horizontal) { + context.rotate(-Math.PI / 2); + context.scale(-1, 1); + } + }, + + getBarGeometry : function (x, y, options) { + + var + horizontal = options.horizontal, + barWidth = options.barWidth, + centered = options.centered, + stack = options.stacked ? this.stack : false, + lineWidth = options.lineWidth, + bisection = centered ? barWidth / 2 : 0, + xScale = horizontal ? options.yScale : options.xScale, + yScale = horizontal ? options.xScale : options.yScale, + xValue = horizontal ? y : x, + yValue = horizontal ? x : y, + stackOffset = 0, + stackValue, left, right, top, bottom; + + if (options.grouped) { + this.current / this.groups; + xValue = xValue - bisection; + barWidth = barWidth / this.groups; + bisection = barWidth / 2; + xValue = xValue + barWidth * this.current - bisection; + } + + // Stacked bars + if (stack) { + stackValue = yValue > 0 ? stack.positive : stack.negative; + stackOffset = stackValue[xValue] || stackOffset; + stackValue[xValue] = stackOffset + yValue; + } + + left = xScale(xValue - bisection); + right = xScale(xValue + barWidth - bisection); + top = yScale(yValue + stackOffset); + bottom = yScale(stackOffset); + + // TODO for test passing... probably looks better without this + if (bottom < 0) bottom = 0; + + // TODO Skipping... + // if (right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) continue; + + return (x === null || y === null) ? null : { + x : xValue, + y : yValue, + xScale : xScale, + yScale : yScale, + top : top, + left : Math.min(left, right) - lineWidth / 2, + width : Math.abs(right - left) - lineWidth, + height : bottom - top + }; + }, + + hit : function (options) { + var + data = options.data, + args = options.args, + mouse = args[0], + n = args[1], + x = options.xInverse(mouse.relX), + y = options.yInverse(mouse.relY), + hitGeometry = this.getBarGeometry(x, y, options), + width = hitGeometry.width / 2, + left = hitGeometry.left, + height = hitGeometry.y, + geometry, i; + + for (i = data.length; i--;) { + geometry = this.getBarGeometry(data[i][0], data[i][1], options); + if ( + // Height: + ( + // Positive Bars: + (height > 0 && height < geometry.y) || + // Negative Bars: + (height < 0 && height > geometry.y) + ) && + // Width: + (Math.abs(left - geometry.left) < width) + ) { + n.x = data[i][0]; + n.y = data[i][1]; + n.index = i; + n.seriesIndex = options.index; + } + } + }, + + drawHit : function (options) { + // TODO hits for stacked bars; implement using calculateStack option? + var + context = options.context, + args = options.args, + geometry = this.getBarGeometry(args.x, args.y, options), + left = geometry.left, + top = geometry.top, + width = geometry.width, + height = geometry.height; + + context.save(); + context.strokeStyle = options.color; + context.lineWidth = options.lineWidth; + this.translate(context, options.horizontal); + + // Draw highlight + context.beginPath(); + context.moveTo(left, top + height); + context.lineTo(left, top); + context.lineTo(left + width, top); + context.lineTo(left + width, top + height); + if (options.fill) { + context.fillStyle = options.fillStyle; + context.fill(); + } + context.stroke(); + context.closePath(); + + context.restore(); + }, + + clearHit: function (options) { + var + context = options.context, + args = options.args, + geometry = this.getBarGeometry(args.x, args.y, options), + left = geometry.left, + width = geometry.width, + top = geometry.top, + height = geometry.height, + lineWidth = 2 * options.lineWidth; + + context.save(); + this.translate(context, options.horizontal); + context.clearRect( + left - lineWidth, + Math.min(top, top + height) - lineWidth, + width + 2 * lineWidth, + Math.abs(height) + 2 * lineWidth + ); + context.restore(); + }, + + extendXRange : function (axis, data, options, bars) { + this._extendRange(axis, data, options, bars); + this.groups = (this.groups + 1) || 1; + this.current = 0; + }, + + extendYRange : function (axis, data, options, bars) { + this._extendRange(axis, data, options, bars); + }, + _extendRange: function (axis, data, options, bars) { + + var + max = axis.options.max; + + if (_.isNumber(max) || _.isString(max)) return; + + var + newmin = axis.min, + newmax = axis.max, + horizontal = options.horizontal, + orientation = axis.orientation, + positiveSums = this.positiveSums || {}, + negativeSums = this.negativeSums || {}, + value, datum, index, j; + + // Sides of bars + if ((orientation == 1 && !horizontal) || (orientation == -1 && horizontal)) { + if (options.centered) { + newmax = Math.max(axis.datamax + options.barWidth, newmax); + newmin = Math.min(axis.datamin - options.barWidth, newmin); + } + } + + if (options.stacked && + ((orientation == 1 && horizontal) || (orientation == -1 && !horizontal))){ + + for (j = data.length; j--;) { + value = data[j][(orientation == 1 ? 1 : 0)]+''; + datum = data[j][(orientation == 1 ? 0 : 1)]; + + // Positive + if (datum > 0) { + positiveSums[value] = (positiveSums[value] || 0) + datum; + newmax = Math.max(newmax, positiveSums[value]); + } + + // Negative + else { + negativeSums[value] = (negativeSums[value] || 0) + datum; + newmin = Math.min(newmin, negativeSums[value]); + } + } + } + + // End of bars + if ((orientation == 1 && horizontal) || (orientation == -1 && !horizontal)) { + if (options.topPadding && (axis.max === axis.datamax || (options.stacked && this.stackMax !== newmax))) { + newmax += options.topPadding * (newmax - newmin); + } + } + + this.stackMin = newmin; + this.stackMax = newmax; + this.negativeSums = negativeSums; + this.positiveSums = positiveSums; + + axis.max = newmax; + axis.min = newmin; + } + +}); + +/** Bubbles **/ +Flotr.addType('bubbles', { + options: { + show: false, // => setting to true will show radar chart, false will hide + lineWidth: 2, // => line width in pixels + fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill + fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill + baseRadius: 2 // => ratio of the radar, against the plot size + }, + draw : function (options) { + var + context = options.context, + shadowSize = options.shadowSize; + + context.save(); + context.lineWidth = options.lineWidth; + + // Shadows + context.fillStyle = 'rgba(0,0,0,0.05)'; + context.strokeStyle = 'rgba(0,0,0,0.05)'; + this.plot(options, shadowSize / 2); + context.strokeStyle = 'rgba(0,0,0,0.1)'; + this.plot(options, shadowSize / 4); + + // Chart + context.strokeStyle = options.color; + context.fillStyle = options.fillStyle; + this.plot(options); + + context.restore(); + }, + plot : function (options, offset) { + + var + data = options.data, + context = options.context, + geometry, + i, x, y, z; + + offset = offset || 0; + + for (i = 0; i < data.length; ++i){ + + geometry = this.getGeometry(data[i], options); + + context.beginPath(); + context.arc(geometry.x + offset, geometry.y + offset, geometry.z, 0, 2 * Math.PI, true); + context.stroke(); + if (options.fill) context.fill(); + context.closePath(); + } + }, + getGeometry : function (point, options) { + return { + x : options.xScale(point[0]), + y : options.yScale(point[1]), + z : point[2] * options.baseRadius + }; + }, + hit : function (options) { + var + data = options.data, + args = options.args, + mouse = args[0], + n = args[1], + relX = mouse.relX, + relY = mouse.relY, + distance, + geometry, + dx, dy; + + n.best = n.best || Number.MAX_VALUE; + + for (i = data.length; i--;) { + geometry = this.getGeometry(data[i], options); + + dx = geometry.x - relX; + dy = geometry.y - relY; + distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < geometry.z && geometry.z < n.best) { + n.x = data[i][0]; + n.y = data[i][1]; + n.index = i; + n.seriesIndex = options.index; + n.best = geometry.z; + } + } + }, + drawHit : function (options) { + + var + context = options.context, + geometry = this.getGeometry(options.data[options.args.index], options); + + context.save(); + context.lineWidth = options.lineWidth; + context.fillStyle = options.fillStyle; + context.strokeStyle = options.color; + context.beginPath(); + context.arc(geometry.x, geometry.y, geometry.z, 0, 2 * Math.PI, true); + context.fill(); + context.stroke(); + context.closePath(); + context.restore(); + }, + clearHit : function (options) { + + var + context = options.context, + geometry = this.getGeometry(options.data[options.args.index], options), + offset = geometry.z + options.lineWidth; + + context.save(); + context.clearRect( + geometry.x - offset, + geometry.y - offset, + 2 * offset, + 2 * offset + ); + context.restore(); + } + // TODO Add a hit calculation method (like pie) +}); + +/** Candles **/ +Flotr.addType('candles', { + options: { + show: false, // => setting to true will show candle sticks, false will hide + lineWidth: 1, // => in pixels + wickLineWidth: 1, // => in pixels + candleWidth: 0.6, // => in units of the x axis + fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill + upFillColor: '#00A8F0',// => up sticks fill color + downFillColor: '#CB4B4B',// => down sticks fill color + fillOpacity: 0.5, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill + barcharts: false // => draw as barcharts (not standard bars but financial barcharts) + }, + + draw : function (options) { + + var + context = options.context; + + context.save(); + context.lineJoin = 'miter'; + context.lineCap = 'butt'; + // @TODO linewidth not interpreted the right way. + context.lineWidth = options.wickLineWidth || options.lineWidth; + + this.plot(options); + + context.restore(); + }, + + plot : function (options) { + + var + data = options.data, + context = options.context, + xScale = options.xScale, + yScale = options.yScale, + width = options.candleWidth / 2, + shadowSize = options.shadowSize, + lineWidth = options.lineWidth, + wickLineWidth = options.wickLineWidth, + pixelOffset = (wickLineWidth % 2) / 2, + color, + datum, x, y, + open, high, low, close, + left, right, bottom, top, bottom2, top2, reverseLines, + i; + + if (data.length < 1) return; + + for (i = 0; i < data.length; i++) { + datum = data[i]; + x = datum[0]; + open = datum[1]; + high = datum[2]; + low = datum[3]; + close = datum[4]; + left = xScale(x - width); + right = xScale(x + width); + bottom = yScale(low); + top = yScale(high); + bottom2 = yScale(Math.min(open, close)); + top2 = yScale(Math.max(open, close)); + + /* + // TODO skipping + if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) + continue; + */ + + color = options[open > close ? 'downFillColor' : 'upFillColor']; + + // Fill the candle. + if (options.fill && !options.barcharts) { + context.fillStyle = 'rgba(0,0,0,0.05)'; + context.fillRect(left + shadowSize, top2 + shadowSize, right - left, bottom2 - top2); + context.save(); + context.globalAlpha = options.fillOpacity; + context.fillStyle = color; + context.fillRect(left, top2 + lineWidth, right - left, bottom2 - top2); + context.restore(); + } + + // Draw candle outline/border, high, low. + if (lineWidth || wickLineWidth) { + + x = Math.floor((left + right) / 2) + pixelOffset; + + context.strokeStyle = color; + context.beginPath(); + + if (options.barcharts) { + context.moveTo(x, Math.floor(top + lineWidth)); + context.lineTo(x, Math.floor(bottom + lineWidth)); + + reverseLines = open < close; + context.moveTo(reverseLines ? right : left, Math.floor(top2 + lineWidth)); + context.lineTo(x, Math.floor(top2 + lineWidth)); + context.moveTo(x, Math.floor(bottom2 + lineWidth)); + context.lineTo(reverseLines ? left : right, Math.floor(bottom2 + lineWidth)); + } else { + context.strokeRect(left, top2 + lineWidth, right - left, bottom2 - top2); + context.moveTo(x, Math.floor(top2 + lineWidth)); + context.lineTo(x, Math.floor(top + lineWidth)); + context.moveTo(x, Math.floor(bottom2 + lineWidth)); + context.lineTo(x, Math.floor(bottom + lineWidth)); + } + + context.closePath(); + context.stroke(); + } + } + }, + + hit : function (options) { + var + xScale = options.xScale, + yScale = options.yScale, + data = options.data, + args = options.args, + mouse = args[0], + width = options.candleWidth / 2, + n = args[1], + x = mouse.relX, + y = mouse.relY, + length = data.length, + i, datum, + high, low, + left, right, top, bottom; + + for (i = 0; i < length; i++) { + datum = data[i], + high = datum[2]; + low = datum[3]; + left = xScale(datum[0] - width); + right = xScale(datum[0] + width); + bottom = yScale(low); + top = yScale(high); + + if (x > left && x < right && y > top && y < bottom) { + n.x = datum[0]; + n.index = i; + n.seriesIndex = options.index; + return; + } + } + }, + + drawHit : function (options) { + var + context = options.context; + context.save(); + this.plot( + _.defaults({ + fill : !!options.fillColor, + upFillColor : options.color, + downFillColor : options.color, + data : [options.data[options.args.index]] + }, options) + ); + context.restore(); + }, + + clearHit : function (options) { + var + args = options.args, + context = options.context, + xScale = options.xScale, + yScale = options.yScale, + lineWidth = options.lineWidth, + width = options.candleWidth / 2, + bar = options.data[args.index], + left = xScale(bar[0] - width) - lineWidth, + right = xScale(bar[0] + width) + lineWidth, + top = yScale(bar[2]), + bottom = yScale(bar[3]) + lineWidth; + context.clearRect(left, top, right - left, bottom - top); + }, + + extendXRange: function (axis, data, options) { + if (axis.options.max === null) { + axis.max = Math.max(axis.datamax + 0.5, axis.max); + axis.min = Math.min(axis.datamin - 0.5, axis.min); + } + } +}); + +/** Gantt + * Base on data in form [s,y,d] where: + * y - executor or simply y value + * s - task start value + * d - task duration + * **/ +Flotr.addType('gantt', { + options: { + show: false, // => setting to true will show gantt, false will hide + lineWidth: 2, // => in pixels + barWidth: 1, // => in units of the x axis + fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill + fillColor: null, // => fill color + fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill + centered: true // => center the bars to their x axis value + }, + /** + * Draws gantt series in the canvas element. + * @param {Object} series - Series with options.gantt.show = true. + */ + draw: function(series) { + var ctx = this.ctx, + bw = series.gantt.barWidth, + lw = Math.min(series.gantt.lineWidth, bw); + + ctx.save(); + ctx.translate(this.plotOffset.left, this.plotOffset.top); + ctx.lineJoin = 'miter'; + + /** + * @todo linewidth not interpreted the right way. + */ + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + + ctx.save(); + this.gantt.plotShadows(series, bw, 0, series.gantt.fill); + ctx.restore(); + + if(series.gantt.fill){ + var color = series.gantt.fillColor || series.color; + ctx.fillStyle = this.processColor(color, {opacity: series.gantt.fillOpacity}); + } + + this.gantt.plot(series, bw, 0, series.gantt.fill); + ctx.restore(); + }, + plot: function(series, barWidth, offset, fill){ + var data = series.data; + if(data.length < 1) return; + + var xa = series.xaxis, + ya = series.yaxis, + ctx = this.ctx, i; + + for(i = 0; i < data.length; i++){ + var y = data[i][0], + s = data[i][1], + d = data[i][2], + drawLeft = true, drawTop = true, drawRight = true; + + if (s === null || d === null) continue; + + var left = s, + right = s + d, + bottom = y - (series.gantt.centered ? barWidth/2 : 0), + top = y + barWidth - (series.gantt.centered ? barWidth/2 : 0); + + if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) + continue; + + if(left < xa.min){ + left = xa.min; + drawLeft = false; + } + + if(right > xa.max){ + right = xa.max; + if (xa.lastSerie != series) + drawTop = false; + } + + if(bottom < ya.min) + bottom = ya.min; + + if(top > ya.max){ + top = ya.max; + if (ya.lastSerie != series) + drawTop = false; + } + + /** + * Fill the bar. + */ + if(fill){ + ctx.beginPath(); + ctx.moveTo(xa.d2p(left), ya.d2p(bottom) + offset); + ctx.lineTo(xa.d2p(left), ya.d2p(top) + offset); + ctx.lineTo(xa.d2p(right), ya.d2p(top) + offset); + ctx.lineTo(xa.d2p(right), ya.d2p(bottom) + offset); + ctx.fill(); + ctx.closePath(); + } + + /** + * Draw bar outline/border. + */ + if(series.gantt.lineWidth && (drawLeft || drawRight || drawTop)){ + ctx.beginPath(); + ctx.moveTo(xa.d2p(left), ya.d2p(bottom) + offset); + + ctx[drawLeft ?'lineTo':'moveTo'](xa.d2p(left), ya.d2p(top) + offset); + ctx[drawTop ?'lineTo':'moveTo'](xa.d2p(right), ya.d2p(top) + offset); + ctx[drawRight?'lineTo':'moveTo'](xa.d2p(right), ya.d2p(bottom) + offset); + + ctx.stroke(); + ctx.closePath(); + } + } + }, + plotShadows: function(series, barWidth, offset){ + var data = series.data; + if(data.length < 1) return; + + var i, y, s, d, + xa = series.xaxis, + ya = series.yaxis, + ctx = this.ctx, + sw = this.options.shadowSize; + + for(i = 0; i < data.length; i++){ + y = data[i][0]; + s = data[i][1]; + d = data[i][2]; + + if (s === null || d === null) continue; + + var left = s, + right = s + d, + bottom = y - (series.gantt.centered ? barWidth/2 : 0), + top = y + barWidth - (series.gantt.centered ? barWidth/2 : 0); + + if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) + continue; + + if(left < xa.min) left = xa.min; + if(right > xa.max) right = xa.max; + if(bottom < ya.min) bottom = ya.min; + if(top > ya.max) top = ya.max; + + var width = xa.d2p(right)-xa.d2p(left)-((xa.d2p(right)+sw <= this.plotWidth) ? 0 : sw); + var height = ya.d2p(bottom)-ya.d2p(top)-((ya.d2p(bottom)+sw <= this.plotHeight) ? 0 : sw ); + + ctx.fillStyle = 'rgba(0,0,0,0.05)'; + ctx.fillRect(Math.min(xa.d2p(left)+sw, this.plotWidth), Math.min(ya.d2p(top)+sw, this.plotHeight), width, height); + } + }, + extendXRange: function(axis) { + if(axis.options.max === null){ + var newmin = axis.min, + newmax = axis.max, + i, j, x, s, g, + stackedSumsPos = {}, + stackedSumsNeg = {}, + lastSerie = null; + + for(i = 0; i < this.series.length; ++i){ + s = this.series[i]; + g = s.gantt; + + if(g.show && s.xaxis == axis) { + for (j = 0; j < s.data.length; j++) { + if (g.show) { + y = s.data[j][0]+''; + stackedSumsPos[y] = Math.max((stackedSumsPos[y] || 0), s.data[j][1]+s.data[j][2]); + lastSerie = s; + } + } + for (j in stackedSumsPos) { + newmax = Math.max(stackedSumsPos[j], newmax); + } + } + } + axis.lastSerie = lastSerie; + axis.max = newmax; + axis.min = newmin; + } + }, + extendYRange: function(axis){ + if(axis.options.max === null){ + var newmax = Number.MIN_VALUE, + newmin = Number.MAX_VALUE, + i, j, s, g, + stackedSumsPos = {}, + stackedSumsNeg = {}, + lastSerie = null; + + for(i = 0; i < this.series.length; ++i){ + s = this.series[i]; + g = s.gantt; + + if (g.show && !s.hide && s.yaxis == axis) { + var datamax = Number.MIN_VALUE, datamin = Number.MAX_VALUE; + for(j=0; j < s.data.length; j++){ + datamax = Math.max(datamax,s.data[j][0]); + datamin = Math.min(datamin,s.data[j][0]); + } + + if (g.centered) { + newmax = Math.max(datamax + 0.5, newmax); + newmin = Math.min(datamin - 0.5, newmin); + } + else { + newmax = Math.max(datamax + 1, newmax); + newmin = Math.min(datamin, newmin); + } + // For normal horizontal bars + if (g.barWidth + datamax > newmax){ + newmax = axis.max + g.barWidth; + } + } + } + axis.lastSerie = lastSerie; + axis.max = newmax; + axis.min = newmin; + axis.tickSize = Flotr.getTickSize(axis.options.noTicks, newmin, newmax, axis.options.tickDecimals); + } + } +}); + +/** Markers **/ +/** + * Formats the marker labels. + * @param {Object} obj - Marker value Object {x:..,y:..} + * @return {String} Formatted marker string + */ +(function () { + +Flotr.defaultMarkerFormatter = function(obj){ + return (Math.round(obj.y*100)/100)+''; +}; + +Flotr.addType('markers', { + options: { + show: false, // => setting to true will show markers, false will hide + lineWidth: 1, // => line width of the rectangle around the marker + color: '#000000', // => text color + fill: false, // => fill or not the marekers' rectangles + fillColor: "#FFFFFF", // => fill color + fillOpacity: 0.4, // => fill opacity + stroke: false, // => draw the rectangle around the markers + position: 'ct', // => the markers position (vertical align: b, m, t, horizontal align: l, c, r) + verticalMargin: 0, // => the margin between the point and the text. + labelFormatter: Flotr.defaultMarkerFormatter, + fontSize: Flotr.defaultOptions.fontSize, + stacked: false, // => true if markers should be stacked + stackingType: 'b', // => define staching behavior, (b- bars like, a - area like) (see Issue 125 for details) + horizontal: false // => true if markers should be horizontal (For now only in a case on horizontal stacked bars, stacks should be calculated horizontaly) + }, + + // TODO test stacked markers. + stack : { + positive : [], + negative : [], + values : [] + }, + + draw : function (options) { + + var + data = options.data, + context = options.context, + stack = options.stacked ? options.stack : false, + stackType = options.stackingType, + stackOffsetNeg, + stackOffsetPos, + stackOffset, + i, x, y, label; + + context.save(); + context.lineJoin = 'round'; + context.lineWidth = options.lineWidth; + context.strokeStyle = 'rgba(0,0,0,0.5)'; + context.fillStyle = options.fillStyle; + + function stackPos (a, b) { + stackOffsetPos = stack.negative[a] || 0; + stackOffsetNeg = stack.positive[a] || 0; + if (b > 0) { + stack.positive[a] = stackOffsetPos + b; + return stackOffsetPos + b; + } else { + stack.negative[a] = stackOffsetNeg + b; + return stackOffsetNeg + b; + } + } + + for (i = 0; i < data.length; ++i) { + + x = data[i][0]; + y = data[i][1]; + + if (stack) { + if (stackType == 'b') { + if (options.horizontal) y = stackPos(y, x); + else x = stackPos(x, y); + } else if (stackType == 'a') { + stackOffset = stack.values[x] || 0; + stack.values[x] = stackOffset + y; + y = stackOffset + y; + } + } + + label = options.labelFormatter({x: x, y: y, index: i, data : data}); + this.plot(options.xScale(x), options.yScale(y), label, options); + } + context.restore(); + }, + plot: function(x, y, label, options) { + var context = options.context; + if (isImage(label) && !label.complete) { + throw 'Marker image not loaded.'; + } else { + this._plot(x, y, label, options); + } + }, + + _plot: function(x, y, label, options) { + var context = options.context, + margin = 2, + left = x, + top = y, + dim; + + if (isImage(label)) + dim = {height : label.height, width: label.width}; + else + dim = options.text.canvas(label); + + dim.width = Math.floor(dim.width+margin*2); + dim.height = Math.floor(dim.height+margin*2); + + if (options.position.indexOf('c') != -1) left -= dim.width/2 + margin; + else if (options.position.indexOf('l') != -1) left -= dim.width; + + if (options.position.indexOf('m') != -1) top -= dim.height/2 + margin; + else if (options.position.indexOf('t') != -1) top -= dim.height + options.verticalMargin; + else top += options.verticalMargin; + + left = Math.floor(left)+0.5; + top = Math.floor(top)+0.5; + + if(options.fill) + context.fillRect(left, top, dim.width, dim.height); + + if(options.stroke) + context.strokeRect(left, top, dim.width, dim.height); + + if (isImage(label)) + context.drawImage(label, parseInt(left+margin, 10), parseInt(top+margin, 10)); + else + Flotr.drawText(context, label, left+margin, top+margin, {textBaseline: 'top', textAlign: 'left', size: options.fontSize, color: options.color}); + } +}); + +function isImage (i) { + return typeof i === 'object' && i.constructor && (Image ? true : i.constructor === Image); +} + +})(); + +/** + * Pie + * + * Formats the pies labels. + * @param {Object} slice - Slice object + * @return {String} Formatted pie label string + */ +(function () { + +var + _ = Flotr._; + +Flotr.defaultPieLabelFormatter = function (total, value) { + return (100 * value / total).toFixed(2)+'%'; +}; + +Flotr.addType('pie', { + options: { + show: false, // => setting to true will show bars, false will hide + lineWidth: 1, // => in pixels + fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill + fillColor: null, // => fill color + fillOpacity: 0.6, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill + explode: 6, // => the number of pixels the splices will be far from the center + sizeRatio: 0.6, // => the size ratio of the pie relative to the plot + startAngle: Math.PI/4, // => the first slice start angle + labelFormatter: Flotr.defaultPieLabelFormatter, + pie3D: false, // => whether to draw the pie in 3 dimenstions or not (ineffective) + pie3DviewAngle: (Math.PI/2 * 0.8), + pie3DspliceThickness: 20, + epsilon: 0.1 // => how close do you have to get to hit empty slice + }, + + draw : function (options) { + + // TODO 3D charts what? + var + data = options.data, + context = options.context, + lineWidth = options.lineWidth, + shadowSize = options.shadowSize, + sizeRatio = options.sizeRatio, + height = options.height, + width = options.width, + explode = options.explode, + color = options.color, + fill = options.fill, + fillStyle = options.fillStyle, + radius = Math.min(width, height) * sizeRatio / 2, + value = data[0][1], + html = [], + vScale = 1,//Math.cos(series.pie.viewAngle); + measure = Math.PI * 2 * value / this.total, + startAngle = this.startAngle || (2 * Math.PI * options.startAngle), // TODO: this initial startAngle is already in radians (fixing will be test-unstable) + endAngle = startAngle + measure, + bisection = startAngle + measure / 2, + label = options.labelFormatter(this.total, value), + //plotTickness = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale; + explodeCoeff = explode + radius + 4, + distX = Math.cos(bisection) * explodeCoeff, + distY = Math.sin(bisection) * explodeCoeff, + textAlign = distX < 0 ? 'right' : 'left', + textBaseline = distY > 0 ? 'top' : 'bottom', + style, + x, y; + + context.save(); + context.translate(width / 2, height / 2); + context.scale(1, vScale); + + x = Math.cos(bisection) * explode; + y = Math.sin(bisection) * explode; + + // Shadows + if (shadowSize > 0) { + this.plotSlice(x + shadowSize, y + shadowSize, radius, startAngle, endAngle, context); + if (fill) { + context.fillStyle = 'rgba(0,0,0,0.1)'; + context.fill(); + } + } + + this.plotSlice(x, y, radius, startAngle, endAngle, context); + if (fill) { + context.fillStyle = fillStyle; + context.fill(); + } + context.lineWidth = lineWidth; + context.strokeStyle = color; + context.stroke(); + + style = { + size : options.fontSize * 1.2, + color : options.fontColor, + weight : 1.5 + }; + + if (label) { + if (options.htmlText || !options.textEnabled) { + divStyle = 'position:absolute;' + textBaseline + ':' + (height / 2 + (textBaseline === 'top' ? distY : -distY)) + 'px;'; + divStyle += textAlign + ':' + (width / 2 + (textAlign === 'right' ? -distX : distX)) + 'px;'; + html.push('
', label, '
'); + } + else { + style.textAlign = textAlign; + style.textBaseline = textBaseline; + Flotr.drawText(context, label, distX, distY, style); + } + } + + if (options.htmlText || !options.textEnabled) { + var div = Flotr.DOM.node('
'); + Flotr.DOM.insert(div, html.join('')); + Flotr.DOM.insert(options.element, div); + } + + context.restore(); + + // New start angle + this.startAngle = endAngle; + this.slices = this.slices || []; + this.slices.push({ + radius : radius, + x : x, + y : y, + explode : explode, + start : startAngle, + end : endAngle + }); + }, + plotSlice : function (x, y, radius, startAngle, endAngle, context) { + context.beginPath(); + context.moveTo(x, y); + context.arc(x, y, radius, startAngle, endAngle, false); + context.lineTo(x, y); + context.closePath(); + }, + hit : function (options) { + + var + data = options.data[0], + args = options.args, + index = options.index, + mouse = args[0], + n = args[1], + slice = this.slices[index], + x = mouse.relX - options.width / 2, + y = mouse.relY - options.height / 2, + r = Math.sqrt(x * x + y * y), + theta = Math.atan(y / x), + circle = Math.PI * 2, + explode = slice.explode || options.explode, + start = slice.start % circle, + end = slice.end % circle, + epsilon = options.epsilon; + + if (x < 0) { + theta += Math.PI; + } else if (x > 0 && y < 0) { + theta += circle; + } + + if (r < slice.radius + explode && r > explode) { + if ( + (theta > start && theta < end) || // Normal Slice + (start > end && (theta < end || theta > start)) || // First slice + // TODO: Document the two cases at the end: + (start === end && ((slice.start === slice.end && Math.abs(theta - start) < epsilon) || (slice.start !== slice.end && Math.abs(theta-start) > epsilon))) + ) { + + // TODO Decouple this from hit plugin (chart shouldn't know what n means) + n.x = data[0]; + n.y = data[1]; + n.sAngle = start; + n.eAngle = end; + n.index = 0; + n.seriesIndex = index; + n.fraction = data[1] / this.total; + } + } + }, + drawHit: function (options) { + var + context = options.context, + slice = this.slices[options.args.seriesIndex]; + + context.save(); + context.translate(options.width / 2, options.height / 2); + this.plotSlice(slice.x, slice.y, slice.radius, slice.start, slice.end, context); + context.stroke(); + context.restore(); + }, + clearHit : function (options) { + var + context = options.context, + slice = this.slices[options.args.seriesIndex], + padding = 2 * options.lineWidth, + radius = slice.radius + padding; + + context.save(); + context.translate(options.width / 2, options.height / 2); + context.clearRect( + slice.x - radius, + slice.y - radius, + 2 * radius + padding, + 2 * radius + padding + ); + context.restore(); + }, + extendYRange : function (axis, data) { + this.total = (this.total || 0) + data[0][1]; + } +}); +})(); + +/** Points **/ +Flotr.addType('points', { + options: { + show: false, // => setting to true will show points, false will hide + radius: 3, // => point radius (pixels) + lineWidth: 2, // => line width in pixels + fill: true, // => true to fill the points with a color, false for (transparent) no fill + fillColor: '#FFFFFF', // => fill color. Null to use series color. + fillOpacity: 1, // => opacity of color inside the points + hitRadius: null // => override for points hit radius + }, + + draw : function (options) { + var + context = options.context, + lineWidth = options.lineWidth, + shadowSize = options.shadowSize; + + context.save(); + + if (shadowSize > 0) { + context.lineWidth = shadowSize / 2; + + context.strokeStyle = 'rgba(0,0,0,0.1)'; + this.plot(options, shadowSize / 2 + context.lineWidth / 2); + + context.strokeStyle = 'rgba(0,0,0,0.2)'; + this.plot(options, context.lineWidth / 2); + } + + context.lineWidth = options.lineWidth; + context.strokeStyle = options.color; + if (options.fill) context.fillStyle = options.fillStyle; + + this.plot(options); + context.restore(); + }, + + plot : function (options, offset) { + var + data = options.data, + context = options.context, + xScale = options.xScale, + yScale = options.yScale, + i, x, y; + + for (i = data.length - 1; i > -1; --i) { + y = data[i][1]; + if (y === null) continue; + + x = xScale(data[i][0]); + y = yScale(y); + + if (x < 0 || x > options.width || y < 0 || y > options.height) continue; + + context.beginPath(); + if (offset) { + context.arc(x, y + offset, options.radius, 0, Math.PI, false); + } else { + context.arc(x, y, options.radius, 0, 2 * Math.PI, true); + if (options.fill) context.fill(); + } + context.stroke(); + context.closePath(); + } + } +}); + +/** Radar **/ +Flotr.addType('radar', { + options: { + show: false, // => setting to true will show radar chart, false will hide + lineWidth: 2, // => line width in pixels + fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill + fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill + radiusRatio: 0.90, // => ratio of the radar, against the plot size + sensibility: 2 // => the lower this number, the more precise you have to aim to show a value. + }, + draw : function (options) { + var + context = options.context, + shadowSize = options.shadowSize; + + context.save(); + context.translate(options.width / 2, options.height / 2); + context.lineWidth = options.lineWidth; + + // Shadow + context.fillStyle = 'rgba(0,0,0,0.05)'; + context.strokeStyle = 'rgba(0,0,0,0.05)'; + this.plot(options, shadowSize / 2); + context.strokeStyle = 'rgba(0,0,0,0.1)'; + this.plot(options, shadowSize / 4); + + // Chart + context.strokeStyle = options.color; + context.fillStyle = options.fillStyle; + this.plot(options); + + context.restore(); + }, + plot : function (options, offset) { + var + data = options.data, + context = options.context, + radius = Math.min(options.height, options.width) * options.radiusRatio / 2, + step = 2 * Math.PI / data.length, + angle = -Math.PI / 2, + i, ratio; + + offset = offset || 0; + + context.beginPath(); + for (i = 0; i < data.length; ++i) { + ratio = data[i][1] / this.max; + + context[i === 0 ? 'moveTo' : 'lineTo']( + Math.cos(i * step + angle) * radius * ratio + offset, + Math.sin(i * step + angle) * radius * ratio + offset + ); + } + context.closePath(); + if (options.fill) context.fill(); + context.stroke(); + }, + getGeometry : function (point, options) { + var + radius = Math.min(options.height, options.width) * options.radiusRatio / 2, + step = 2 * Math.PI / options.data.length, + angle = -Math.PI / 2, + ratio = point[1] / this.max; + + return { + x : (Math.cos(point[0] * step + angle) * radius * ratio) + options.width / 2, + y : (Math.sin(point[0] * step + angle) * radius * ratio) + options.height / 2 + }; + }, + hit : function (options) { + var + args = options.args, + mouse = args[0], + n = args[1], + relX = mouse.relX, + relY = mouse.relY, + distance, + geometry, + dx, dy; + + for (var i = 0; i < n.series.length; i++) { + var serie = n.series[i]; + var data = serie.data; + + for (var j = data.length; j--;) { + geometry = this.getGeometry(data[j], options); + + dx = geometry.x - relX; + dy = geometry.y - relY; + distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < options.sensibility*2) { + n.x = data[j][0]; + n.y = data[j][1]; + n.index = j; + n.seriesIndex = i; + return n; + } + } + } + }, + drawHit : function (options) { + var step = 2 * Math.PI / options.data.length; + var angle = -Math.PI / 2; + var radius = Math.min(options.height, options.width) * options.radiusRatio / 2; + + var s = options.args.series; + var point_radius = s.points.hitRadius || s.points.radius || s.mouse.radius; + + var context = options.context; + + context.translate(options.width / 2, options.height / 2); + + var j = options.args.index; + var ratio = options.data[j][1] / this.max; + var x = Math.cos(j * step + angle) * radius * ratio; + var y = Math.sin(j * step + angle) * radius * ratio; + context.beginPath(); + context.arc(x, y, point_radius , 0, 2 * Math.PI, true); + context.closePath(); + context.stroke(); + }, + clearHit : function (options) { + var step = 2 * Math.PI / options.data.length; + var angle = -Math.PI / 2; + var radius = Math.min(options.height, options.width) * options.radiusRatio / 2; + + var context = options.context; + + var + s = options.args.series, + lw = (s.points ? s.points.lineWidth : 1); + offset = (s.points.hitRadius || s.points.radius || s.mouse.radius) + lw; + + context.translate(options.width / 2, options.height / 2); + + var j = options.args.index; + var ratio = options.data[j][1] / this.max; + var x = Math.cos(j * step + angle) * radius * ratio; + var y = Math.sin(j * step + angle) * radius * ratio; + context.clearRect(x-offset,y-offset,offset*2,offset*2); + }, + extendYRange : function (axis, data) { + this.max = Math.max(axis.max, this.max || -Number.MAX_VALUE); + } +}); + +Flotr.addType('timeline', { + options: { + show: false, + lineWidth: 1, + barWidth: 0.2, + fill: true, + fillColor: null, + fillOpacity: 0.4, + centered: true + }, + + draw : function (options) { + + var + context = options.context; + + context.save(); + context.lineJoin = 'miter'; + context.lineWidth = options.lineWidth; + context.strokeStyle = options.color; + context.fillStyle = options.fillStyle; + + this.plot(options); + + context.restore(); + }, + + plot : function (options) { + + var + data = options.data, + context = options.context, + xScale = options.xScale, + yScale = options.yScale, + barWidth = options.barWidth, + lineWidth = options.lineWidth, + i; + + Flotr._.each(data, function (timeline) { + + var + x = timeline[0], + y = timeline[1], + w = timeline[2], + h = barWidth, + + xt = Math.ceil(xScale(x)), + wt = Math.ceil(xScale(x + w)) - xt, + yt = Math.round(yScale(y)), + ht = Math.round(yScale(y - h)) - yt, + + x0 = xt - lineWidth / 2, + y0 = Math.round(yt - ht / 2) - lineWidth / 2; + + context.strokeRect(x0, y0, wt, ht); + context.fillRect(x0, y0, wt, ht); + + }); + }, + + extendRange : function (series) { + + var + data = series.data, + xa = series.xaxis, + ya = series.yaxis, + w = series.timeline.barWidth; + + if (xa.options.min === null) + xa.min = xa.datamin - w / 2; + + if (xa.options.max === null) { + + var + max = xa.max; + + Flotr._.each(data, function (timeline) { + max = Math.max(max, timeline[0] + timeline[2]); + }, this); + + xa.max = max + w / 2; + } + + if (ya.options.min === null) + ya.min = ya.datamin - w; + if (ya.options.min === null) + ya.max = ya.datamax + w; + } + +}); + +(function () { + +var D = Flotr.DOM; + +Flotr.addPlugin('crosshair', { + options: { + mode: null, // => one of null, 'x', 'y' or 'xy' + color: '#FF0000', // => crosshair color + hideCursor: true // => hide the cursor when the crosshair is shown + }, + callbacks: { + 'flotr:mousemove': function(e, pos) { + if (this.options.crosshair.mode) { + this.crosshair.clearCrosshair(); + this.crosshair.drawCrosshair(pos); + } + } + }, + /** + * Draws the selection box. + */ + drawCrosshair: function(pos) { + var octx = this.octx, + options = this.options.crosshair, + plotOffset = this.plotOffset, + x = plotOffset.left + Math.round(pos.relX) + 0.5, + y = plotOffset.top + Math.round(pos.relY) + 0.5; + + if (pos.relX < 0 || pos.relY < 0 || pos.relX > this.plotWidth || pos.relY > this.plotHeight) { + this.el.style.cursor = null; + D.removeClass(this.el, 'flotr-crosshair'); + return; + } + + if (options.hideCursor) { + this.el.style.cursor = 'none'; + D.addClass(this.el, 'flotr-crosshair'); + } + + octx.save(); + octx.strokeStyle = options.color; + octx.lineWidth = 1; + octx.beginPath(); + + if (options.mode.indexOf('x') != -1) { + octx.moveTo(x, plotOffset.top); + octx.lineTo(x, plotOffset.top + this.plotHeight); + } + + if (options.mode.indexOf('y') != -1) { + octx.moveTo(plotOffset.left, y); + octx.lineTo(plotOffset.left + this.plotWidth, y); + } + + octx.stroke(); + octx.restore(); + }, + /** + * Removes the selection box from the overlay canvas. + */ + clearCrosshair: function() { + + var + plotOffset = this.plotOffset, + position = this.lastMousePos, + context = this.octx; + + if (position) { + context.clearRect( + Math.round(position.relX) + plotOffset.left, + plotOffset.top, + 1, + this.plotHeight + 1 + ); + context.clearRect( + plotOffset.left, + Math.round(position.relY) + plotOffset.top, + this.plotWidth + 1, + 1 + ); + } + } +}); +})(); + +(function() { + +var + D = Flotr.DOM, + _ = Flotr._; + +function getImage (type, canvas, context, width, height, background) { + + // TODO add scaling for w / h + var + mime = 'image/'+type, + data = context.getImageData(0, 0, width, height), + image = new Image(); + + context.save(); + context.globalCompositeOperation = 'destination-over'; + context.fillStyle = background; + context.fillRect(0, 0, width, height); + image.src = canvas.toDataURL(mime); + context.restore(); + + context.clearRect(0, 0, width, height); + context.putImageData(data, 0, 0); + + return image; +} + +Flotr.addPlugin('download', { + + saveImage: function (type, width, height, replaceCanvas) { + var + grid = this.options.grid, + image; + + if (Flotr.isIE && Flotr.isIE < 9) { + image = ''+this.canvas.firstChild.innerHTML+''; + return window.open().document.write(image); + } + + if (type !== 'jpeg' && type !== 'png') return; + + image = getImage( + type, this.canvas, this.ctx, + this.canvasWidth, this.canvasHeight, + grid && grid.backgroundColor || '#ffffff' + ); + + if (_.isElement(image) && replaceCanvas) { + this.download.restoreCanvas(); + D.hide(this.canvas); + D.hide(this.overlay); + D.setStyles({position: 'absolute'}); + D.insert(this.el, image); + this.saveImageElement = image; + } else { + return window.open(image.src); + } + }, + + restoreCanvas: function() { + D.show(this.canvas); + D.show(this.overlay); + if (this.saveImageElement) this.el.removeChild(this.saveImageElement); + this.saveImageElement = null; + } +}); + +})(); + +(function () { + +var E = Flotr.EventAdapter, + _ = Flotr._; + +Flotr.addPlugin('graphGrid', { + + callbacks: { + 'flotr:beforedraw' : function () { + this.graphGrid.drawGrid(); + }, + 'flotr:afterdraw' : function () { + this.graphGrid.drawOutline(); + } + }, + + drawGrid: function(){ + + var + ctx = this.ctx, + options = this.options, + grid = options.grid, + verticalLines = grid.verticalLines, + horizontalLines = grid.horizontalLines, + minorVerticalLines = grid.minorVerticalLines, + minorHorizontalLines = grid.minorHorizontalLines, + plotHeight = this.plotHeight, + plotWidth = this.plotWidth, + a, v, i, j; + + if(verticalLines || minorVerticalLines || + horizontalLines || minorHorizontalLines){ + E.fire(this.el, 'flotr:beforegrid', [this.axes.x, this.axes.y, options, this]); + } + ctx.save(); + ctx.lineWidth = 1; + ctx.strokeStyle = grid.tickColor; + + function circularHorizontalTicks (ticks) { + for(i = 0; i < ticks.length; ++i){ + var ratio = ticks[i].v / a.max; + for(j = 0; j <= sides; ++j){ + ctx[j === 0 ? 'moveTo' : 'lineTo']( + Math.cos(j*coeff+angle)*radius*ratio, + Math.sin(j*coeff+angle)*radius*ratio + ); + } + } + } + function drawGridLines (ticks, callback) { + _.each(_.pluck(ticks, 'v'), function(v){ + // Don't show lines on upper and lower bounds. + if ((v <= a.min || v >= a.max) || + (v == a.min || v == a.max) && grid.outlineWidth) + return; + callback(Math.floor(a.d2p(v)) + ctx.lineWidth/2); + }); + } + function drawVerticalLines (x) { + ctx.moveTo(x, 0); + ctx.lineTo(x, plotHeight); + } + function drawHorizontalLines (y) { + ctx.moveTo(0, y); + ctx.lineTo(plotWidth, y); + } + + if (grid.circular) { + ctx.translate(this.plotOffset.left+plotWidth/2, this.plotOffset.top+plotHeight/2); + var radius = Math.min(plotHeight, plotWidth)*options.radar.radiusRatio/2, + sides = this.axes.x.ticks.length, + coeff = 2*(Math.PI/sides), + angle = -Math.PI/2; + + // Draw grid lines in vertical direction. + ctx.beginPath(); + + a = this.axes.y; + + if(horizontalLines){ + circularHorizontalTicks(a.ticks); + } + if(minorHorizontalLines){ + circularHorizontalTicks(a.minorTicks); + } + + if(verticalLines){ + _.times(sides, function(i){ + ctx.moveTo(0, 0); + ctx.lineTo(Math.cos(i*coeff+angle)*radius, Math.sin(i*coeff+angle)*radius); + }); + } + ctx.stroke(); + } + else { + ctx.translate(this.plotOffset.left, this.plotOffset.top); + + // Draw grid background, if present in options. + if(grid.backgroundColor){ + ctx.fillStyle = this.processColor(grid.backgroundColor, {x1: 0, y1: 0, x2: plotWidth, y2: plotHeight}); + ctx.fillRect(0, 0, plotWidth, plotHeight); + } + + ctx.beginPath(); + + a = this.axes.x; + if (verticalLines) drawGridLines(a.ticks, drawVerticalLines); + if (minorVerticalLines) drawGridLines(a.minorTicks, drawVerticalLines); + + a = this.axes.y; + if (horizontalLines) drawGridLines(a.ticks, drawHorizontalLines); + if (minorHorizontalLines) drawGridLines(a.minorTicks, drawHorizontalLines); + + ctx.stroke(); + } + + ctx.restore(); + if(verticalLines || minorVerticalLines || + horizontalLines || minorHorizontalLines){ + E.fire(this.el, 'flotr:aftergrid', [this.axes.x, this.axes.y, options, this]); + } + }, + + drawOutline: function(){ + var + that = this, + options = that.options, + grid = options.grid, + outline = grid.outline, + ctx = that.ctx, + backgroundImage = grid.backgroundImage, + plotOffset = that.plotOffset, + leftOffset = plotOffset.left, + topOffset = plotOffset.top, + plotWidth = that.plotWidth, + plotHeight = that.plotHeight, + v, img, src, left, top, globalAlpha; + + if (!grid.outlineWidth) return; + + ctx.save(); + + if (grid.circular) { + ctx.translate(leftOffset + plotWidth / 2, topOffset + plotHeight / 2); + var radius = Math.min(plotHeight, plotWidth) * options.radar.radiusRatio / 2, + sides = this.axes.x.ticks.length, + coeff = 2*(Math.PI/sides), + angle = -Math.PI/2; + + // Draw axis/grid border. + ctx.beginPath(); + ctx.lineWidth = grid.outlineWidth; + ctx.strokeStyle = grid.color; + ctx.lineJoin = 'round'; + + for(i = 0; i <= sides; ++i){ + ctx[i === 0 ? 'moveTo' : 'lineTo'](Math.cos(i*coeff+angle)*radius, Math.sin(i*coeff+angle)*radius); + } + //ctx.arc(0, 0, radius, 0, Math.PI*2, true); + + ctx.stroke(); + } + else { + ctx.translate(leftOffset, topOffset); + + // Draw axis/grid border. + var lw = grid.outlineWidth, + orig = 0.5-lw+((lw+1)%2/2), + lineTo = 'lineTo', + moveTo = 'moveTo'; + ctx.lineWidth = lw; + ctx.strokeStyle = grid.color; + ctx.lineJoin = 'miter'; + ctx.beginPath(); + ctx.moveTo(orig, orig); + plotWidth = plotWidth - (lw / 2) % 1; + plotHeight = plotHeight + lw / 2; + ctx[outline.indexOf('n') !== -1 ? lineTo : moveTo](plotWidth, orig); + ctx[outline.indexOf('e') !== -1 ? lineTo : moveTo](plotWidth, plotHeight); + ctx[outline.indexOf('s') !== -1 ? lineTo : moveTo](orig, plotHeight); + ctx[outline.indexOf('w') !== -1 ? lineTo : moveTo](orig, orig); + ctx.stroke(); + ctx.closePath(); + } + + ctx.restore(); + + if (backgroundImage) { + + src = backgroundImage.src || backgroundImage; + left = (parseInt(backgroundImage.left, 10) || 0) + plotOffset.left; + top = (parseInt(backgroundImage.top, 10) || 0) + plotOffset.top; + img = new Image(); + + img.onload = function() { + ctx.save(); + if (backgroundImage.alpha) ctx.globalAlpha = backgroundImage.alpha; + ctx.globalCompositeOperation = 'destination-over'; + ctx.drawImage(img, 0, 0, img.width, img.height, left, top, plotWidth, plotHeight); + ctx.restore(); + }; + + img.src = src; + } + } +}); + +})(); + +(function () { + +var + D = Flotr.DOM, + _ = Flotr._, + flotr = Flotr, + S_MOUSETRACK = 'opacity:0.7;background-color:#000;color:#fff;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;'; + +Flotr.addPlugin('hit', { + callbacks: { + 'flotr:mousemove': function(e, pos) { + this.hit.track(pos); + }, + 'flotr:click': function(pos) { + var + hit = this.hit.track(pos); + if (hit && !_.isUndefined(hit.index)) pos.hit = hit; + }, + 'flotr:mouseout': function(e) { + if (e.relatedTarget !== this.mouseTrack) { + this.hit.clearHit(); + } + }, + 'flotr:destroy': function() { + if (this.options.mouse.container) { + D.remove(this.mouseTrack); + } + this.mouseTrack = null; + } + }, + track : function (pos) { + if (this.options.mouse.track || _.any(this.series, function(s){return s.mouse && s.mouse.track;})) { + return this.hit.hit(pos); + } + }, + /** + * Try a method on a graph type. If the method exists, execute it. + * @param {Object} series + * @param {String} method Method name. + * @param {Array} args Arguments applied to method. + * @return executed successfully or failed. + */ + executeOnType: function(s, method, args){ + var + success = false, + options; + + if (!_.isArray(s)) s = [s]; + + function e(s, index) { + _.each(_.keys(flotr.graphTypes), function (type) { + if (s[type] && s[type].show && !s.hide && this[type][method]) { + options = this.getOptions(s, type); + + options.fill = !!s.mouse.fillColor; + options.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity}); + options.color = s.mouse.lineColor; + options.context = this.octx; + options.index = index; + + if (args) options.args = args; + this[type][method].call(this[type], options); + success = true; + } + }, this); + } + _.each(s, e, this); + + return success; + }, + /** + * Updates the mouse tracking point on the overlay. + */ + drawHit: function(n){ + var octx = this.octx, + s = n.series; + + if (s.mouse.lineColor) { + octx.save(); + octx.lineWidth = (s.points ? s.points.lineWidth : 1); + octx.strokeStyle = s.mouse.lineColor; + octx.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity}); + octx.translate(this.plotOffset.left, this.plotOffset.top); + + if (!this.hit.executeOnType(s, 'drawHit', n)) { + var + xa = n.xaxis, + ya = n.yaxis; + + octx.beginPath(); + // TODO fix this (points) should move to general testable graph mixin + octx.arc(xa.d2p(n.x), ya.d2p(n.y), s.points.hitRadius || s.points.radius || s.mouse.radius, 0, 2 * Math.PI, true); + octx.fill(); + octx.stroke(); + octx.closePath(); + } + octx.restore(); + this.clip(octx); + } + this.prevHit = n; + }, + /** + * Removes the mouse tracking point from the overlay. + */ + clearHit: function(){ + var prev = this.prevHit, + octx = this.octx, + plotOffset = this.plotOffset; + octx.save(); + octx.translate(plotOffset.left, plotOffset.top); + if (prev) { + if (!this.hit.executeOnType(prev.series, 'clearHit', this.prevHit)) { + // TODO fix this (points) should move to general testable graph mixin + var + s = prev.series, + lw = (s.points ? s.points.lineWidth : 1); + offset = (s.points.hitRadius || s.points.radius || s.mouse.radius) + lw; + octx.clearRect( + prev.xaxis.d2p(prev.x) - offset, + prev.yaxis.d2p(prev.y) - offset, + offset*2, + offset*2 + ); + } + D.hide(this.mouseTrack); + this.prevHit = null; + } + octx.restore(); + }, + /** + * Retrieves the nearest data point from the mouse cursor. If it's within + * a certain range, draw a point on the overlay canvas and display the x and y + * value of the data. + * @param {Object} mouse - Object that holds the relative x and y coordinates of the cursor. + */ + hit : function (mouse) { + + var + options = this.options, + prevHit = this.prevHit, + closest, sensibility, dataIndex, seriesIndex, series, value, xaxis, yaxis, n; + + if (this.series.length === 0) return; + + // Nearest data element. + // dist, x, y, relX, relY, absX, absY, sAngle, eAngle, fraction, mouse, + // xaxis, yaxis, series, index, seriesIndex + n = { + relX : mouse.relX, + relY : mouse.relY, + absX : mouse.absX, + absY : mouse.absY, + series: this.series + }; + + if (options.mouse.trackY && + !options.mouse.trackAll && + this.hit.executeOnType(this.series, 'hit', [mouse, n]) && + !_.isUndefined(n.seriesIndex)) + { + series = this.series[n.seriesIndex]; + n.series = series; + n.mouse = series.mouse; + n.xaxis = series.xaxis; + n.yaxis = series.yaxis; + } else { + + closest = this.hit.closest(mouse); + + if (closest) { + + closest = options.mouse.trackY ? closest.point : closest.x; + seriesIndex = closest.seriesIndex; + series = this.series[seriesIndex]; + xaxis = series.xaxis; + yaxis = series.yaxis; + sensibility = 2 * series.mouse.sensibility; + + if + (options.mouse.trackAll || + (closest.distanceX < sensibility / xaxis.scale && + (!options.mouse.trackY || closest.distanceY < sensibility / yaxis.scale))) + { + n.series = series; + n.xaxis = series.xaxis; + n.yaxis = series.yaxis; + n.mouse = series.mouse; + n.x = closest.x; + n.y = closest.y; + n.dist = closest.distance; + n.index = closest.dataIndex; + n.seriesIndex = seriesIndex; + } + } + } + + if (!prevHit || (prevHit.index !== n.index || prevHit.seriesIndex !== n.seriesIndex)) { + this.hit.clearHit(); + if (n.series && n.mouse && n.mouse.track) { + this.hit.drawMouseTrack(n); + this.hit.drawHit(n); + Flotr.EventAdapter.fire(this.el, 'flotr:hit', [n, this]); + } + } + + return n; + }, + + closest : function (mouse) { + + var + series = this.series, + options = this.options, + relX = mouse.relX, + relY = mouse.relY, + compare = Number.MAX_VALUE, + compareX = Number.MAX_VALUE, + closest = {}, + closestX = {}, + check = false, + serie, data, + distance, distanceX, distanceY, + mouseX, mouseY, + x, y, i, j; + + function setClosest (o) { + o.distance = distance; + o.distanceX = distanceX; + o.distanceY = distanceY; + o.seriesIndex = i; + o.dataIndex = j; + o.x = x; + o.y = y; + check = true; + } + + for (i = 0; i < series.length; i++) { + + serie = series[i]; + data = serie.data; + mouseX = serie.xaxis.p2d(relX); + mouseY = serie.yaxis.p2d(relY); + + if (serie.hide) continue; + + for (j = data.length; j--;) { + + x = data[j][0]; + y = data[j][1]; + // Add stack offset if exists + if (data[j].y0) y += data[j].y0; + + if (x === null || y === null) continue; + + // don't check if the point isn't visible in the current range + if (x < serie.xaxis.min || x > serie.xaxis.max) continue; + + distanceX = Math.abs(x - mouseX); + distanceY = Math.abs(y - mouseY); + + // Skip square root for speed + distance = distanceX * distanceX + distanceY * distanceY; + + if (distance < compare) { + compare = distance; + setClosest(closest); + } + + if (distanceX < compareX) { + compareX = distanceX; + setClosest(closestX); + } + } + } + + return check ? { + point : closest, + x : closestX + } : false; + }, + + drawMouseTrack : function (n) { + + var + pos = '', + s = n.series, + p = n.mouse.position, + m = n.mouse.margin, + x = n.x, + y = n.y, + elStyle = S_MOUSETRACK, + mouseTrack = this.mouseTrack, + plotOffset = this.plotOffset, + left = plotOffset.left, + right = plotOffset.right, + bottom = plotOffset.bottom, + top = plotOffset.top, + decimals = n.mouse.trackDecimals, + options = this.options, + container = options.mouse.container, + oTop = 0, + oLeft = 0, + offset, size, content; + + // Create + if (!mouseTrack) { + mouseTrack = D.node('
'); + this.mouseTrack = mouseTrack; + D.insert(container || this.el, mouseTrack); + } + + // Fill tracker: + if (!decimals || decimals < 0) decimals = 0; + if (x && x.toFixed) x = x.toFixed(decimals); + if (y && y.toFixed) y = y.toFixed(decimals); + content = n.mouse.trackFormatter({ + x: x, + y: y, + series: n.series, + index: n.index, + nearest: n, + fraction: n.fraction + }); + if (_.isNull(content) || _.isUndefined(content)) { + D.hide(mouseTrack); + return; + } else { + mouseTrack.innerHTML = content; + D.show(mouseTrack); + } + + // Positioning + if (!p) { + return; + } + size = D.size(mouseTrack); + if (container) { + offset = D.position(this.el); + oTop = offset.top; + oLeft = offset.left; + } + + if (!n.mouse.relative) { // absolute to the canvas + pos += 'top:'; + if (p.charAt(0) == 'n') pos += (oTop + m + top); + else if (p.charAt(0) == 's') pos += (oTop - m + top + this.plotHeight - size.height); + pos += 'px;bottom:auto;left:'; + if (p.charAt(1) == 'e') pos += (oLeft - m + left + this.plotWidth - size.width); + else if (p.charAt(1) == 'w') pos += (oLeft + m + left); + pos += 'px;right:auto;'; + + // Pie + } else if (s.pie && s.pie.show) { + var center = { + x: (this.plotWidth)/2, + y: (this.plotHeight)/2 + }, + radius = (Math.min(this.canvasWidth, this.canvasHeight) * s.pie.sizeRatio) / 2, + bisection = n.sAngle one of null, 'x', 'y' or 'xy' + color: '#B6D9FF', // => selection box color + fps: 20 // => frames-per-second + }, + + callbacks: { + 'flotr:mouseup' : function (event) { + + var + options = this.options.selection, + selection = this.selection, + pointer = this.getEventPosition(event); + + if (!options || !options.mode) return; + if (selection.interval) clearInterval(selection.interval); + + if (this.multitouches) { + selection.updateSelection(); + } else + if (!options.pinchOnly) { + selection.setSelectionPos(selection.selection.second, pointer); + } + selection.clearSelection(); + + if(selection.selecting && selection.selectionIsSane()){ + selection.drawSelection(); + selection.fireSelectEvent(); + this.ignoreClick = true; + } + }, + 'flotr:mousedown' : function (event) { + + var + options = this.options.selection, + selection = this.selection, + pointer = this.getEventPosition(event); + + if (!options || !options.mode) return; + if (!options.mode || (!isLeftClick(event) && _.isUndefined(event.touches))) return; + if (!options.pinchOnly) selection.setSelectionPos(selection.selection.first, pointer); + if (selection.interval) clearInterval(selection.interval); + + this.lastMousePos.pageX = null; + selection.selecting = false; + selection.interval = setInterval( + _.bind(selection.updateSelection, this), + 1000 / options.fps + ); + }, + 'flotr:destroy' : function (event) { + clearInterval(this.selection.interval); + } + }, + + // TODO This isn't used. Maybe it belongs in the draw area and fire select event methods? + getArea: function() { + + var + s = this.selection.selection, + a = this.axes, + first = s.first, + second = s.second, + x1, x2, y1, y2; + + x1 = a.x.p2d(s.first.x); + x2 = a.x.p2d(s.second.x); + y1 = a.y.p2d(s.first.y); + y2 = a.y.p2d(s.second.y); + + return { + x1 : Math.min(x1, x2), + y1 : Math.min(y1, y2), + x2 : Math.max(x1, x2), + y2 : Math.max(y1, y2), + xfirst : x1, + xsecond : x2, + yfirst : y1, + ysecond : y2 + }; + }, + + selection: {first: {x: -1, y: -1}, second: {x: -1, y: -1}}, + prevSelection: null, + interval: null, + + /** + * Fires the 'flotr:select' event when the user made a selection. + */ + fireSelectEvent: function(name){ + var + area = this.selection.getArea(); + name = name || 'select'; + area.selection = this.selection.selection; + E.fire(this.el, 'flotr:'+name, [area, this]); + }, + + /** + * Allows the user the manually select an area. + * @param {Object} area - Object with coordinates to select. + */ + setSelection: function(area, preventEvent){ + var options = this.options, + xa = this.axes.x, + ya = this.axes.y, + vertScale = ya.scale, + hozScale = xa.scale, + selX = options.selection.mode.indexOf('x') != -1, + selY = options.selection.mode.indexOf('y') != -1, + s = this.selection.selection; + + this.selection.clearSelection(); + + s.first.y = boundY((selX && !selY) ? 0 : (ya.max - area.y1) * vertScale, this); + s.second.y = boundY((selX && !selY) ? this.plotHeight - 1: (ya.max - area.y2) * vertScale, this); + s.first.x = boundX((selY && !selX) ? 0 : (area.x1 - xa.min) * hozScale, this); + s.second.x = boundX((selY && !selX) ? this.plotWidth : (area.x2 - xa.min) * hozScale, this); + + this.selection.drawSelection(); + if (!preventEvent) + this.selection.fireSelectEvent(); + }, + + /** + * Calculates the position of the selection. + * @param {Object} pos - Position object. + * @param {Event} event - Event object. + */ + setSelectionPos: function(pos, pointer) { + var mode = this.options.selection.mode, + selection = this.selection.selection; + + if(mode.indexOf('x') == -1) { + pos.x = (pos == selection.first) ? 0 : this.plotWidth; + }else{ + pos.x = boundX(pointer.relX, this); + } + + if (mode.indexOf('y') == -1) { + pos.y = (pos == selection.first) ? 0 : this.plotHeight - 1; + }else{ + pos.y = boundY(pointer.relY, this); + } + }, + /** + * Draws the selection box. + */ + drawSelection: function() { + + this.selection.fireSelectEvent('selecting'); + + var s = this.selection.selection, + octx = this.octx, + options = this.options, + plotOffset = this.plotOffset, + prevSelection = this.selection.prevSelection; + + if (prevSelection && + s.first.x == prevSelection.first.x && + s.first.y == prevSelection.first.y && + s.second.x == prevSelection.second.x && + s.second.y == prevSelection.second.y) { + return; + } + + octx.save(); + octx.strokeStyle = this.processColor(options.selection.color, {opacity: 0.8}); + octx.lineWidth = 1; + octx.lineJoin = 'miter'; + octx.fillStyle = this.processColor(options.selection.color, {opacity: 0.4}); + + this.selection.prevSelection = { + first: { x: s.first.x, y: s.first.y }, + second: { x: s.second.x, y: s.second.y } + }; + + var x = Math.min(s.first.x, s.second.x), + y = Math.min(s.first.y, s.second.y), + w = Math.abs(s.second.x - s.first.x), + h = Math.abs(s.second.y - s.first.y); + + octx.fillRect(x + plotOffset.left+0.5, y + plotOffset.top+0.5, w, h); + octx.strokeRect(x + plotOffset.left+0.5, y + plotOffset.top+0.5, w, h); + octx.restore(); + }, + + /** + * Updates (draws) the selection box. + */ + updateSelection: function(){ + if (!this.lastMousePos.pageX) return; + + this.selection.selecting = true; + + if (this.multitouches) { + this.selection.setSelectionPos(this.selection.selection.first, this.getEventPosition(this.multitouches[0])); + this.selection.setSelectionPos(this.selection.selection.second, this.getEventPosition(this.multitouches[1])); + } else + if (this.options.selection.pinchOnly) { + return; + } else { + this.selection.setSelectionPos(this.selection.selection.second, this.lastMousePos); + } + + this.selection.clearSelection(); + + if(this.selection.selectionIsSane()) { + this.selection.drawSelection(); + } + }, + + /** + * Removes the selection box from the overlay canvas. + */ + clearSelection: function() { + if (!this.selection.prevSelection) return; + + var prevSelection = this.selection.prevSelection, + lw = 1, + plotOffset = this.plotOffset, + x = Math.min(prevSelection.first.x, prevSelection.second.x), + y = Math.min(prevSelection.first.y, prevSelection.second.y), + w = Math.abs(prevSelection.second.x - prevSelection.first.x), + h = Math.abs(prevSelection.second.y - prevSelection.first.y); + + this.octx.clearRect(x + plotOffset.left - lw + 0.5, + y + plotOffset.top - lw, + w + 2 * lw + 0.5, + h + 2 * lw + 0.5); + + this.selection.prevSelection = null; + }, + /** + * Determines whether or not the selection is sane and should be drawn. + * @return {Boolean} - True when sane, false otherwise. + */ + selectionIsSane: function(){ + var s = this.selection.selection; + return Math.abs(s.second.x - s.first.x) >= 5 || + Math.abs(s.second.y - s.first.y) >= 5; + } + +}); + +})(); + +(function () { + +var D = Flotr.DOM; + +Flotr.addPlugin('labels', { + + callbacks : { + 'flotr:afterdraw' : function () { + this.labels.draw(); + } + }, + + draw: function(){ + // Construct fixed width label boxes, which can be styled easily. + var + axis, tick, left, top, xBoxWidth, + radius, sides, coeff, angle, + div, i, html = '', + noLabels = 0, + options = this.options, + ctx = this.ctx, + a = this.axes, + style = { size: options.fontSize }; + + for (i = 0; i < a.x.ticks.length; ++i){ + if (a.x.ticks[i].label) { ++noLabels; } + } + xBoxWidth = this.plotWidth / noLabels; + + if (options.grid.circular) { + ctx.save(); + ctx.translate(this.plotOffset.left + this.plotWidth / 2, + this.plotOffset.top + this.plotHeight / 2); + + radius = this.plotHeight * options.radar.radiusRatio / 2 + options.fontSize; + sides = this.axes.x.ticks.length; + coeff = 2 * (Math.PI / sides); + angle = -Math.PI / 2; + + drawLabelCircular(this, a.x, false); + drawLabelCircular(this, a.x, true); + drawLabelCircular(this, a.y, false); + drawLabelCircular(this, a.y, true); + ctx.restore(); + } + + if (!options.HtmlText && this.textEnabled) { + drawLabelNoHtmlText(this, a.x, 'center', 'top'); + drawLabelNoHtmlText(this, a.x2, 'center', 'bottom'); + drawLabelNoHtmlText(this, a.y, 'right', 'middle'); + drawLabelNoHtmlText(this, a.y2, 'left', 'middle'); + + } else if (( + a.x.options.showLabels || + a.x2.options.showLabels || + a.y.options.showLabels || + a.y2.options.showLabels) && + !options.grid.circular + ) { + + html = ''; + + drawLabelHtml(this, a.x); + drawLabelHtml(this, a.x2); + drawLabelHtml(this, a.y); + drawLabelHtml(this, a.y2); + + ctx.stroke(); + ctx.restore(); + div = D.create('div'); + D.setStyles(div, { + fontSize: 'smaller', + color: options.grid.color + }); + div.className = 'flotr-labels'; + D.insert(this.el, div); + D.insert(div, html); + } + + function drawLabelCircular (graph, axis, minorTicks) { + var + ticks = minorTicks ? axis.minorTicks : axis.ticks, + isX = axis.orientation === 1, + isFirst = axis.n === 1, + style, offset; + + style = { + color : axis.options.color || options.grid.color, + angle : Flotr.toRad(axis.options.labelsAngle), + textBaseline : 'middle' + }; + + for (i = 0; i < ticks.length && + (minorTicks ? axis.options.showMinorLabels : axis.options.showLabels); ++i){ + tick = ticks[i]; + tick.label += ''; + if (!tick.label || !tick.label.length) { continue; } + + x = Math.cos(i * coeff + angle) * radius; + y = Math.sin(i * coeff + angle) * radius; + + style.textAlign = isX ? (Math.abs(x) < 0.1 ? 'center' : (x < 0 ? 'right' : 'left')) : 'left'; + + Flotr.drawText( + ctx, tick.label, + isX ? x : 3, + isX ? y : -(axis.ticks[i].v / axis.max) * (radius - options.fontSize), + style + ); + } + } + + function drawLabelNoHtmlText (graph, axis, textAlign, textBaseline) { + var + isX = axis.orientation === 1, + isFirst = axis.n === 1, + style, offset; + + style = { + color : axis.options.color || options.grid.color, + textAlign : textAlign, + textBaseline : textBaseline, + angle : Flotr.toRad(axis.options.labelsAngle) + }; + style = Flotr.getBestTextAlign(style.angle, style); + + for (i = 0; i < axis.ticks.length && continueShowingLabels(axis); ++i) { + + tick = axis.ticks[i]; + if (!tick.label || !tick.label.length) { continue; } + + offset = axis.d2p(tick.v); + if (offset < 0 || + offset > (isX ? graph.plotWidth : graph.plotHeight)) { continue; } + + Flotr.drawText( + ctx, tick.label, + leftOffset(graph, isX, isFirst, offset), + topOffset(graph, isX, isFirst, offset), + style + ); + + // Only draw on axis y2 + if (!isX && !isFirst) { + ctx.save(); + ctx.strokeStyle = style.color; + ctx.beginPath(); + ctx.moveTo(graph.plotOffset.left + graph.plotWidth - 8, graph.plotOffset.top + axis.d2p(tick.v)); + ctx.lineTo(graph.plotOffset.left + graph.plotWidth, graph.plotOffset.top + axis.d2p(tick.v)); + ctx.stroke(); + ctx.restore(); + } + } + + function continueShowingLabels (axis) { + return axis.options.showLabels && axis.used; + } + function leftOffset (graph, isX, isFirst, offset) { + return graph.plotOffset.left + + (isX ? offset : + (isFirst ? + -options.grid.labelMargin : + options.grid.labelMargin + graph.plotWidth)); + } + function topOffset (graph, isX, isFirst, offset) { + return graph.plotOffset.top + + (isX ? options.grid.labelMargin : offset) + + ((isX && isFirst) ? graph.plotHeight : 0); + } + } + + function drawLabelHtml (graph, axis) { + var + isX = axis.orientation === 1, + isFirst = axis.n === 1, + name = '', + left, style, top, + offset = graph.plotOffset; + + if (!isX && !isFirst) { + ctx.save(); + ctx.strokeStyle = axis.options.color || options.grid.color; + ctx.beginPath(); + } + + if (axis.options.showLabels && (isFirst ? true : axis.used)) { + for (i = 0; i < axis.ticks.length; ++i) { + tick = axis.ticks[i]; + if (!tick.label || !tick.label.length || + ((isX ? offset.left : offset.top) + axis.d2p(tick.v) < 0) || + ((isX ? offset.left : offset.top) + axis.d2p(tick.v) > (isX ? graph.canvasWidth : graph.canvasHeight))) { + continue; + } + top = offset.top + + (isX ? + ((isFirst ? 1 : -1 ) * (graph.plotHeight + options.grid.labelMargin)) : + axis.d2p(tick.v) - axis.maxLabel.height / 2); + left = isX ? (offset.left + axis.d2p(tick.v) - xBoxWidth / 2) : 0; + + name = ''; + if (i === 0) { + name = ' first'; + } else if (i === axis.ticks.length - 1) { + name = ' last'; + } + name += isX ? ' flotr-grid-label-x' : ' flotr-grid-label-y'; + + html += [ + '
' + tick.label + '
' + ].join(' '); + + if (!isX && !isFirst) { + ctx.moveTo(offset.left + graph.plotWidth - 8, offset.top + axis.d2p(tick.v)); + ctx.lineTo(offset.left + graph.plotWidth, offset.top + axis.d2p(tick.v)); + } + } + } + } + } + +}); +})(); + +(function () { + +var + D = Flotr.DOM, + _ = Flotr._; + +Flotr.addPlugin('legend', { + options: { + show: true, // => setting to true will show the legend, hide otherwise + noColumns: 1, // => number of colums in legend table // @todo: doesn't work for HtmlText = false + labelFormatter: function(v){return v;}, // => fn: string -> string + labelBoxBorderColor: '#CCCCCC', // => border color for the little label boxes + labelBoxWidth: 14, + labelBoxHeight: 10, + labelBoxMargin: 5, + container: null, // => container (as jQuery object) to put legend in, null means default on top of graph + position: 'nw', // => position of default legend container within plot + margin: 5, // => distance from grid edge to default legend container within plot + backgroundColor: '#F0F0F0', // => Legend background color. + backgroundOpacity: 0.85// => set to 0 to avoid background, set to 1 for a solid background + }, + callbacks: { + 'flotr:afterinit': function() { + this.legend.insertLegend(); + }, + 'flotr:destroy': function() { + var markup = this.legend.markup; + if (markup) { + this.legend.markup = null; + D.remove(markup); + } + } + }, + /** + * Adds a legend div to the canvas container or draws it on the canvas. + */ + insertLegend: function(){ + + if(!this.options.legend.show) + return; + + var series = this.series, + plotOffset = this.plotOffset, + options = this.options, + legend = options.legend, + fragments = [], + rowStarted = false, + ctx = this.ctx, + itemCount = _.filter(series, function(s) {return (s.label && !s.hide);}).length, + p = legend.position, + m = legend.margin, + opacity = legend.backgroundOpacity, + i, label, color; + + if (itemCount) { + + var lbw = legend.labelBoxWidth, + lbh = legend.labelBoxHeight, + lbm = legend.labelBoxMargin, + offsetX = plotOffset.left + m, + offsetY = plotOffset.top + m, + labelMaxWidth = 0, + style = { + size: options.fontSize*1.1, + color: options.grid.color + }; + + // We calculate the labels' max width + for(i = series.length - 1; i > -1; --i){ + if(!series[i].label || series[i].hide) continue; + label = legend.labelFormatter(series[i].label); + labelMaxWidth = Math.max(labelMaxWidth, this._text.measureText(label, style).width); + } + + var legendWidth = Math.round(lbw + lbm*3 + labelMaxWidth), + legendHeight = Math.round(itemCount*(lbm+lbh) + lbm); + + // Default Opacity + if (!opacity && opacity !== 0) { + opacity = 0.1; + } + + if (!options.HtmlText && this.textEnabled && !legend.container) { + + if(p.charAt(0) == 's') offsetY = plotOffset.top + this.plotHeight - (m + legendHeight); + if(p.charAt(0) == 'c') offsetY = plotOffset.top + (this.plotHeight/2) - (m + (legendHeight/2)); + if(p.charAt(1) == 'e') offsetX = plotOffset.left + this.plotWidth - (m + legendWidth); + + // Legend box + color = this.processColor(legend.backgroundColor, { opacity : opacity }); + + ctx.fillStyle = color; + ctx.fillRect(offsetX, offsetY, legendWidth, legendHeight); + ctx.strokeStyle = legend.labelBoxBorderColor; + ctx.strokeRect(Flotr.toPixel(offsetX), Flotr.toPixel(offsetY), legendWidth, legendHeight); + + // Legend labels + var x = offsetX + lbm; + var y = offsetY + lbm; + for(i = 0; i < series.length; i++){ + if(!series[i].label || series[i].hide) continue; + label = legend.labelFormatter(series[i].label); + + ctx.fillStyle = series[i].color; + ctx.fillRect(x, y, lbw-1, lbh-1); + + ctx.strokeStyle = legend.labelBoxBorderColor; + ctx.lineWidth = 1; + ctx.strokeRect(Math.ceil(x)-1.5, Math.ceil(y)-1.5, lbw+2, lbh+2); + + // Legend text + Flotr.drawText(ctx, label, x + lbw + lbm, y + lbh, style); + + y += lbh + lbm; + } + } + else { + for(i = 0; i < series.length; ++i){ + if(!series[i].label || series[i].hide) continue; + + if(i % legend.noColumns === 0){ + fragments.push(rowStarted ? '' : ''); + rowStarted = true; + } + + var s = series[i], + boxWidth = legend.labelBoxWidth, + boxHeight = legend.labelBoxHeight; + + label = legend.labelFormatter(s.label); + color = 'background-color:' + ((s.bars && s.bars.show && s.bars.fillColor && s.bars.fill) ? s.bars.fillColor : s.color) + ';'; + + fragments.push( + '', + '
', + '
', // Border + '
', // Background + '
', + '
', + '', + '', label, '' + ); + } + if(rowStarted) fragments.push(''); + + if(fragments.length > 0){ + var table = '' + fragments.join('') + '
'; + if(legend.container){ + table = D.node(table); + this.legend.markup = table; + D.insert(legend.container, table); + } + else { + var styles = {position: 'absolute', 'zIndex': '2', 'border' : '1px solid ' + legend.labelBoxBorderColor}; + + if(p.charAt(0) == 'n') { styles.top = (m + plotOffset.top) + 'px'; styles.bottom = 'auto'; } + else if(p.charAt(0) == 'c') { styles.top = (m + (this.plotHeight - legendHeight) / 2) + 'px'; styles.bottom = 'auto'; } + else if(p.charAt(0) == 's') { styles.bottom = (m + plotOffset.bottom) + 'px'; styles.top = 'auto'; } + if(p.charAt(1) == 'e') { styles.right = (m + plotOffset.right) + 'px'; styles.left = 'auto'; } + else if(p.charAt(1) == 'w') { styles.left = (m + plotOffset.left) + 'px'; styles.right = 'auto'; } + + var div = D.create('div'), size; + div.className = 'flotr-legend'; + D.setStyles(div, styles); + D.insert(div, table); + D.insert(this.el, div); + + if (!opacity) return; + + var c = legend.backgroundColor || options.grid.backgroundColor || '#ffffff'; + + _.extend(styles, D.size(div), { + 'backgroundColor': c, + 'zIndex' : '', + 'border' : '' + }); + styles.width += 'px'; + styles.height += 'px'; + + // Put in the transparent background separately to avoid blended labels and + div = D.create('div'); + div.className = 'flotr-legend-bg'; + D.setStyles(div, styles); + D.opacity(div, opacity); + D.insert(div, ' '); + D.insert(this.el, div); + } + } + } + } + } +}); +})(); + +/** Spreadsheet **/ +(function() { + +function getRowLabel(value){ + if (this.options.spreadsheet.tickFormatter){ + //TODO maybe pass the xaxis formatter to the custom tick formatter as an opt-out? + return this.options.spreadsheet.tickFormatter(value); + } + else { + var t = _.find(this.axes.x.ticks, function(t){return t.v == value;}); + if (t) { + return t.label; + } + return value; + } +} + +var + D = Flotr.DOM, + _ = Flotr._; + +Flotr.addPlugin('spreadsheet', { + options: { + show: false, // => show the data grid using two tabs + tabGraphLabel: 'Graph', + tabDataLabel: 'Data', + toolbarDownload: 'Download CSV', // @todo: add better language support + toolbarSelectAll: 'Select all', + csvFileSeparator: ',', + decimalSeparator: '.', + tickFormatter: null, + initialTab: 'graph' + }, + /** + * Builds the tabs in the DOM + */ + callbacks: { + 'flotr:afterconstruct': function(){ + // @TODO necessary? + //this.el.select('.flotr-tabs-group,.flotr-datagrid-container').invoke('remove'); + + if (!this.options.spreadsheet.show) return; + + var ss = this.spreadsheet, + container = D.node('
'), + graph = D.node('
'+this.options.spreadsheet.tabGraphLabel+'
'), + data = D.node('
'+this.options.spreadsheet.tabDataLabel+'
'), + offset; + + ss.tabsContainer = container; + ss.tabs = { graph : graph, data : data }; + + D.insert(container, graph); + D.insert(container, data); + D.insert(this.el, container); + + offset = D.size(data).height + 2; + this.plotOffset.bottom += offset; + + D.setStyles(container, {top: this.canvasHeight-offset+'px'}); + + this. + observe(graph, 'click', function(){ss.showTab('graph');}). + observe(data, 'click', function(){ss.showTab('data');}); + if (this.options.spreadsheet.initialTab !== 'graph'){ + ss.showTab(this.options.spreadsheet.initialTab); + } + } + }, + /** + * Builds a matrix of the data to make the correspondance between the x values and the y values : + * X value => Y values from the axes + * @return {Array} The data grid + */ + loadDataGrid: function(){ + if (this.seriesData) return this.seriesData; + + var s = this.series, + rows = {}; + + /* The data grid is a 2 dimensions array. There is a row for each X value. + * Each row contains the x value and the corresponding y value for each serie ('undefined' if there isn't one) + **/ + _.each(s, function(serie, i){ + _.each(serie.data, function (v) { + var x = v[0], + y = v[1], + r = rows[x]; + if (r) { + r[i+1] = y; + } else { + var newRow = []; + newRow[0] = x; + newRow[i+1] = y; + rows[x] = newRow; + } + }); + }); + + // The data grid is sorted by x value + this.seriesData = _.sortBy(rows, function(row, x){ + return parseInt(x, 10); + }); + return this.seriesData; + }, + /** + * Constructs the data table for the spreadsheet + * @todo make a spreadsheet manager (Flotr.Spreadsheet) + * @return {Element} The resulting table element + */ + constructDataGrid: function(){ + // If the data grid has already been built, nothing to do here + if (this.spreadsheet.datagrid) return this.spreadsheet.datagrid; + + var s = this.series, + datagrid = this.spreadsheet.loadDataGrid(), + colgroup = [''], + buttonDownload, buttonSelect, t; + + // First row : series' labels + var html = ['']; + html.push(''); + _.each(s, function(serie,i){ + html.push(''); + colgroup.push(''); + }); + html.push(''); + // Data rows + _.each(datagrid, function(row){ + html.push(''); + _.times(s.length+1, function(i){ + var tag = 'td', + value = row[i], + // TODO: do we really want to handle problems with floating point + // precision here? + content = (!_.isUndefined(value) ? Math.round(value*100000)/100000 : ''); + if (i === 0) { + tag = 'th'; + var label = getRowLabel.call(this, content); + if (label) content = label; + } + + html.push('<'+tag+(tag=='th'?' scope="row"':'')+'>'+content+''); + }, this); + html.push(''); + }, this); + colgroup.push(''); + t = D.node(html.join('')); + + /** + * @TODO disabled this + if (!Flotr.isIE || Flotr.isIE == 9) { + function handleMouseout(){ + t.select('colgroup col.hover, th.hover').invoke('removeClassName', 'hover'); + } + function handleMouseover(e){ + var td = e.element(), + siblings = td.previousSiblings(); + t.select('th[scope=col]')[siblings.length-1].addClassName('hover'); + t.select('colgroup col')[siblings.length].addClassName('hover'); + } + _.each(t.select('td'), function(td) { + Flotr.EventAdapter. + observe(td, 'mouseover', handleMouseover). + observe(td, 'mouseout', handleMouseout); + }); + } + */ + + buttonDownload = D.node( + ''); + + buttonSelect = D.node( + ''); + + this. + observe(buttonDownload, 'click', _.bind(this.spreadsheet.downloadCSV, this)). + observe(buttonSelect, 'click', _.bind(this.spreadsheet.selectAllData, this)); + + var toolbar = D.node('
'); + D.insert(toolbar, buttonDownload); + D.insert(toolbar, buttonSelect); + + var containerHeight =this.canvasHeight - D.size(this.spreadsheet.tabsContainer).height-2, + container = D.node('
'); + + D.insert(container, toolbar); + D.insert(container, t); + D.insert(this.el, container); + this.spreadsheet.datagrid = t; + this.spreadsheet.container = container; + + return t; + }, + /** + * Shows the specified tab, by its name + * @todo make a tab manager (Flotr.Tabs) + * @param {String} tabName - The tab name + */ + showTab: function(tabName){ + if (this.spreadsheet.activeTab === tabName){ + return; + } + switch(tabName) { + case 'graph': + D.hide(this.spreadsheet.container); + D.removeClass(this.spreadsheet.tabs.data, 'selected'); + D.addClass(this.spreadsheet.tabs.graph, 'selected'); + break; + case 'data': + if (!this.spreadsheet.datagrid) + this.spreadsheet.constructDataGrid(); + D.show(this.spreadsheet.container); + D.addClass(this.spreadsheet.tabs.data, 'selected'); + D.removeClass(this.spreadsheet.tabs.graph, 'selected'); + break; + default: + throw 'Illegal tab name: ' + tabName; + } + this.spreadsheet.activeTab = tabName; + }, + /** + * Selects the data table in the DOM for copy/paste + */ + selectAllData: function(){ + if (this.spreadsheet.tabs) { + var selection, range, doc, win, node = this.spreadsheet.constructDataGrid(); + + this.spreadsheet.showTab('data'); + + // deferred to be able to select the table + setTimeout(function () { + if ((doc = node.ownerDocument) && (win = doc.defaultView) && + win.getSelection && doc.createRange && + (selection = window.getSelection()) && + selection.removeAllRanges) { + range = doc.createRange(); + range.selectNode(node); + selection.removeAllRanges(); + selection.addRange(range); + } + else if (document.body && document.body.createTextRange && + (range = document.body.createTextRange())) { + range.moveToElementText(node); + range.select(); + } + }, 0); + return true; + } + else return false; + }, + /** + * Converts the data into CSV in order to download a file + */ + downloadCSV: function(){ + var csv = '', + series = this.series, + options = this.options, + dg = this.spreadsheet.loadDataGrid(), + separator = encodeURIComponent(options.spreadsheet.csvFileSeparator); + + if (options.spreadsheet.decimalSeparator === options.spreadsheet.csvFileSeparator) { + throw "The decimal separator is the same as the column separator ("+options.spreadsheet.decimalSeparator+")"; + } + + // The first row + _.each(series, function(serie, i){ + csv += separator+'"'+(serie.label || String.fromCharCode(65+i)).replace(/\"/g, '\\"')+'"'; + }); + + csv += "%0D%0A"; // \r\n + + // For each row + csv += _.reduce(dg, function(memo, row){ + var rowLabel = getRowLabel.call(this, row[0]) || ''; + rowLabel = '"'+(rowLabel+'').replace(/\"/g, '\\"')+'"'; + var numbers = row.slice(1).join(separator); + if (options.spreadsheet.decimalSeparator !== '.') { + numbers = numbers.replace(/\./g, options.spreadsheet.decimalSeparator); + } + return memo + rowLabel+separator+numbers+"%0D%0A"; // \t and \r\n + }, '', this); + + if (Flotr.isIE && Flotr.isIE < 9) { + csv = csv.replace(new RegExp(separator, 'g'), decodeURIComponent(separator)).replace(/%0A/g, '\n').replace(/%0D/g, '\r'); + window.open().document.write(csv); + } + else window.open('data:text/csv,'+csv); + } +}); +})(); + +(function () { + +var D = Flotr.DOM; + +Flotr.addPlugin('titles', { + callbacks: { + 'flotr:afterdraw': function() { + this.titles.drawTitles(); + } + }, + /** + * Draws the title and the subtitle + */ + drawTitles : function () { + var html, + options = this.options, + margin = options.grid.labelMargin, + ctx = this.ctx, + a = this.axes; + + if (!options.HtmlText && this.textEnabled) { + var style = { + size: options.fontSize, + color: options.grid.color, + textAlign: 'center' + }; + + // Add subtitle + if (options.subtitle){ + Flotr.drawText( + ctx, options.subtitle, + this.plotOffset.left + this.plotWidth/2, + this.titleHeight + this.subtitleHeight - 2, + style + ); + } + + style.weight = 1.5; + style.size *= 1.5; + + // Add title + if (options.title){ + Flotr.drawText( + ctx, options.title, + this.plotOffset.left + this.plotWidth/2, + this.titleHeight - 2, + style + ); + } + + style.weight = 1.8; + style.size *= 0.8; + + // Add x axis title + if (a.x.options.title && a.x.used){ + style.textAlign = a.x.options.titleAlign || 'center'; + style.textBaseline = 'top'; + style.angle = Flotr.toRad(a.x.options.titleAngle); + style = Flotr.getBestTextAlign(style.angle, style); + Flotr.drawText( + ctx, a.x.options.title, + this.plotOffset.left + this.plotWidth/2, + this.plotOffset.top + a.x.maxLabel.height + this.plotHeight + 2 * margin, + style + ); + } + + // Add x2 axis title + if (a.x2.options.title && a.x2.used){ + style.textAlign = a.x2.options.titleAlign || 'center'; + style.textBaseline = 'bottom'; + style.angle = Flotr.toRad(a.x2.options.titleAngle); + style = Flotr.getBestTextAlign(style.angle, style); + Flotr.drawText( + ctx, a.x2.options.title, + this.plotOffset.left + this.plotWidth/2, + this.plotOffset.top - a.x2.maxLabel.height - 2 * margin, + style + ); + } + + // Add y axis title + if (a.y.options.title && a.y.used){ + style.textAlign = a.y.options.titleAlign || 'right'; + style.textBaseline = 'middle'; + style.angle = Flotr.toRad(a.y.options.titleAngle); + style = Flotr.getBestTextAlign(style.angle, style); + Flotr.drawText( + ctx, a.y.options.title, + this.plotOffset.left - a.y.maxLabel.width - 2 * margin, + this.plotOffset.top + this.plotHeight / 2, + style + ); + } + + // Add y2 axis title + if (a.y2.options.title && a.y2.used){ + style.textAlign = a.y2.options.titleAlign || 'left'; + style.textBaseline = 'middle'; + style.angle = Flotr.toRad(a.y2.options.titleAngle); + style = Flotr.getBestTextAlign(style.angle, style); + Flotr.drawText( + ctx, a.y2.options.title, + this.plotOffset.left + this.plotWidth + a.y2.maxLabel.width + 2 * margin, + this.plotOffset.top + this.plotHeight / 2, + style + ); + } + } + else { + html = []; + + // Add title + if (options.title) + html.push( + '
', options.title, '
' + ); + + // Add subtitle + if (options.subtitle) + html.push( + '
', options.subtitle, '
' + ); + + html.push(''); + + html.push('
'); + + // Add x axis title + if (a.x.options.title && a.x.used) + html.push( + '
', a.x.options.title, '
' + ); + + // Add x2 axis title + if (a.x2.options.title && a.x2.used) + html.push( + '
', a.x2.options.title, '
' + ); + + // Add y axis title + if (a.y.options.title && a.y.used) + html.push( + '
', a.y.options.title, '
' + ); + + // Add y2 axis title + if (a.y2.options.title && a.y2.used) + html.push( + '
', a.y2.options.title, '
' + ); + + html = html.join(''); + + var div = D.create('div'); + D.setStyles({ + color: options.grid.color + }); + div.className = 'flotr-titles'; + D.insert(this.el, div); + D.insert(div, html); + } + } +}); +})(); diff --git a/gridplatform/bootstrap/static/bootstrap/genius.css b/gridplatform/bootstrap/static/bootstrap/genius.css new file mode 100644 index 0000000..dbffc59 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius.css @@ -0,0 +1,48 @@ +/* Hacks for Genius Admin Template */ + +.list-group-item.disabled { + color: grey; +} + +.table-condensed .alert { + margin-bottom: 0; +} + +.list-search input { + border: none; + height: 39px; + border-left: 1px solid #ced1d4; + padding: 0 5px; + width: 20em; +} +.list-datepicker input { + border: none; + height: 39px; + border-left: 1px solid #ced1d4; + padding: 0 5px; + width: 6em; +} + +.box .box-header .box-icon .list-search i, +.box .box-header .box-icon .list-datepicker i +{ + border: none; + background-color: #FFF; + margin-right: 2px; +} + +.box .box-header .box-icon .list-datepicker i +{ + border: none; + background-color: #FFF; + margin-right: 2px; +} + +/* Hack to get normal boostrap behaivier */ +.modal-lg { + width: 900px!important; +} + +a.navbar-brand span { + font-family: 'verdana'!important; +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius.js b/gridplatform/bootstrap/static/bootstrap/genius.js new file mode 100644 index 0000000..05000b5 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius.js @@ -0,0 +1,51 @@ +/*jslint browser: true */ +/*global $, jQuery, gettext, pgettext, get_format */ + +/* Genius Admin Template specific JavaScript */ + +// Save state of menu whenever menu is shown/hidden or minimized/restored +$(document).ready(function () { + $('#main-menu-toggle, #main-menu-min').click(function () { + if ($('#main-menu-toggle').hasClass('open')) { + jQuery.cookie('main-menu-toggle', 'open', {path: '/'}); + } else if ($('#main-menu-toggle').hasClass('close')) { + jQuery.cookie('main-menu-toggle', 'close', {path: '/'}); + } + + if ($('#main-menu-min').hasClass('full')) { + jQuery.cookie('main-menu-min', 'full', {path: '/'}); + } else if ($('#main-menu-min').hasClass('minified')) { + jQuery.cookie('main-menu-min', 'minified', {path: '/'}); + } + }); + + if (jQuery.cookie('main-menu-toggle') === 'close') { + // Menu is initially hidden + $('#main-menu-toggle').removeClass('open').addClass('close'); + $('#content').addClass('full'); + $('.navbar-brand').addClass('noBg'); + $('#sidebar-left').hide(); + } + + if (jQuery.cookie('main-menu-min') === 'minified') { + // Menu is initially minimized + $('#main-menu-min').removeClass('full').addClass('minified').find('i').removeClass('fa-angle-double-left').addClass('fa-angle-double-right'); + + $('body').addClass('sidebar-minified'); + $('#content').addClass('sidebar-minified'); + $('#sidebar-left').addClass('minified'); + + $('.dropmenu > .chevron').removeClass('opened').addClass('closed'); + $('.dropmenu').parent().find('ul').hide(); + + $('#sidebar-left > div > ul > li > a > .chevron').removeClass('closed').addClass('opened'); + $('#sidebar-left > div > ul > li > a').addClass('open'); + } + + /* Hack to make dropdowns work in box headers. */ + $('.box-header .dropdown').on('show.bs.dropdown', function () { + $('.box .box-header').css('overflow', 'visible'); + }).on('hide.bs.dropdown', function () { + $('.box .box-header').css('overflow', 'hidden'); + }); +}); diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap-editable.css b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap-editable.css new file mode 100755 index 0000000..efe1494 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap-editable.css @@ -0,0 +1,665 @@ +/*! X-editable - v1.5.0 +* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery +* http://github.com/vitalets/x-editable +* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ +.editableform { + margin-bottom: 0; /* overwrites bootstrap margin */ +} + +.editableform .control-group { + margin-bottom: 0; /* overwrites bootstrap margin */ + white-space: nowrap; /* prevent wrapping buttons on new line */ + line-height: 20px; /* overwriting bootstrap line-height. See #133 */ +} + +.editable-buttons { + display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ + vertical-align: top; + margin-left: 7px; + /* inline-block emulation for IE7*/ + zoom: 1; + *display: inline; +} + +.editable-buttons.editable-buttons-bottom { + display: block; + margin-top: 7px; + margin-left: 0; +} + +.editable-input { + vertical-align: top; + display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ + width: auto; /* bootstrap-responsive has width: 100% that breakes layout */ + white-space: normal; /* reset white-space decalred in parent*/ + /* display-inline emulation for IE7*/ + zoom: 1; + *display: inline; +} + +.editable-buttons .editable-cancel { + margin-left: 7px; +} + +/*for jquery-ui buttons need set height to look more pretty*/ +.editable-buttons button.ui-button-icon-only { + height: 24px; + width: 30px; +} + +.editableform-loading { + background: url('../img/loading.gif') center center no-repeat; + height: 25px; + width: auto; + min-width: 25px; +} + +.editable-inline .editableform-loading { + background-position: left 5px; +} + + .editable-error-block { + max-width: 300px; + margin: 5px 0 0 0; + width: auto; + white-space: normal; +} + +/*add padding for jquery ui*/ +.editable-error-block.ui-state-error { + padding: 3px; +} + +.editable-error { + color: red; +} + +/* ---- For specific types ---- */ + +.editableform .editable-date { + padding: 0; + margin: 0; + float: left; +} + +/* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */ +.editable-inline .add-on .icon-th { + margin-top: 3px; + margin-left: 1px; +} + + +/* checklist vertical alignment */ +.editable-checklist label input[type="checkbox"], +.editable-checklist label span { + vertical-align: middle; + margin: 0; +} + +.editable-checklist label { + white-space: nowrap; +} + +/* set exact width of textarea to fit buttons toolbar */ +.editable-wysihtml5 { + width: 566px; + height: 250px; +} + +/* clear button shown as link in date inputs */ +.editable-clear { + clear: both; + font-size: 0.9em; + text-decoration: none; + text-align: right; +} + +/* IOS-style clear button for text inputs */ +.editable-clear-x { + background: url('../img/clear.png') center center no-repeat; + display: block; + width: 13px; + height: 13px; + position: absolute; + opacity: 0.6; + z-index: 100; + + top: 50%; + right: 6px; + margin-top: -6px; + +} + +.editable-clear-x:hover { + opacity: 1; +} + +.editable-pre-wrapped { + white-space: pre-wrap; +} +.editable-container.editable-popup { + max-width: none !important; /* without this rule poshytip/tooltip does not stretch */ +} + +.editable-container.popover { + width: auto; /* without this rule popover does not stretch */ +} + +.editable-container.editable-inline { + display: inline-block; + vertical-align: middle; + width: auto; + /* inline-block emulation for IE7*/ + zoom: 1; + *display: inline; +} + +.editable-container.ui-widget { + font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */ + z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */ +} +.editable-click, +a.editable-click, +a.editable-click:hover { + text-decoration: none; + border-bottom: dashed 1px #0088cc; +} + +.editable-click.editable-disabled, +a.editable-click.editable-disabled, +a.editable-click.editable-disabled:hover { + color: #585858; + cursor: default; + border-bottom: none; +} + +.editable-empty, .editable-empty:hover, .editable-empty:focus{ + font-style: italic; + color: #DD1144; + /* border-bottom: none; */ + text-decoration: none; +} + +.editable-unsaved { + font-weight: bold; +} + +.editable-unsaved:after { +/* content: '*'*/ +} + +.editable-bg-transition { + -webkit-transition: background-color 1400ms ease-out; + -moz-transition: background-color 1400ms ease-out; + -o-transition: background-color 1400ms ease-out; + -ms-transition: background-color 1400ms ease-out; + transition: background-color 1400ms ease-out; +} + +/*see https://github.com/vitalets/x-editable/issues/139 */ +.form-horizontal .editable +{ + padding-top: 5px; + display:inline-block; +} + + +/*! + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.datepicker { + padding: 4px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + direction: ltr; + /*.dow { + border-top: 1px solid #ddd !important; + }*/ + +} +.datepicker-inline { + width: 220px; +} +.datepicker.datepicker-rtl { + direction: rtl; +} +.datepicker.datepicker-rtl table tr td span { + float: right; +} +.datepicker-dropdown { + top: 0; + left: 0; +} +.datepicker-dropdown:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 6px; +} +.datepicker-dropdown:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 7px; +} +.datepicker > div { + display: none; +} +.datepicker.days div.datepicker-days { + display: block; +} +.datepicker.months div.datepicker-months { + display: block; +} +.datepicker.years div.datepicker-years { + display: block; +} +.datepicker table { + margin: 0; +} +.datepicker td, +.datepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border: none; +} +.table-striped .datepicker table tr td, +.table-striped .datepicker table tr th { + background-color: transparent; +} +.datepicker table tr td.day:hover { + background: #eeeeee; + cursor: pointer; +} +.datepicker table tr td.old, +.datepicker table tr td.new { + color: #999999; +} +.datepicker table tr td.disabled, +.datepicker table tr td.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td.today, +.datepicker table tr td.today:hover, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today.disabled:hover { + background-color: #fde19a; + background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); + background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); + background-image: linear-gradient(top, #fdd49a, #fdf59a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); + border-color: #fdf59a #fdf59a #fbed50; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #000; +} +.datepicker table tr td.today:hover, +.datepicker table tr td.today:hover:hover, +.datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today.disabled:hover:hover, +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today:hover.disabled, +.datepicker table tr td.today.disabled.disabled, +.datepicker table tr td.today.disabled:hover.disabled, +.datepicker table tr td.today[disabled], +.datepicker table tr td.today:hover[disabled], +.datepicker table tr td.today.disabled[disabled], +.datepicker table tr td.today.disabled:hover[disabled] { + background-color: #fdf59a; +} +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active { + background-color: #fbf069 \9; +} +.datepicker table tr td.today:hover:hover { + color: #000; +} +.datepicker table tr td.today.active:hover { + color: #fff; +} +.datepicker table tr td.range, +.datepicker table tr td.range:hover, +.datepicker table tr td.range.disabled, +.datepicker table tr td.range.disabled:hover { + background: #eeeeee; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.datepicker table tr td.range.today, +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today.disabled:hover { + background-color: #f3d17a; + background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a); + background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a)); + background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a); + background-image: -o-linear-gradient(top, #f3c17a, #f3e97a); + background-image: linear-gradient(top, #f3c17a, #f3e97a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0); + border-color: #f3e97a #f3e97a #edde34; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today:hover:hover, +.datepicker table tr td.range.today.disabled:hover, +.datepicker table tr td.range.today.disabled:hover:hover, +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active, +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today:hover.disabled, +.datepicker table tr td.range.today.disabled.disabled, +.datepicker table tr td.range.today.disabled:hover.disabled, +.datepicker table tr td.range.today[disabled], +.datepicker table tr td.range.today:hover[disabled], +.datepicker table tr td.range.today.disabled[disabled], +.datepicker table tr td.range.today.disabled:hover[disabled] { + background-color: #f3e97a; +} +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active { + background-color: #efe24b \9; +} +.datepicker table tr td.selected, +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected.disabled:hover { + background-color: #9e9e9e; + background-image: -moz-linear-gradient(top, #b3b3b3, #808080); + background-image: -ms-linear-gradient(top, #b3b3b3, #808080); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080)); + background-image: -webkit-linear-gradient(top, #b3b3b3, #808080); + background-image: -o-linear-gradient(top, #b3b3b3, #808080); + background-image: linear-gradient(top, #b3b3b3, #808080); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0); + border-color: #808080 #808080 #595959; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected:hover:hover, +.datepicker table tr td.selected.disabled:hover, +.datepicker table tr td.selected.disabled:hover:hover, +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active, +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected:hover.disabled, +.datepicker table tr td.selected.disabled.disabled, +.datepicker table tr td.selected.disabled:hover.disabled, +.datepicker table tr td.selected[disabled], +.datepicker table tr td.selected:hover[disabled], +.datepicker table tr td.selected.disabled[disabled], +.datepicker table tr td.selected.disabled:hover[disabled] { + background-color: #808080; +} +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active { + background-color: #666666 \9; +} +.datepicker table tr td.active, +.datepicker table tr td.active:hover, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.active:hover, +.datepicker table tr td.active:hover:hover, +.datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active.disabled:hover:hover, +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active:hover.disabled, +.datepicker table tr td.active.disabled.disabled, +.datepicker table tr td.active.disabled:hover.disabled, +.datepicker table tr td.active[disabled], +.datepicker table tr td.active:hover[disabled], +.datepicker table tr td.active.disabled[disabled], +.datepicker table tr td.active.disabled:hover[disabled] { + background-color: #0044cc; +} +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active { + background-color: #003399 \9; +} +.datepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.datepicker table tr td span:hover { + background: #eeeeee; +} +.datepicker table tr td span.disabled, +.datepicker table tr td span.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td span.active, +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active:hover:hover, +.datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active.disabled:hover:hover, +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active:hover.disabled, +.datepicker table tr td span.active.disabled.disabled, +.datepicker table tr td span.active.disabled:hover.disabled, +.datepicker table tr td span.active[disabled], +.datepicker table tr td span.active:hover[disabled], +.datepicker table tr td span.active.disabled[disabled], +.datepicker table tr td span.active.disabled:hover[disabled] { + background-color: #0044cc; +} +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active { + background-color: #003399 \9; +} +.datepicker table tr td span.old, +.datepicker table tr td span.new { + color: #999999; +} +.datepicker th.datepicker-switch { + width: 145px; +} +.datepicker thead tr:first-child th, +.datepicker tfoot tr th { + cursor: pointer; +} +.datepicker thead tr:first-child th:hover, +.datepicker tfoot tr th:hover { + background: #eeeeee; +} +.datepicker .cw { + font-size: 10px; + width: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; +} +.datepicker thead tr:first-child th.cw { + cursor: default; + background-color: transparent; +} +.input-append.date .add-on i, +.input-prepend.date .add-on i { + display: block; + cursor: pointer; + width: 16px; + height: 16px; +} +.input-daterange input { + text-align: center; +} +.input-daterange input:first-child { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-daterange input:last-child { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-daterange .add-on { + display: inline-block; + width: auto; + min-width: 16px; + height: 18px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + vertical-align: middle; + background-color: #eeeeee; + border: 1px solid #ccc; + margin-left: -5px; + margin-right: -5px; +} + +.editable-address { + display: block; + margin-bottom: 5px; +} + +.editable-address span { + width: 70px; + display: inline-block; +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap-theme.css b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap-theme.css new file mode 100644 index 0000000..df2d3d9 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap-theme.css @@ -0,0 +1,397 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +.btn-default, +.btn-primary, +.btn-success, +.btn-info, +.btn-warning, +.btn-danger { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.btn-default:active, +.btn-primary:active, +.btn-success:active, +.btn-info:active, +.btn-warning:active, +.btn-danger:active, +.btn-default.active, +.btn-primary.active, +.btn-success.active, +.btn-info.active, +.btn-warning.active, +.btn-danger.active { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} + +.btn:active, +.btn.active { + background-image: none; +} + +.btn-default { + text-shadow: 0 1px 0 #fff; + background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); + background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%); + background-repeat: repeat-x; + border-color: #dbdbdb; + border-color: #ccc; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-default:hover, +.btn-default:focus { + background-color: #e0e0e0; + background-position: 0 -15px; +} + +.btn-default:active, +.btn-default.active { + background-color: #e0e0e0; + border-color: #dbdbdb; +} + +.btn-primary { + background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); + background-repeat: repeat-x; + border-color: #2b669a; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:focus { + background-color: #2d6ca2; + background-position: 0 -15px; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #2d6ca2; + border-color: #2b669a; +} + +.btn-success { + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); + background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); + background-repeat: repeat-x; + border-color: #3e8f3e; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:focus { + background-color: #419641; + background-position: 0 -15px; +} + +.btn-success:active, +.btn-success.active { + background-color: #419641; + border-color: #3e8f3e; +} + +.btn-warning { + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); + background-repeat: repeat-x; + border-color: #e38d13; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:focus { + background-color: #eb9316; + background-position: 0 -15px; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #eb9316; + border-color: #e38d13; +} + +.btn-danger { + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); + background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); + background-repeat: repeat-x; + border-color: #b92c28; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:focus { + background-color: #c12e2a; + background-position: 0 -15px; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #c12e2a; + border-color: #b92c28; +} + +.btn-info { + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); + background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); + background-repeat: repeat-x; + border-color: #28a4c9; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:focus { + background-color: #2aabd2; + background-position: 0 -15px; +} + +.btn-info:active, +.btn-info.active { + background-color: #2aabd2; + border-color: #28a4c9; +} + +.thumbnail, +.img-thumbnail { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + background-color: #e8e8e8; + background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + background-color: #357ebd; + background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); +} + +.navbar-default { + background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); + background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%); + background-repeat: repeat-x; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); +} + +.navbar-default .navbar-nav > .active > a { + background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); + background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); +} + +.navbar-brand, +.navbar-nav > li > a { + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); +} + +.navbar-inverse { + background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%); + background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.navbar-inverse .navbar-nav > .active > a { + background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%); + background-image: linear-gradient(to bottom, #222222 0%, #282828 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .navbar-brand, +.navbar-inverse .navbar-nav > li > a { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar-static-top, +.navbar-fixed-top, +.navbar-fixed-bottom { + border-radius: 0; +} + +.alert { + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.alert-success { + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); + background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); + background-repeat: repeat-x; + border-color: #b2dba1; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); +} + +.alert-info { + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); + background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); + background-repeat: repeat-x; + border-color: #9acfea; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); +} + +.alert-warning { + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); + background-repeat: repeat-x; + border-color: #f5e79e; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); +} + +.alert-danger { + background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); + background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); + background-repeat: repeat-x; + border-color: #dca7a7; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); +} + +.progress { + background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); + background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); +} + +.progress-bar { + background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); +} + +.progress-bar-success { + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); + background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); +} + +.progress-bar-info { + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); + background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); +} + +.progress-bar-warning { + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); +} + +.progress-bar-danger { + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); + background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); +} + +.list-group { + border-radius: 4px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); +} + +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + text-shadow: 0 -1px 0 #3071a9; + background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); + background-repeat: repeat-x; + border-color: #3278b3; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); +} + +.panel { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.panel-default > .panel-heading { + background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); +} + +.panel-primary > .panel-heading { + background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); +} + +.panel-success > .panel-heading { + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); + background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); +} + +.panel-info > .panel-heading { + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); + background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); +} + +.panel-warning > .panel-heading { + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); +} + +.panel-danger > .panel-heading { + background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); + background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); +} + +.well { + background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); + background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); + background-repeat: repeat-x; + border-color: #dcdcdc; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap-theme.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap-theme.min.css new file mode 100644 index 0000000..c7b6d39 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap-theme.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.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:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap.css b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap.css new file mode 100644 index 0000000..377dff3 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap.css @@ -0,0 +1,7118 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} + +audio, +canvas, +video { + display: inline-block; +} + +audio:not([controls]) { + display: none; + height: 0; +} + +[hidden], +template { + display: none; +} + +html { + font-family: sans-serif; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +body { + margin: 0; +} + +a { + background: transparent; +} + +a:focus { + outline: thin dotted; +} + +a:active, +a:hover { + outline: 0; +} + +h1 { + margin: 0.67em 0; + font-size: 2em; +} + +abbr[title] { + border-bottom: 1px dotted; +} + +b, +strong { + font-weight: bold; +} + +dfn { + font-style: italic; +} + +hr { + height: 0; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +mark { + color: #000; + background: #ff0; +} + +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} + +pre { + white-space: pre-wrap; +} + +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} + +small { + font-size: 80%; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + border: 0; +} + +svg:not(:root) { + overflow: hidden; +} + +figure { + margin: 0; +} + +fieldset { + padding: 0.35em 0.625em 0.75em; + margin: 0 2px; + border: 1px solid #c0c0c0; +} + +legend { + padding: 0; + border: 0; +} + +button, +input, +select, +textarea { + margin: 0; + font-family: inherit; + font-size: 100%; +} + +button, +input { + line-height: normal; +} + +button, +select { + text-transform: none; +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +button[disabled], +html input[disabled] { + cursor: default; +} + +input[type="checkbox"], +input[type="radio"] { + padding: 0; + box-sizing: border-box; +} + +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; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !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: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 2cm .5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + select { + background: #fff !important; + } + .navbar { + display: none; + } + .table td, + .table th { + background-color: #fff !important; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} + +*, +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +html { + font-size: 62.5%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.428571429; + color: #333333; + background-color: #ffffff; +} + +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +a { + color: #428bca; + text-decoration: none; +} + +a:hover, +a:focus { + color: #2a6496; + text-decoration: underline; +} + +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +img { + vertical-align: middle; +} + +.img-responsive { + display: block; + height: auto; + max-width: 100%; +} + +.img-rounded { + border-radius: 6px; +} + +.img-thumbnail { + display: inline-block; + height: auto; + max-width: 100%; + padding: 4px; + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +.img-circle { + border-radius: 50%; +} + +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eeeeee; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 500; + line-height: 1.1; + color: inherit; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #999999; +} + +h1, +h2, +h3 { + margin-top: 20px; + margin-bottom: 10px; +} + +h1 small, +h2 small, +h3 small, +h1 .small, +h2 .small, +h3 .small { + font-size: 65%; +} + +h4, +h5, +h6 { + margin-top: 10px; + margin-bottom: 10px; +} + +h4 small, +h5 small, +h6 small, +h4 .small, +h5 .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: 200; + line-height: 1.4; +} + +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} + +small, +.small { + font-size: 85%; +} + +cite { + font-style: normal; +} + +.text-muted { + color: #999999; +} + +.text-primary { + color: #428bca; +} + +.text-primary:hover { + color: #3071a9; +} + +.text-warning { + color: #8a6d3b; +} + +.text-warning:hover { + color: #66512c; +} + +.text-danger { + color: #a94442; +} + +.text-danger:hover { + color: #843534; +} + +.text-success { + color: #3c763d; +} + +.text-success:hover { + color: #2b542c; +} + +.text-info { + color: #31708f; +} + +.text-info:hover { + color: #245269; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eeeeee; +} + +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} + +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline > li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; +} + +.list-inline > li:first-child { + padding-left: 0; +} + +dl { + margin-top: 0; + margin-bottom: 20px; +} + +dt, +dd { + line-height: 1.428571429; +} + +dt { + font-weight: bold; +} + +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; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + display: table; + content: " "; + } + .dl-horizontal dd:after { + clear: both; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + display: table; + content: " "; + } + .dl-horizontal dd:after { + clear: both; + } +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + font-size: 17.5px; + font-weight: 300; + line-height: 1.25; +} + +blockquote p:last-child { + margin-bottom: 0; +} + +blockquote small, +blockquote .small { + display: block; + line-height: 1.428571429; + color: #999999; +} + +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small, +blockquote.pull-right .small { + text-align: right; +} + +blockquote.pull-right small:before, +blockquote.pull-right .small:before { + content: ''; +} + +blockquote.pull-right small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} + +blockquote:before, +blockquote:after { + content: ""; +} + +address { + margin-bottom: 20px; + font-style: normal; + line-height: 1.428571429; +} + +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} + +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + white-space: nowrap; + background-color: #f9f2f4; + border-radius: 4px; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.428571429; + color: #333333; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #cccccc; + 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; +} + +.container:before, +.container:after { + display: table; + content: " "; +} + +.container:after { + clear: both; +} + +.container:before, +.container:after { + display: table; + content: " "; +} + +.container:after { + clear: both; +} + +@media (min-width: 768px) { + .container { + width: 750px; + } +} + +@media (min-width: 992px) { + .container { + width: 970px; + } +} + +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} + +.row { + margin-right: -15px; + margin-left: -15px; +} + +.row:before, +.row:after { + display: table; + content: " "; +} + +.row:after { + clear: both; +} + +.row:before, +.row:after { + display: table; + content: " "; +} + +.row:after { + clear: both; +} + +.col-xs-1, +.col-sm-1, +.col-md-1, +.col-lg-1, +.col-xs-2, +.col-sm-2, +.col-md-2, +.col-lg-2, +.col-xs-3, +.col-sm-3, +.col-md-3, +.col-lg-3, +.col-xs-4, +.col-sm-4, +.col-md-4, +.col-lg-4, +.col-xs-5, +.col-sm-5, +.col-md-5, +.col-lg-5, +.col-xs-6, +.col-sm-6, +.col-md-6, +.col-lg-6, +.col-xs-7, +.col-sm-7, +.col-md-7, +.col-lg-7, +.col-xs-8, +.col-sm-8, +.col-md-8, +.col-lg-8, +.col-xs-9, +.col-sm-9, +.col-md-9, +.col-lg-9, +.col-xs-10, +.col-sm-10, +.col-md-10, +.col-lg-10, +.col-xs-11, +.col-sm-11, +.col-md-11, +.col-lg-11, +.col-xs-12, +.col-sm-12, +.col-md-12, +.col-lg-12 { + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; +} + +.col-xs-1, +.col-xs-2, +.col-xs-3, +.col-xs-4, +.col-xs-5, +.col-xs-6, +.col-xs-7, +.col-xs-8, +.col-xs-9, +.col-xs-10, +.col-xs-11, +.col-xs-12 { + float: left; +} + +.col-xs-12 { + width: 100%; +} + +.col-xs-11 { + width: 91.66666666666666%; +} + +.col-xs-10 { + width: 83.33333333333334%; +} + +.col-xs-9 { + width: 75%; +} + +.col-xs-8 { + width: 66.66666666666666%; +} + +.col-xs-7 { + width: 58.333333333333336%; +} + +.col-xs-6 { + width: 50%; +} + +.col-xs-5 { + width: 41.66666666666667%; +} + +.col-xs-4 { + width: 33.33333333333333%; +} + +.col-xs-3 { + width: 25%; +} + +.col-xs-2 { + width: 16.666666666666664%; +} + +.col-xs-1 { + width: 8.333333333333332%; +} + +.col-xs-pull-12 { + right: 100%; +} + +.col-xs-pull-11 { + right: 91.66666666666666%; +} + +.col-xs-pull-10 { + right: 83.33333333333334%; +} + +.col-xs-pull-9 { + right: 75%; +} + +.col-xs-pull-8 { + right: 66.66666666666666%; +} + +.col-xs-pull-7 { + right: 58.333333333333336%; +} + +.col-xs-pull-6 { + right: 50%; +} + +.col-xs-pull-5 { + right: 41.66666666666667%; +} + +.col-xs-pull-4 { + right: 33.33333333333333%; +} + +.col-xs-pull-3 { + right: 25%; +} + +.col-xs-pull-2 { + right: 16.666666666666664%; +} + +.col-xs-pull-1 { + right: 8.333333333333332%; +} + +.col-xs-pull-0 { + right: 0; +} + +.col-xs-push-12 { + left: 100%; +} + +.col-xs-push-11 { + left: 91.66666666666666%; +} + +.col-xs-push-10 { + left: 83.33333333333334%; +} + +.col-xs-push-9 { + left: 75%; +} + +.col-xs-push-8 { + left: 66.66666666666666%; +} + +.col-xs-push-7 { + left: 58.333333333333336%; +} + +.col-xs-push-6 { + left: 50%; +} + +.col-xs-push-5 { + left: 41.66666666666667%; +} + +.col-xs-push-4 { + left: 33.33333333333333%; +} + +.col-xs-push-3 { + left: 25%; +} + +.col-xs-push-2 { + left: 16.666666666666664%; +} + +.col-xs-push-1 { + left: 8.333333333333332%; +} + +.col-xs-push-0 { + left: 0; +} + +.col-xs-offset-12 { + margin-left: 100%; +} + +.col-xs-offset-11 { + margin-left: 91.66666666666666%; +} + +.col-xs-offset-10 { + margin-left: 83.33333333333334%; +} + +.col-xs-offset-9 { + margin-left: 75%; +} + +.col-xs-offset-8 { + margin-left: 66.66666666666666%; +} + +.col-xs-offset-7 { + margin-left: 58.333333333333336%; +} + +.col-xs-offset-6 { + margin-left: 50%; +} + +.col-xs-offset-5 { + margin-left: 41.66666666666667%; +} + +.col-xs-offset-4 { + margin-left: 33.33333333333333%; +} + +.col-xs-offset-3 { + margin-left: 25%; +} + +.col-xs-offset-2 { + margin-left: 16.666666666666664%; +} + +.col-xs-offset-1 { + margin-left: 8.333333333333332%; +} + +.col-xs-offset-0 { + margin-left: 0; +} + +@media (min-width: 768px) { + .col-sm-1, + .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-sm-10, + .col-sm-11, + .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666666666666%; + } + .col-sm-10 { + width: 83.33333333333334%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666666666666%; + } + .col-sm-7 { + width: 58.333333333333336%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666666666667%; + } + .col-sm-4 { + width: 33.33333333333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.666666666666664%; + } + .col-sm-1 { + width: 8.333333333333332%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666666666666%; + } + .col-sm-pull-10 { + right: 83.33333333333334%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666666666666%; + } + .col-sm-pull-7 { + right: 58.333333333333336%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666666666667%; + } + .col-sm-pull-4 { + right: 33.33333333333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.666666666666664%; + } + .col-sm-pull-1 { + right: 8.333333333333332%; + } + .col-sm-pull-0 { + right: 0; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666666666666%; + } + .col-sm-push-10 { + left: 83.33333333333334%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666666666666%; + } + .col-sm-push-7 { + left: 58.333333333333336%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666666666667%; + } + .col-sm-push-4 { + left: 33.33333333333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.666666666666664%; + } + .col-sm-push-1 { + left: 8.333333333333332%; + } + .col-sm-push-0 { + left: 0; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666666666666%; + } + .col-sm-offset-10 { + margin-left: 83.33333333333334%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666666666666%; + } + .col-sm-offset-7 { + margin-left: 58.333333333333336%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666666666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.666666666666664%; + } + .col-sm-offset-1 { + margin-left: 8.333333333333332%; + } + .col-sm-offset-0 { + margin-left: 0; + } +} + +@media (min-width: 992px) { + .col-md-1, + .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-md-10, + .col-md-11, + .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666666666666%; + } + .col-md-10 { + width: 83.33333333333334%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666666666666%; + } + .col-md-7 { + width: 58.333333333333336%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666666666667%; + } + .col-md-4 { + width: 33.33333333333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.666666666666664%; + } + .col-md-1 { + width: 8.333333333333332%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666666666666%; + } + .col-md-pull-10 { + right: 83.33333333333334%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666666666666%; + } + .col-md-pull-7 { + right: 58.333333333333336%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666666666667%; + } + .col-md-pull-4 { + right: 33.33333333333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.666666666666664%; + } + .col-md-pull-1 { + right: 8.333333333333332%; + } + .col-md-pull-0 { + right: 0; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666666666666%; + } + .col-md-push-10 { + left: 83.33333333333334%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666666666666%; + } + .col-md-push-7 { + left: 58.333333333333336%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666666666667%; + } + .col-md-push-4 { + left: 33.33333333333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.666666666666664%; + } + .col-md-push-1 { + left: 8.333333333333332%; + } + .col-md-push-0 { + left: 0; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666666666666%; + } + .col-md-offset-10 { + margin-left: 83.33333333333334%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666666666666%; + } + .col-md-offset-7 { + margin-left: 58.333333333333336%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666666666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.666666666666664%; + } + .col-md-offset-1 { + margin-left: 8.333333333333332%; + } + .col-md-offset-0 { + margin-left: 0; + } +} + +@media (min-width: 1200px) { + .col-lg-1, + .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-lg-10, + .col-lg-11, + .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666666666666%; + } + .col-lg-10 { + width: 83.33333333333334%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666666666666%; + } + .col-lg-7 { + width: 58.333333333333336%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666666666667%; + } + .col-lg-4 { + width: 33.33333333333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.666666666666664%; + } + .col-lg-1 { + width: 8.333333333333332%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666666666666%; + } + .col-lg-pull-10 { + right: 83.33333333333334%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666666666666%; + } + .col-lg-pull-7 { + right: 58.333333333333336%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666666666667%; + } + .col-lg-pull-4 { + right: 33.33333333333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.666666666666664%; + } + .col-lg-pull-1 { + right: 8.333333333333332%; + } + .col-lg-pull-0 { + right: 0; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666666666666%; + } + .col-lg-push-10 { + left: 83.33333333333334%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666666666666%; + } + .col-lg-push-7 { + left: 58.333333333333336%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666666666667%; + } + .col-lg-push-4 { + left: 33.33333333333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.666666666666664%; + } + .col-lg-push-1 { + left: 8.333333333333332%; + } + .col-lg-push-0 { + left: 0; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666666666666%; + } + .col-lg-offset-10 { + margin-left: 83.33333333333334%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666666666666%; + } + .col-lg-offset-7 { + margin-left: 58.333333333333336%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666666666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.666666666666664%; + } + .col-lg-offset-1 { + margin-left: 8.333333333333332%; + } + .col-lg-offset-0 { + margin-left: 0; + } +} + +table { + max-width: 100%; + background-color: transparent; +} + +th { + text-align: left; +} + +.table { + width: 100%; + margin-bottom: 20px; +} + +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.428571429; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #dddddd; +} + +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} + +.table > tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table .table { + background-color: #ffffff; +} + +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} + +.table-bordered { + border: 1px solid #dddddd; +} + +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #dddddd; +} + +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} + +.table-striped > tbody > tr:nth-child(odd) > td, +.table-striped > tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} + +.table-hover > tbody > tr:hover > td, +.table-hover > tbody > tr:hover > th { + background-color: #f5f5f5; +} + +table col[class*="col-"] { + position: static; + display: table-column; + float: none; +} + +table td[class*="col-"], +table th[class*="col-"] { + display: table-cell; + float: none; +} + +.table > thead > tr > .active, +.table > tbody > tr > .active, +.table > tfoot > tr > .active, +.table > thead > .active > td, +.table > tbody > .active > td, +.table > tfoot > .active > td, +.table > thead > .active > th, +.table > tbody > .active > th, +.table > tfoot > .active > th { + background-color: #f5f5f5; +} + +.table-hover > tbody > tr > .active:hover, +.table-hover > tbody > .active:hover > td, +.table-hover > tbody > .active:hover > th { + background-color: #e8e8e8; +} + +.table > thead > tr > .success, +.table > tbody > tr > .success, +.table > tfoot > tr > .success, +.table > thead > .success > td, +.table > tbody > .success > td, +.table > tfoot > .success > td, +.table > thead > .success > th, +.table > tbody > .success > th, +.table > tfoot > .success > th { + background-color: #dff0d8; +} + +.table-hover > tbody > tr > .success:hover, +.table-hover > tbody > .success:hover > td, +.table-hover > tbody > .success:hover > th { + background-color: #d0e9c6; +} + +.table > thead > tr > .danger, +.table > tbody > tr > .danger, +.table > tfoot > tr > .danger, +.table > thead > .danger > td, +.table > tbody > .danger > td, +.table > tfoot > .danger > td, +.table > thead > .danger > th, +.table > tbody > .danger > th, +.table > tfoot > .danger > th { + background-color: #f2dede; +} + +.table-hover > tbody > tr > .danger:hover, +.table-hover > tbody > .danger:hover > td, +.table-hover > tbody > .danger:hover > th { + background-color: #ebcccc; +} + +.table > thead > tr > .warning, +.table > tbody > tr > .warning, +.table > tfoot > tr > .warning, +.table > thead > .warning > td, +.table > tbody > .warning > td, +.table > tfoot > .warning > td, +.table > thead > .warning > th, +.table > tbody > .warning > th, +.table > tfoot > .warning > th { + background-color: #fcf8e3; +} + +.table-hover > tbody > tr > .warning:hover, +.table-hover > tbody > .warning:hover > td, +.table-hover > tbody > .warning:hover > th { + background-color: #faf2cc; +} + +@media (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-x: scroll; + overflow-y: hidden; + border: 1px solid #dddddd; + -ms-overflow-style: -ms-autohiding-scrollbar; + -webkit-overflow-scrolling: touch; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; +} + +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + /* IE8-9 */ + + line-height: normal; +} + +input[type="file"] { + display: block; +} + +select[multiple], +select[size] { + height: auto; +} + +select optgroup { + font-family: inherit; + font-size: inherit; + font-style: inherit; +} + +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; +} + +input[type="number"]::-webkit-outer-spin-button, +input[type="number"]::-webkit-inner-spin-button { + height: auto; +} + +output { + display: block; + padding-top: 7px; + font-size: 14px; + line-height: 1.428571429; + color: #555555; + vertical-align: middle; +} + +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + color: #555555; + vertical-align: middle; + background-color: #ffffff; + background-image: none; + border: 1px solid #cccccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; + transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; +} + +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); +} + +.form-control:-moz-placeholder { + color: #999999; +} + +.form-control::-moz-placeholder { + color: #999999; + opacity: 1; +} + +.form-control:-ms-input-placeholder { + color: #999999; +} + +.form-control::-webkit-input-placeholder { + color: #999999; +} + +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + cursor: not-allowed; + background-color: #eeeeee; +} + +textarea.form-control { + height: auto; +} + +.form-group { + margin-bottom: 15px; +} + +.radio, +.checkbox { + display: block; + min-height: 20px; + padding-left: 20px; + margin-top: 10px; + margin-bottom: 10px; + vertical-align: middle; +} + +.radio label, +.checkbox label { + display: inline; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} + +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} + +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + vertical-align: middle; + cursor: pointer; +} + +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +.radio[disabled], +.radio-inline[disabled], +.checkbox[disabled], +.checkbox-inline[disabled], +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"], +fieldset[disabled] .radio, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} + +.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; +} + +textarea.input-sm { + height: auto; +} + +.input-lg { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} + +select.input-lg { + height: 46px; + line-height: 46px; +} + +textarea.input-lg { + height: auto; +} + +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline { + color: #8a6d3b; +} + +.has-warning .form-control { + border-color: #8a6d3b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; +} + +.has-warning .input-group-addon { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #8a6d3b; +} + +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline { + color: #a94442; +} + +.has-error .form-control { + border-color: #a94442; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; +} + +.has-error .input-group-addon { + color: #a94442; + background-color: #f2dede; + border-color: #a94442; +} + +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline { + color: #3c763d; +} + +.has-success .form-control { + border-color: #3c763d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; +} + +.has-success .input-group-addon { + color: #3c763d; + background-color: #dff0d8; + border-color: #3c763d; +} + +.form-control-static { + margin-bottom: 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; + } + .form-inline select.form-control { + width: auto; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } +} + +.form-horizontal .control-label, +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + padding-top: 7px; + margin-top: 0; + margin-bottom: 0; +} + +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 27px; +} + +.form-horizontal .form-group { + margin-right: -15px; + margin-left: -15px; +} + +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + display: table; + content: " "; +} + +.form-horizontal .form-group:after { + clear: both; +} + +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + display: table; + content: " "; +} + +.form-horizontal .form-group:after { + clear: both; +} + +.form-horizontal .form-control-static { + padding-top: 7px; +} + +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + } +} + +.btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.428571429; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.btn:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; +} + +.btn:active, +.btn.active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} + +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + pointer-events: none; + cursor: not-allowed; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} + +.btn-default { + color: #333333; + background-color: #ffffff; + border-color: #cccccc; +} + +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + color: #333333; + background-color: #ebebeb; + border-color: #adadad; +} + +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + background-image: none; +} + +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #ffffff; + border-color: #cccccc; +} + +.btn-default .badge { + color: #ffffff; + background-color: #fff; +} + +.btn-primary { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #3276b1; + border-color: #285e8e; +} + +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + background-image: none; +} + +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #428bca; + border-color: #357ebd; +} + +.btn-primary .badge { + color: #428bca; + background-color: #fff; +} + +.btn-warning { + color: #ffffff; + background-color: #f0ad4e; + border-color: #eea236; +} + +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #ed9c28; + border-color: #d58512; +} + +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + background-image: none; +} + +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #f0ad4e; + border-color: #eea236; +} + +.btn-warning .badge { + color: #f0ad4e; + background-color: #fff; +} + +.btn-danger { + color: #ffffff; + background-color: #d9534f; + border-color: #d43f3a; +} + +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #d2322d; + border-color: #ac2925; +} + +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + background-image: none; +} + +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #d9534f; + border-color: #d43f3a; +} + +.btn-danger .badge { + color: #d9534f; + background-color: #fff; +} + +.btn-success { + color: #ffffff; + background-color: #5cb85c; + border-color: #4cae4c; +} + +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #47a447; + border-color: #398439; +} + +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + background-image: none; +} + +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #5cb85c; + border-color: #4cae4c; +} + +.btn-success .badge { + color: #5cb85c; + background-color: #fff; +} + +.btn-info { + color: #ffffff; + background-color: #5bc0de; + border-color: #46b8da; +} + +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #39b3d7; + border-color: #269abc; +} + +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + background-image: none; +} + +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #5bc0de; + border-color: #46b8da; +} + +.btn-info .badge { + color: #5bc0de; + background-color: #fff; +} + +.btn-link { + font-weight: normal; + color: #428bca; + cursor: pointer; + border-radius: 0; +} + +.btn-link, +.btn-link:active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} + +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} + +.btn-link:hover, +.btn-link:focus { + color: #2a6496; + text-decoration: underline; + background-color: transparent; +} + +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #999999; + text-decoration: none; +} + +.btn-lg { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} + +.btn-sm { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-xs { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; +} + +.btn-block + .btn-block { + margin-top: 5px; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + display: none; +} + +.collapse.in { + display: block; +} + +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +@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.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'; + -webkit-font-smoothing: antialiased; + font-style: normal; + font-weight: normal; + line-height: 1; + -moz-osx-font-smoothing: grayscale; +} + +.glyphicon:empty { + width: 1em; +} + +.glyphicon-asterisk:before { + content: "\2a"; +} + +.glyphicon-plus:before { + content: "\2b"; +} + +.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"; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px solid; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} + +.dropdown { + 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; + list-style: none; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; +} + +.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: normal; + line-height: 1.428571429; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + color: #262626; + text-decoration: none; + background-color: #f5f5f5; +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + background-color: #428bca; + outline: 0; +} + +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} + +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + 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-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.428571429; + color: #999999; +} + +.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 { + border-top: 0; + border-bottom: 4px solid; + content: ""; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + right: 0; + left: auto; + } +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} + +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} + +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} + +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus { + outline: none; +} + +.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:before, +.btn-toolbar:after { + display: table; + content: " "; +} + +.btn-toolbar:after { + clear: both; +} + +.btn-toolbar:before, +.btn-toolbar:after { + display: table; + content: " "; +} + +.btn-toolbar:after { + clear: both; +} + +.btn-toolbar .btn-group { + float: left; +} + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group, +.btn-toolbar > .btn-group + .btn-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-bottom-left-radius: 0; + border-top-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 > .btn:last-child, +.btn-group > .btn-group:first-child > .dropdown-toggle { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group > .btn-group:last-child > .btn:first-child { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} + +.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, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 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:before, +.btn-group-vertical > .btn-group:after { + display: table; + content: " "; +} + +.btn-group-vertical > .btn-group:after { + clear: both; +} + +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after { + display: table; + content: " "; +} + +.btn-group-vertical > .btn-group:after { + clear: both; +} + +.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-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-top-right-radius: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 0; +} + +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} + +.btn-group-vertical > .btn-group:first-child > .btn:last-child, +.btn-group-vertical > .btn-group:first-child > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn-group:last-child > .btn:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.btn-group-justified { + display: table; + width: 100%; + border-collapse: separate; + table-layout: fixed; +} + +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + display: table-cell; + float: none; + width: 1%; +} + +.btn-group-justified > .btn-group .btn { + width: 100%; +} + +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + display: 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 { + width: 100%; + margin-bottom: 0; +} + +.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.33; + 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; +} + +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; +} + +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-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} + +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control: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: normal; + line-height: 1; + color: #555555; + text-align: center; + background-color: #eeeeee; + border: 1px solid #cccccc; + 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="radio"], +.input-group-addon input[type="checkbox"] { + 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 > .dropdown-toggle, +.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:last-child > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.input-group-addon:last-child { + border-left: 0; +} + +.input-group-btn { + position: relative; + white-space: nowrap; +} + +.input-group-btn:first-child > .btn { + margin-right: -1px; +} + +.input-group-btn:last-child > .btn { + margin-left: -1px; +} + +.input-group-btn > .btn { + position: relative; +} + +.input-group-btn > .btn + .btn { + margin-left: -4px; +} + +.input-group-btn > .btn:hover, +.input-group-btn > .btn:active { + z-index: 2; +} + +.nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav:before, +.nav:after { + display: table; + content: " "; +} + +.nav:after { + clear: both; +} + +.nav:before, +.nav:after { + display: table; + content: " "; +} + +.nav:after { + clear: both; +} + +.nav > li { + position: relative; + display: block; +} + +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} + +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > li.disabled > a { + color: #999999; +} + +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999999; + text-decoration: none; + cursor: not-allowed; + background-color: transparent; +} + +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eeeeee; + border-color: #428bca; +} + +.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 #dddddd; +} + +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} + +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.428571429; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #dddddd; + 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:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #dddddd; +} + +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} + +.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:hover, +.nav-pills > li.active > a:focus { + color: #ffffff; + background-color: #428bca; +} + +.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:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #dddddd; +} + +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} + +.tab-content > .tab-pane { + display: none; +} + +.tab-content > .active { + display: block; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.navbar { + position: relative; + min-height: 50px; + margin-bottom: 20px; + border: 1px solid transparent; +} + +.navbar:before, +.navbar:after { + display: table; + content: " "; +} + +.navbar:after { + clear: both; +} + +.navbar:before, +.navbar:after { + display: table; + content: " "; +} + +.navbar:after { + clear: both; +} + +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} + +.navbar-header:before, +.navbar-header:after { + display: table; + content: " "; +} + +.navbar-header:after { + clear: both; +} + +.navbar-header:before, +.navbar-header:after { + display: table; + content: " "; +} + +.navbar-header:after { + clear: both; +} + +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} + +.navbar-collapse { + max-height: 340px; + padding-right: 15px; + padding-left: 15px; + overflow-x: visible; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} + +.navbar-collapse:before, +.navbar-collapse:after { + display: table; + content: " "; +} + +.navbar-collapse:after { + clear: both; +} + +.navbar-collapse:before, +.navbar-collapse:after { + display: table; + content: " "; +} + +.navbar-collapse:after { + clear: both; +} + +.navbar-collapse.in { + overflow-y: auto; +} + +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + 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-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-right: 0; + padding-left: 0; + } +} + +.container > .navbar-header, +.container > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} + +@media (min-width: 768px) { + .container > .navbar-header, + .container > .navbar-collapse { + 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-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} + +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + 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; + padding: 15px 15px; + font-size: 18px; + line-height: 20px; +} + +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} + +@media (min-width: 768px) { + .navbar > .container .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 .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; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + 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-nav.navbar-right:last-child { + margin-right: -15px; + } +} + +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + } +} + +.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, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.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; + } + .navbar-form select.form-control { + width: auto; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } +} + +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } +} + +@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-form.navbar-right:last-child { + margin-right: -15px; + } +} + +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.navbar-nav.pull-right > li > .dropdown-menu, +.navbar-nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.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; + } + .navbar-text.navbar-right:last-child { + margin-right: 0; + } +} + +.navbar-default { + background-color: #f8f8f8; + border-color: #e7e7e7; +} + +.navbar-default .navbar-brand { + color: #777777; +} + +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} + +.navbar-default .navbar-text { + color: #777777; +} + +.navbar-default .navbar-nav > li > a { + color: #777777; +} + +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333333; + background-color: transparent; +} + +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555555; + background-color: #e7e7e7; +} + +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #cccccc; + background-color: transparent; +} + +.navbar-default .navbar-toggle { + border-color: #dddddd; +} + +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #dddddd; +} + +.navbar-default .navbar-toggle .icon-bar { + background-color: #cccccc; +} + +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #e7e7e7; +} + +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + color: #555555; + background-color: #e7e7e7; +} + +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #cccccc; + background-color: transparent; + } +} + +.navbar-default .navbar-link { + color: #777777; +} + +.navbar-default .navbar-link:hover { + color: #333333; +} + +.navbar-inverse { + background-color: #222222; + border-color: #080808; +} + +.navbar-inverse .navbar-brand { + color: #999999; +} + +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .navbar-nav > li > a { + color: #999999; +} + +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #080808; +} + +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444444; + background-color: transparent; +} + +.navbar-inverse .navbar-toggle { + border-color: #333333; +} + +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333333; +} + +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #ffffff; +} + +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #101010; +} + +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + color: #ffffff; + 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: #999999; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ffffff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444444; + background-color: transparent; + } +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} + +.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: #cccccc; + content: "/\00a0"; +} + +.breadcrumb > .active { + color: #999999; +} + +.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.428571429; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; +} + +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-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:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + background-color: #eeeeee; +} + +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #ffffff; + cursor: default; + background-color: #428bca; + border-color: #428bca; +} + +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999999; + cursor: not-allowed; + background-color: #ffffff; + border-color: #dddddd; +} + +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; +} + +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 6px; + border-top-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; +} + +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 3px; + border-top-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:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + cursor: not-allowed; + background-color: #ffffff; +} + +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} + +.label[href]:hover, +.label[href]:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label:empty { + display: none; +} + +.btn .label { + position: relative; + top: -1px; +} + +.label-default { + background-color: #999999; +} + +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #808080; +} + +.label-primary { + background-color: #428bca; +} + +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #3071a9; +} + +.label-success { + background-color: #5cb85c; +} + +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} + +.label-info { + background-color: #5bc0de; +} + +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} + +.label-warning { + background-color: #f0ad4e; +} + +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} + +.label-danger { + background-color: #d9534f; +} + +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} + +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; + border-radius: 10px; +} + +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #428bca; + background-color: #ffffff; +} + +.nav-pills > li > a > .badge { + margin-left: 3px; +} + +.jumbotron { + padding: 30px; + margin-bottom: 30px; + font-size: 21px; + font-weight: 200; + line-height: 2.1428571435; + color: inherit; + background-color: #eeeeee; +} + +.jumbotron h1, +.jumbotron .h1 { + line-height: 1; + color: inherit; +} + +.jumbotron p { + line-height: 1.4; +} + +.container .jumbotron { + border-radius: 6px; +} + +.jumbotron .container { + max-width: 100%; +} + +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .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.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +.thumbnail > img, +.thumbnail a > img { + display: block; + height: auto; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #428bca; +} + +.thumbnail .caption { + padding: 9px; + color: #333333; +} + +.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: bold; +} + +.alert > p, +.alert > ul { + margin-bottom: 0; +} + +.alert > p + p { + margin-top: 5px; +} + +.alert-dismissable { + padding-right: 35px; +} + +.alert-dismissable .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; + } +} + +@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, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress-bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #ffffff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress-striped .progress-bar { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} + +.progress.active .progress-bar { + -webkit-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, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.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, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.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, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.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, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.media, +.media-body { + overflow: hidden; + zoom: 1; +} + +.media, +.media .media { + margin-top: 15px; +} + +.media:first-child { + margin-top: 0; +} + +.media-object { + display: block; +} + +.media-heading { + margin: 0 0 5px; +} + +.media > .pull-left { + margin-right: 10px; +} + +.media > .pull-right { + margin-left: 10px; +} + +.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: #ffffff; + border: 1px solid #dddddd; +} + +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-radius: 4px; +} + +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} + +.list-group-item > .badge { + float: right; +} + +.list-group-item > .badge + .badge { + margin-right: 5px; +} + +a.list-group-item { + color: #555555; +} + +a.list-group-item .list-group-item-heading { + color: #333333; +} + +a.list-group-item:hover, +a.list-group-item:focus { + text-decoration: none; + background-color: #f5f5f5; +} + +a.list-group-item.active, +a.list-group-item.active:hover, +a.list-group-item.active:focus { + z-index: 2; + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} + +a.list-group-item.active .list-group-item-heading, +a.list-group-item.active:hover .list-group-item-heading, +a.list-group-item.active:focus .list-group-item-heading { + color: inherit; +} + +a.list-group-item.active .list-group-item-text, +a.list-group-item.active:hover .list-group-item-text, +a.list-group-item.active:focus .list-group-item-text { + color: #e1edf7; +} + +.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: #ffffff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.panel-body { + padding: 15px; +} + +.panel-body:before, +.panel-body:after { + display: table; + content: " "; +} + +.panel-body:after { + clear: both; +} + +.panel-body:before, +.panel-body:after { + display: table; + content: " "; +} + +.panel-body:after { + clear: both; +} + +.panel > .list-group { + margin-bottom: 0; +} + +.panel > .list-group .list-group-item { + border-width: 1px 0; +} + +.panel > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.panel > .list-group .list-group-item:last-child { + border-bottom: 0; +} + +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} + +.panel > .table, +.panel > .table-responsive > .table { + margin-bottom: 0; +} + +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive { + border-top: 1px solid #dddddd; +} + +.panel > .table > tbody:first-child th, +.panel > .table > tbody:first-child td { + border-top: 0; +} + +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} + +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} + +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} + +.panel > .table-bordered > thead > tr:last-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > th, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-bordered > thead > tr:last-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; +} + +.panel > .table-responsive { + margin-bottom: 0; + border: 0; +} + +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} + +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} + +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} + +.panel-title > a { + color: inherit; +} + +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #dddddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} + +.panel-group .panel { + margin-bottom: 0; + overflow: hidden; + border-radius: 4px; +} + +.panel-group .panel + .panel { + margin-top: 5px; +} + +.panel-group .panel-heading { + border-bottom: 0; +} + +.panel-group .panel-heading + .panel-collapse .panel-body { + border-top: 1px solid #dddddd; +} + +.panel-group .panel-footer { + border-top: 0; +} + +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dddddd; +} + +.panel-default { + border-color: #dddddd; +} + +.panel-default > .panel-heading { + color: #333333; + background-color: #f5f5f5; + border-color: #dddddd; +} + +.panel-default > .panel-heading + .panel-collapse .panel-body { + border-top-color: #dddddd; +} + +.panel-default > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #dddddd; +} + +.panel-primary { + border-color: #428bca; +} + +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} + +.panel-primary > .panel-heading + .panel-collapse .panel-body { + border-top-color: #428bca; +} + +.panel-primary > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #428bca; +} + +.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-footer + .panel-collapse .panel-body { + border-bottom-color: #d6e9c6; +} + +.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-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-footer + .panel-collapse .panel-body { + border-bottom-color: #ebccd1; +} + +.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-footer + .panel-collapse .panel-body { + border-bottom-color: #bce8f1; +} + +.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, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 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: bold; + line-height: 1; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.modal-open { + overflow: hidden; +} + +.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + display: none; + overflow: auto; + overflow-y: scroll; +} + +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} + +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} + +.modal-dialog { + position: relative; + z-index: 1050; + width: auto; + margin: 10px; +} + +.modal-content { + position: relative; + background-color: #ffffff; + border: 1px solid #999999; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} + +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} + +.modal-header { + min-height: 16.428571429px; + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} + +.modal-header .close { + margin-top: -2px; +} + +.modal-title { + margin: 0; + line-height: 1.428571429; +} + +.modal-body { + position: relative; + padding: 20px; +} + +.modal-footer { + padding: 19px 20px 20px; + margin-top: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} + +.modal-footer:after { + clear: both; +} + +.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; +} + +@media screen and (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 12px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.9; + filter: alpha(opacity=90); +} + +.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: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + 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-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.top-left .tooltip-arrow { + bottom: 0; + left: 5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.top-right .tooltip-arrow { + right: 5px; + bottom: 0; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.tooltip.bottom-left .tooltip-arrow { + top: 0; + left: 5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.tooltip.bottom-right .tooltip-arrow { + top: 0; + right: 5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + background-clip: padding-box; +} + +.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; + font-weight: normal; + line-height: 18px; + 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 { + border-width: 10px; + content: ""; +} + +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; +} + +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-top-color: #ffffff; + border-bottom-width: 0; + content: " "; +} + +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999999; + border-right-color: rgba(0, 0, 0, 0.25); + border-left-width: 0; +} + +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + border-right-color: #ffffff; + border-left-width: 0; + content: " "; +} + +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-bottom-color: #999999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; +} + +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-bottom-color: #ffffff; + border-top-width: 0; + content: " "; +} + +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-left-color: #999999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; +} + +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + border-left-color: #ffffff; + border-right-width: 0; + content: " "; +} + +.carousel { + position: relative; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + height: auto; + max-width: 100%; + line-height: 1; +} + +.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: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.left { + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0), color-stop(rgba(0, 0, 0, 0.0001) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.0001) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); +} + +.carousel-control.right { + right: 0; + left: auto; + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0), color-stop(rgba(0, 0, 0, 0.5) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.5) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); +} + +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + outline: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; +} + +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; +} + +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; +} + +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + font-family: serif; +} + +.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 #ffffff; + border-radius: 10px; +} + +.carousel-indicators .active { + width: 12px; + height: 12px; + margin: 0; + background-color: #ffffff; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} + +.carousel-caption .btn { + text-shadow: none; +} + +@media screen and (min-width: 768px) { + .carousel-control .glyphicons-chevron-left, + .carousel-control .glyphicons-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + margin-left: -15px; + font-size: 30px; + } + .carousel-caption { + right: 20%; + left: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} + +.clearfix:before, +.clearfix:after { + display: table; + content: " "; +} + +.clearfix: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; + visibility: hidden !important; +} + +.affix { + position: fixed; +} + +@-ms-viewport { + width: device-width; +} + +.visible-xs, +tr.visible-xs, +th.visible-xs, +td.visible-xs { + display: none !important; +} + +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-xs.visible-sm { + display: block !important; + } + table.visible-xs.visible-sm { + display: table; + } + tr.visible-xs.visible-sm { + display: table-row !important; + } + th.visible-xs.visible-sm, + td.visible-xs.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-xs.visible-md { + display: block !important; + } + table.visible-xs.visible-md { + display: table; + } + tr.visible-xs.visible-md { + display: table-row !important; + } + th.visible-xs.visible-md, + td.visible-xs.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-xs.visible-lg { + display: block !important; + } + table.visible-xs.visible-lg { + display: table; + } + tr.visible-xs.visible-lg { + display: table-row !important; + } + th.visible-xs.visible-lg, + td.visible-xs.visible-lg { + display: table-cell !important; + } +} + +.visible-sm, +tr.visible-sm, +th.visible-sm, +td.visible-sm { + display: none !important; +} + +@media (max-width: 767px) { + .visible-sm.visible-xs { + display: block !important; + } + table.visible-sm.visible-xs { + display: table; + } + tr.visible-sm.visible-xs { + display: table-row !important; + } + th.visible-sm.visible-xs, + td.visible-sm.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-sm.visible-md { + display: block !important; + } + table.visible-sm.visible-md { + display: table; + } + tr.visible-sm.visible-md { + display: table-row !important; + } + th.visible-sm.visible-md, + td.visible-sm.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-sm.visible-lg { + display: block !important; + } + table.visible-sm.visible-lg { + display: table; + } + tr.visible-sm.visible-lg { + display: table-row !important; + } + th.visible-sm.visible-lg, + td.visible-sm.visible-lg { + display: table-cell !important; + } +} + +.visible-md, +tr.visible-md, +th.visible-md, +td.visible-md { + display: none !important; +} + +@media (max-width: 767px) { + .visible-md.visible-xs { + display: block !important; + } + table.visible-md.visible-xs { + display: table; + } + tr.visible-md.visible-xs { + display: table-row !important; + } + th.visible-md.visible-xs, + td.visible-md.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-md.visible-sm { + display: block !important; + } + table.visible-md.visible-sm { + display: table; + } + tr.visible-md.visible-sm { + display: table-row !important; + } + th.visible-md.visible-sm, + td.visible-md.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-md.visible-lg { + display: block !important; + } + table.visible-md.visible-lg { + display: table; + } + tr.visible-md.visible-lg { + display: table-row !important; + } + th.visible-md.visible-lg, + td.visible-md.visible-lg { + display: table-cell !important; + } +} + +.visible-lg, +tr.visible-lg, +th.visible-lg, +td.visible-lg { + display: none !important; +} + +@media (max-width: 767px) { + .visible-lg.visible-xs { + display: block !important; + } + table.visible-lg.visible-xs { + display: table; + } + tr.visible-lg.visible-xs { + display: table-row !important; + } + th.visible-lg.visible-xs, + td.visible-lg.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-lg.visible-sm { + display: block !important; + } + table.visible-lg.visible-sm { + display: table; + } + tr.visible-lg.visible-sm { + display: table-row !important; + } + th.visible-lg.visible-sm, + td.visible-lg.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-lg.visible-md { + display: block !important; + } + table.visible-lg.visible-md { + display: table; + } + tr.visible-lg.visible-md { + display: table-row !important; + } + th.visible-lg.visible-md, + td.visible-lg.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} + +.hidden-xs { + display: block !important; +} + +table.hidden-xs { + display: table; +} + +tr.hidden-xs { + display: table-row !important; +} + +th.hidden-xs, +td.hidden-xs { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-xs, + tr.hidden-xs, + th.hidden-xs, + td.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-xs.hidden-sm, + tr.hidden-xs.hidden-sm, + th.hidden-xs.hidden-sm, + td.hidden-xs.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-xs.hidden-md, + tr.hidden-xs.hidden-md, + th.hidden-xs.hidden-md, + td.hidden-xs.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-xs.hidden-lg, + tr.hidden-xs.hidden-lg, + th.hidden-xs.hidden-lg, + td.hidden-xs.hidden-lg { + display: none !important; + } +} + +.hidden-sm { + display: block !important; +} + +table.hidden-sm { + display: table; +} + +tr.hidden-sm { + display: table-row !important; +} + +th.hidden-sm, +td.hidden-sm { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-sm.hidden-xs, + tr.hidden-sm.hidden-xs, + th.hidden-sm.hidden-xs, + td.hidden-sm.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm, + tr.hidden-sm, + th.hidden-sm, + td.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-sm.hidden-md, + tr.hidden-sm.hidden-md, + th.hidden-sm.hidden-md, + td.hidden-sm.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-sm.hidden-lg, + tr.hidden-sm.hidden-lg, + th.hidden-sm.hidden-lg, + td.hidden-sm.hidden-lg { + display: none !important; + } +} + +.hidden-md { + display: block !important; +} + +table.hidden-md { + display: table; +} + +tr.hidden-md { + display: table-row !important; +} + +th.hidden-md, +td.hidden-md { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-md.hidden-xs, + tr.hidden-md.hidden-xs, + th.hidden-md.hidden-xs, + td.hidden-md.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-md.hidden-sm, + tr.hidden-md.hidden-sm, + th.hidden-md.hidden-sm, + td.hidden-md.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md, + tr.hidden-md, + th.hidden-md, + td.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-md.hidden-lg, + tr.hidden-md.hidden-lg, + th.hidden-md.hidden-lg, + td.hidden-md.hidden-lg { + display: none !important; + } +} + +.hidden-lg { + display: block !important; +} + +table.hidden-lg { + display: table; +} + +tr.hidden-lg { + display: table-row !important; +} + +th.hidden-lg, +td.hidden-lg { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-lg.hidden-xs, + tr.hidden-lg.hidden-xs, + th.hidden-lg.hidden-xs, + td.hidden-lg.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-lg.hidden-sm, + tr.hidden-lg.hidden-sm, + th.hidden-lg.hidden-sm, + td.hidden-lg.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-lg.hidden-md, + tr.hidden-lg.hidden-md, + th.hidden-lg.hidden-md, + td.hidden-lg.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-lg, + tr.hidden-lg, + th.hidden-lg, + td.hidden-lg { + display: none !important; + } +} + +.visible-print, +tr.visible-print, +th.visible-print, +td.visible-print { + display: none !important; +} + +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } + .hidden-print, + tr.hidden-print, + th.hidden-print, + td.hidden-print { + display: none !important; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap.min.css new file mode 100644 index 0000000..c547283 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}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}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!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:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-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}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .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:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#8a6d3b}.text-warning:hover{color:#66512c}.text-danger{color:#a94442}.text-danger:hover{color:#843534}.text-success{color:#3c763d}.text-success:hover{color:#2b542c}.text-info{color:#31708f}.text-info:hover{color:#245269}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}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}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small,blockquote .small{display:block;line-height:1.428571429;color:#999}blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;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}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}@media(min-width:768px){.container{width:750px}}@media(min-width:992px){.container{width:970px}}@media(min-width:1200px){.container{width:1170px}}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.col-sm-1,.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-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.col-md-1,.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-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.col-lg-1,.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-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;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>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{position:static;display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>.active,.table>tbody>tr>.active,.table>tfoot>tr>.active,.table>thead>.active>td,.table>tbody>.active>td,.table>tfoot>.active>td,.table>thead>.active>th,.table>tbody>.active>th,.table>tfoot>.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>.active:hover,.table-hover>tbody>.active:hover>td,.table-hover>tbody>.active:hover>th{background-color:#e8e8e8}.table>thead>tr>.success,.table>tbody>tr>.success,.table>tfoot>tr>.success,.table>thead>.success>td,.table>tbody>.success>td,.table>tfoot>.success>td,.table>thead>.success>th,.table>tbody>.success>th,.table>tfoot>.success>th{background-color:#dff0d8}.table-hover>tbody>tr>.success:hover,.table-hover>tbody>.success:hover>td,.table-hover>tbody>.success:hover>th{background-color:#d0e9c6}.table>thead>tr>.danger,.table>tbody>tr>.danger,.table>tfoot>tr>.danger,.table>thead>.danger>td,.table>tbody>.danger>td,.table>tfoot>.danger>td,.table>thead>.danger>th,.table>tbody>.danger>th,.table>tfoot>.danger>th{background-color:#f2dede}.table-hover>tbody>tr>.danger:hover,.table-hover>tbody>.danger:hover>td,.table-hover>tbody>.danger:hover>th{background-color:#ebcccc}.table>thead>tr>.warning,.table>tbody>tr>.warning,.table>tfoot>tr>.warning,.table>thead>.warning>td,.table>tbody>.warning>td,.table>tfoot>.warning>td,.table>thead>.warning>th,.table>tbody>.warning>th,.table>tfoot>.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>.warning:hover,.table-hover>tbody>.warning:hover>td,.table-hover>tbody>.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{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;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}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}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-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,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.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}textarea.input-sm{height:auto}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.form-control-static{margin-bottom: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}.form-inline select.form-control{width:auto}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{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,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#fff}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{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:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{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:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@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.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';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.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"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{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;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.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:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{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-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.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{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.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:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-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-bottom-left-radius:0;border-top-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>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.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,0.125);box-shadow:inset 0 3px 5px rgba(0,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:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.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-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display: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{width:100%;margin-bottom:0}.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.33;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}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}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-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control: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:normal;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="radio"],.input-group-addon input[type="checkbox"]{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>.dropdown-toggle,.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:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.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.428571429;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:hover,.nav-tabs>li.active>a:focus{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:hover,.nav-tabs.nav-justified>.active>a:focus{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:hover,.nav-tabs.nav-justified>.active>a:focus{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:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.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:hover,.nav-tabs-justified>.active>a:focus{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:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;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-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{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-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{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;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .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 .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;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{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-nav.navbar-right:last-child{margin-right:-15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.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,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.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}.navbar-form select.form-control{width:auto}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@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-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.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}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{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:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{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:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{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:hover,.navbar-inverse .navbar-nav>.open>a:focus{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:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.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:#999}.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.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-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:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-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}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-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:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.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:hover,.pager li>a:focus{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:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .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.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.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:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .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}}@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,0.1);box-shadow:inset 0 1px 2px rgba(0,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:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-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,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.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,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.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,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.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,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.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-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.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,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child th,.panel>.table>tbody:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>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-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.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-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.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-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.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-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-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.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-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.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,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,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:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.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}@media screen and (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.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;text-decoration:none;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-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.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;font-weight:normal;line-height:18px;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{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.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;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.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,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;outline:0;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.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,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix: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;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}table.visible-xs.visible-sm{display:table}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}table.visible-xs.visible-md{display:table}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}table.visible-xs.visible-lg{display:table}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}table.visible-sm.visible-xs{display:table}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}table.visible-sm.visible-md{display:table}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}table.visible-sm.visible-lg{display:table}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}table.visible-md.visible-xs{display:table}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}table.visible-md.visible-sm{display:table}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}table.visible-md.visible-lg{display:table}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}table.visible-lg.visible-xs{display:table}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}table.visible-lg.visible-sm{display:table}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}table.visible-lg.visible-md{display:table}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}table.hidden-xs{display:table}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}table.hidden-sm{display:table}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}table.hidden-md{display:table}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}table.hidden-lg{display:table}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/chosen-sprite.png b/gridplatform/bootstrap/static/bootstrap/genius/css/chosen-sprite.png new file mode 100755 index 0000000..3611ae4 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/chosen-sprite.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/chosen-sprite@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/chosen-sprite@2x.png new file mode 100755 index 0000000..ffe4d7d Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/chosen-sprite@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/chosen.css b/gridplatform/bootstrap/static/bootstrap/genius/css/chosen.css new file mode 100755 index 0000000..d203a07 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/chosen.css @@ -0,0 +1,430 @@ +/* @group Base */ +.chosen-container { + position: relative; + display: inline-block; + vertical-align: middle; + font-size: 13px; + zoom: 1; + *display: inline; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.chosen-container .chosen-drop { + position: absolute; + top: 100%; + left: -9999px; + z-index: 1010; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100%; + border: 1px solid #aaa; + border-top: 0; + background: #fff; + box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15); +} +.chosen-container.chosen-with-drop .chosen-drop { + left: 0; +} +.chosen-container a { + cursor: pointer; +} + +/* @end */ +/* @group Single Chosen */ +.chosen-container-single .chosen-single { + position: relative; + display: block; + overflow: hidden; + padding: 0 0 0 8px; + height: 23px; + border: 1px solid #aaa; + border-radius: 5px; + background-color: #fff; + background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4)); + background: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); + background: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); + background: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); + background: linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); + background-clip: padding-box; + box-shadow: 0 0 3px white inset, 0 1px 1px rgba(0, 0, 0, 0.1); + color: #444; + text-decoration: none; + white-space: nowrap; + line-height: 24px; +} +.chosen-container-single .chosen-default { + color: #999; +} +.chosen-container-single .chosen-single span { + display: block; + overflow: hidden; + margin-right: 26px; + text-overflow: ellipsis; + white-space: nowrap; +} +.chosen-container-single .chosen-single-with-deselect span { + margin-right: 38px; +} +.chosen-container-single .chosen-single abbr { + position: absolute; + top: 6px; + right: 26px; + display: block; + width: 12px; + height: 12px; + background: url('chosen-sprite.png') -42px 1px no-repeat; + font-size: 1px; +} +.chosen-container-single .chosen-single abbr:hover { + background-position: -42px -10px; +} +.chosen-container-single.chosen-disabled .chosen-single abbr:hover { + background-position: -42px -10px; +} +.chosen-container-single .chosen-single div { + position: absolute; + top: 0; + right: 0; + display: block; + width: 18px; + height: 100%; +} +.chosen-container-single .chosen-single div b { + display: block; + width: 100%; + height: 100%; + background: url('chosen-sprite.png') no-repeat 0px 2px; +} +.chosen-container-single .chosen-search { + position: relative; + z-index: 1010; + margin: 0; + padding: 3px 4px; + white-space: nowrap; +} +.chosen-container-single .chosen-search input[type="text"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 1px 0; + padding: 4px 20px 4px 5px; + width: 100%; + height: auto; + outline: 0; + border: 1px solid #aaa; + background: white url('chosen-sprite.png') no-repeat 100% -20px; + background: url('chosen-sprite.png') no-repeat 100% -20px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); + background: url('chosen-sprite.png') no-repeat 100% -20px, -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat 100% -20px, -moz-linear-gradient(#eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat 100% -20px, -o-linear-gradient(#eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat 100% -20px, linear-gradient(#eeeeee 1%, #ffffff 15%); + font-size: 1em; + font-family: sans-serif; + line-height: normal; + border-radius: 0; +} +.chosen-container-single .chosen-drop { + margin-top: -1px; + border-radius: 0 0 4px 4px; + background-clip: padding-box; +} +.chosen-container-single.chosen-container-single-nosearch .chosen-search { + position: absolute; + left: -9999px; +} + +/* @end */ +/* @group Results */ +.chosen-container .chosen-results { + position: relative; + overflow-x: hidden; + overflow-y: auto; + margin: 0 4px 4px 0; + padding: 0 0 0 4px; + max-height: 240px; + -webkit-overflow-scrolling: touch; +} +.chosen-container .chosen-results li { + display: none; + margin: 0; + padding: 5px 6px; + list-style: none; + line-height: 15px; +} +.chosen-container .chosen-results li.active-result { + display: list-item; + cursor: pointer; +} +.chosen-container .chosen-results li.disabled-result { + display: list-item; + color: #ccc; + cursor: default; +} +.chosen-container .chosen-results li.highlighted { + background-color: #3875d7; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc)); + background-image: -webkit-linear-gradient(#3875d7 20%, #2a62bc 90%); + background-image: -moz-linear-gradient(#3875d7 20%, #2a62bc 90%); + background-image: -o-linear-gradient(#3875d7 20%, #2a62bc 90%); + background-image: linear-gradient(#3875d7 20%, #2a62bc 90%); + color: #fff; +} +.chosen-container .chosen-results li.no-results { + display: list-item; + background: #f4f4f4; +} +.chosen-container .chosen-results li.group-result { + display: list-item; + font-weight: bold; + cursor: default; +} +.chosen-container .chosen-results li.group-option { + padding-left: 15px; +} +.chosen-container .chosen-results li em { + font-style: normal; + text-decoration: underline; +} + +/* @end */ +/* @group Multi Chosen */ +.chosen-container-multi .chosen-choices { + position: relative; + overflow: hidden; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 0; + padding: 0; + width: 100%; + height: auto !important; + height: 1%; + border: 1px solid #aaa; + background-color: #fff; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); + background-image: -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%); + background-image: -moz-linear-gradient(#eeeeee 1%, #ffffff 15%); + background-image: -o-linear-gradient(#eeeeee 1%, #ffffff 15%); + background-image: linear-gradient(#eeeeee 1%, #ffffff 15%); + cursor: text; +} +.chosen-container-multi .chosen-choices li { + float: left; + list-style: none; +} +.chosen-container-multi .chosen-choices li.search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} +.chosen-container-multi .chosen-choices li.search-field input[type="text"] { + margin: 1px 0; + padding: 5px; + height: 15px; + outline: 0; + border: 0 !important; + background: transparent !important; + box-shadow: none; + color: #666; + font-size: 100%; + font-family: sans-serif; + line-height: normal; + border-radius: 0; +} +.chosen-container-multi .chosen-choices li.search-field .default { + color: #999; +} +.chosen-container-multi .chosen-choices li.search-choice { + position: relative; + margin: 3px 0 3px 5px; + padding: 3px 20px 3px 5px; + border: 1px solid #aaa; + border-radius: 3px; + background-color: #e4e4e4; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); + background-image: -webkit-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -moz-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -o-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-clip: padding-box; + box-shadow: 0 0 2px white inset, 0 1px 0 rgba(0, 0, 0, 0.05); + color: #333; + line-height: 13px; + cursor: default; +} +.chosen-container-multi .chosen-choices li.search-choice .search-choice-close { + position: absolute; + top: 4px; + right: 3px; + display: block; + width: 12px; + height: 12px; + background: url('chosen-sprite.png') -42px 1px no-repeat; + font-size: 1px; +} +.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover { + background-position: -42px -10px; +} +.chosen-container-multi .chosen-choices li.search-choice-disabled { + padding-right: 5px; + border: 1px solid #ccc; + background-color: #e4e4e4; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + color: #666; +} +.chosen-container-multi .chosen-choices li.search-choice-focus { + background: #d4d4d4; +} +.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close { + background-position: -42px -10px; +} +.chosen-container-multi .chosen-results { + margin: 0; + padding: 0; +} +.chosen-container-multi .chosen-drop .result-selected { + display: list-item; + color: #ccc; + cursor: default; +} + +/* @end */ +/* @group Active */ +.chosen-container-active .chosen-single { + border: 1px solid #5897fb; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); +} +.chosen-container-active.chosen-with-drop .chosen-single { + border: 1px solid #aaa; + -moz-border-radius-bottomright: 0; + border-bottom-right-radius: 0; + -moz-border-radius-bottomleft: 0; + border-bottom-left-radius: 0; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff)); + background-image: -webkit-linear-gradient(#eeeeee 20%, #ffffff 80%); + background-image: -moz-linear-gradient(#eeeeee 20%, #ffffff 80%); + background-image: -o-linear-gradient(#eeeeee 20%, #ffffff 80%); + background-image: linear-gradient(#eeeeee 20%, #ffffff 80%); + box-shadow: 0 1px 0 #fff inset; +} +.chosen-container-active.chosen-with-drop .chosen-single div { + border-left: none; + background: transparent; +} +.chosen-container-active.chosen-with-drop .chosen-single div b { + background-position: -18px 2px; +} +.chosen-container-active .chosen-choices { + border: 1px solid #5897fb; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); +} +.chosen-container-active .chosen-choices li.search-field input[type="text"] { + color: #111 !important; +} + +/* @end */ +/* @group Disabled Support */ +.chosen-disabled { + opacity: 0.5 !important; + cursor: default; +} +.chosen-disabled .chosen-single { + cursor: default; +} +.chosen-disabled .chosen-choices .search-choice .search-choice-close { + cursor: default; +} + +/* @end */ +/* @group Right to Left */ +.chosen-rtl { + text-align: right; +} +.chosen-rtl .chosen-single { + overflow: visible; + padding: 0 8px 0 0; +} +.chosen-rtl .chosen-single span { + margin-right: 0; + margin-left: 26px; + direction: rtl; +} +.chosen-rtl .chosen-single-with-deselect span { + margin-left: 38px; +} +.chosen-rtl .chosen-single div { + right: auto; + left: 3px; +} +.chosen-rtl .chosen-single abbr { + right: auto; + left: 26px; +} +.chosen-rtl .chosen-choices li { + float: right; +} +.chosen-rtl .chosen-choices li.search-field input[type="text"] { + direction: rtl; +} +.chosen-rtl .chosen-choices li.search-choice { + margin: 3px 5px 3px 0; + padding: 3px 5px 3px 19px; +} +.chosen-rtl .chosen-choices li.search-choice .search-choice-close { + right: auto; + left: 4px; +} +.chosen-rtl.chosen-container-single-nosearch .chosen-search, +.chosen-rtl .chosen-drop { + left: 9999px; +} +.chosen-rtl.chosen-container-single .chosen-results { + margin: 0 0 4px 4px; + padding: 0 4px 0 0; +} +.chosen-rtl .chosen-results li.group-option { + padding-right: 15px; + padding-left: 0; +} +.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div { + border-right: none; +} +.chosen-rtl .chosen-search input[type="text"] { + padding: 4px 5px 4px 20px; + background: white url('chosen-sprite.png') no-repeat -30px -20px; + background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); + background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat -30px -20px, -moz-linear-gradient(#eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat -30px -20px, -o-linear-gradient(#eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat -30px -20px, linear-gradient(#eeeeee 1%, #ffffff 15%); + direction: rtl; +} +.chosen-rtl.chosen-container-single .chosen-single div b { + background-position: 6px 2px; +} +.chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b { + background-position: -12px 2px; +} + +/* @end */ +/* @group Retina compatibility */ +@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-resolution: 144dpi) { + .chosen-rtl .chosen-search input[type="text"], + .chosen-container-single .chosen-single abbr, + .chosen-container-single .chosen-single div b, + .chosen-container-single .chosen-search input[type="text"], + .chosen-container-multi .chosen-choices .search-choice .search-choice-close, + .chosen-container .chosen-results-scroll-down span, + .chosen-container .chosen-results-scroll-up span { + background-image: url('chosen-sprite@2x.png') !important; + background-size: 52px 37px !important; + background-repeat: no-repeat !important; + } +} +/* @end */ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/chosen.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/chosen.min.css new file mode 100755 index 0000000..3f3f5dd --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/chosen.min.css @@ -0,0 +1,3 @@ +/* Chosen v1.0.0 | (c) 2011-2013 by Harvest | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md */ + +.chosen-container{position:relative;display:inline-block;vertical-align:middle;font-size:13px;zoom:1;*display:inline;-webkit-user-select:none;-moz-user-select:none;user-select:none}.chosen-container .chosen-drop{position:absolute;top:100%;left:-9999px;z-index:1010;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:100%;border:1px solid #aaa;border-top:0;background:#fff;box-shadow:0 4px 5px rgba(0,0,0,.15)}.chosen-container.chosen-with-drop .chosen-drop{left:0}.chosen-container a{cursor:pointer}.chosen-container-single .chosen-single{position:relative;display:block;overflow:hidden;padding:0 0 0 8px;height:23px;border:1px solid #aaa;border-radius:5px;background-color:#fff;background:-webkit-gradient(linear,50% 0,50% 100%,color-stop(20%,#fff),color-stop(50%,#f6f6f6),color-stop(52%,#eee),color-stop(100%,#f4f4f4));background:-webkit-linear-gradient(top,#fff 20%,#f6f6f6 50%,#eee 52%,#f4f4f4 100%);background:-moz-linear-gradient(top,#fff 20%,#f6f6f6 50%,#eee 52%,#f4f4f4 100%);background:-o-linear-gradient(top,#fff 20%,#f6f6f6 50%,#eee 52%,#f4f4f4 100%);background:linear-gradient(top,#fff 20%,#f6f6f6 50%,#eee 52%,#f4f4f4 100%);background-clip:padding-box;box-shadow:0 0 3px #fff inset,0 1px 1px rgba(0,0,0,.1);color:#444;text-decoration:none;white-space:nowrap;line-height:24px}.chosen-container-single .chosen-default{color:#999}.chosen-container-single .chosen-single span{display:block;overflow:hidden;margin-right:26px;text-overflow:ellipsis;white-space:nowrap}.chosen-container-single .chosen-single-with-deselect span{margin-right:38px}.chosen-container-single .chosen-single abbr{position:absolute;top:6px;right:26px;display:block;width:12px;height:12px;background:url(chosen-sprite.png) -42px 1px no-repeat;font-size:1px}.chosen-container-single .chosen-single abbr:hover{background-position:-42px -10px}.chosen-container-single.chosen-disabled .chosen-single abbr:hover{background-position:-42px -10px}.chosen-container-single .chosen-single div{position:absolute;top:0;right:0;display:block;width:18px;height:100%}.chosen-container-single .chosen-single div b{display:block;width:100%;height:100%;background:url(chosen-sprite.png) no-repeat 0 2px}.chosen-container-single .chosen-search{position:relative;z-index:1010;margin:0;padding:3px 4px;white-space:nowrap}.chosen-container-single .chosen-search input[type=text]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:1px 0;padding:4px 20px 4px 5px;width:100%;height:auto;outline:0;border:1px solid #aaa;background:#fff url(chosen-sprite.png) no-repeat 100% -20px;background:url(chosen-sprite.png) no-repeat 100% -20px,-webkit-gradient(linear,50% 0,50% 100%,color-stop(1%,#eee),color-stop(15%,#fff));background:url(chosen-sprite.png) no-repeat 100% -20px,-webkit-linear-gradient(#eee 1%,#fff 15%);background:url(chosen-sprite.png) no-repeat 100% -20px,-moz-linear-gradient(#eee 1%,#fff 15%);background:url(chosen-sprite.png) no-repeat 100% -20px,-o-linear-gradient(#eee 1%,#fff 15%);background:url(chosen-sprite.png) no-repeat 100% -20px,linear-gradient(#eee 1%,#fff 15%);font-size:1em;font-family:sans-serif;line-height:normal;border-radius:0}.chosen-container-single .chosen-drop{margin-top:-1px;border-radius:0 0 4px 4px;background-clip:padding-box}.chosen-container-single.chosen-container-single-nosearch .chosen-search{position:absolute;left:-9999px}.chosen-container .chosen-results{position:relative;overflow-x:hidden;overflow-y:auto;margin:0 4px 4px 0;padding:0 0 0 4px;max-height:240px;-webkit-overflow-scrolling:touch}.chosen-container .chosen-results li{display:none;margin:0;padding:5px 6px;list-style:none;line-height:15px}.chosen-container .chosen-results li.active-result{display:list-item;cursor:pointer}.chosen-container .chosen-results li.disabled-result{display:list-item;color:#ccc;cursor:default}.chosen-container .chosen-results li.highlighted{background-color:#3875d7;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(20%,#3875d7),color-stop(90%,#2a62bc));background-image:-webkit-linear-gradient(#3875d7 20%,#2a62bc 90%);background-image:-moz-linear-gradient(#3875d7 20%,#2a62bc 90%);background-image:-o-linear-gradient(#3875d7 20%,#2a62bc 90%);background-image:linear-gradient(#3875d7 20%,#2a62bc 90%);color:#fff}.chosen-container .chosen-results li.no-results{display:list-item;background:#f4f4f4}.chosen-container .chosen-results li.group-result{display:list-item;font-weight:700;cursor:default}.chosen-container .chosen-results li.group-option{padding-left:15px}.chosen-container .chosen-results li em{font-style:normal;text-decoration:underline}.chosen-container-multi .chosen-choices{position:relative;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0;width:100%;height:auto!important;height:1%;border:1px solid #aaa;background-color:#fff;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(1%,#eee),color-stop(15%,#fff));background-image:-webkit-linear-gradient(#eee 1%,#fff 15%);background-image:-moz-linear-gradient(#eee 1%,#fff 15%);background-image:-o-linear-gradient(#eee 1%,#fff 15%);background-image:linear-gradient(#eee 1%,#fff 15%);cursor:text}.chosen-container-multi .chosen-choices li{float:left;list-style:none}.chosen-container-multi .chosen-choices li.search-field{margin:0;padding:0;white-space:nowrap}.chosen-container-multi .chosen-choices li.search-field input[type=text]{margin:1px 0;padding:5px;height:15px;outline:0;border:0!important;background:transparent!important;box-shadow:none;color:#666;font-size:100%;font-family:sans-serif;line-height:normal;border-radius:0}.chosen-container-multi .chosen-choices li.search-field .default{color:#999}.chosen-container-multi .chosen-choices li.search-choice{position:relative;margin:3px 0 3px 5px;padding:3px 20px 3px 5px;border:1px solid #aaa;border-radius:3px;background-color:#e4e4e4;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(20%,#f4f4f4),color-stop(50%,#f0f0f0),color-stop(52%,#e8e8e8),color-stop(100%,#eee));background-image:-webkit-linear-gradient(#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:-moz-linear-gradient(#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:-o-linear-gradient(#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:linear-gradient(#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-clip:padding-box;box-shadow:0 0 2px #fff inset,0 1px 0 rgba(0,0,0,.05);color:#333;line-height:13px;cursor:default}.chosen-container-multi .chosen-choices li.search-choice .search-choice-close{position:absolute;top:4px;right:3px;display:block;width:12px;height:12px;background:url(chosen-sprite.png) -42px 1px no-repeat;font-size:1px}.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover{background-position:-42px -10px}.chosen-container-multi .chosen-choices li.search-choice-disabled{padding-right:5px;border:1px solid #ccc;background-color:#e4e4e4;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(20%,#f4f4f4),color-stop(50%,#f0f0f0),color-stop(52%,#e8e8e8),color-stop(100%,#eee));background-image:-webkit-linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:-moz-linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:-o-linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);color:#666}.chosen-container-multi .chosen-choices li.search-choice-focus{background:#d4d4d4}.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close{background-position:-42px -10px}.chosen-container-multi .chosen-results{margin:0;padding:0}.chosen-container-multi .chosen-drop .result-selected{display:list-item;color:#ccc;cursor:default}.chosen-container-active .chosen-single{border:1px solid #5897fb;box-shadow:0 0 5px rgba(0,0,0,.3)}.chosen-container-active.chosen-with-drop .chosen-single{border:1px solid #aaa;-moz-border-radius-bottomright:0;border-bottom-right-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(20%,#eee),color-stop(80%,#fff));background-image:-webkit-linear-gradient(#eee 20%,#fff 80%);background-image:-moz-linear-gradient(#eee 20%,#fff 80%);background-image:-o-linear-gradient(#eee 20%,#fff 80%);background-image:linear-gradient(#eee 20%,#fff 80%);box-shadow:0 1px 0 #fff inset}.chosen-container-active.chosen-with-drop .chosen-single div{border-left:0;background:transparent}.chosen-container-active.chosen-with-drop .chosen-single div b{background-position:-18px 2px}.chosen-container-active .chosen-choices{border:1px solid #5897fb;box-shadow:0 0 5px rgba(0,0,0,.3)}.chosen-container-active .chosen-choices li.search-field input[type=text]{color:#111!important}.chosen-disabled{opacity:.5!important;cursor:default}.chosen-disabled .chosen-single{cursor:default}.chosen-disabled .chosen-choices .search-choice .search-choice-close{cursor:default}.chosen-rtl{text-align:right}.chosen-rtl .chosen-single{overflow:visible;padding:0 8px 0 0}.chosen-rtl .chosen-single span{margin-right:0;margin-left:26px;direction:rtl}.chosen-rtl .chosen-single-with-deselect span{margin-left:38px}.chosen-rtl .chosen-single div{right:auto;left:3px}.chosen-rtl .chosen-single abbr{right:auto;left:26px}.chosen-rtl .chosen-choices li{float:right}.chosen-rtl .chosen-choices li.search-field input[type=text]{direction:rtl}.chosen-rtl .chosen-choices li.search-choice{margin:3px 5px 3px 0;padding:3px 5px 3px 19px}.chosen-rtl .chosen-choices li.search-choice .search-choice-close{right:auto;left:4px}.chosen-rtl.chosen-container-single-nosearch .chosen-search,.chosen-rtl .chosen-drop{left:9999px}.chosen-rtl.chosen-container-single .chosen-results{margin:0 0 4px 4px;padding:0 4px 0 0}.chosen-rtl .chosen-results li.group-option{padding-right:15px;padding-left:0}.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div{border-right:0}.chosen-rtl .chosen-search input[type=text]{padding:4px 5px 4px 20px;background:#fff url(chosen-sprite.png) no-repeat -30px -20px;background:url(chosen-sprite.png) no-repeat -30px -20px,-webkit-gradient(linear,50% 0,50% 100%,color-stop(1%,#eee),color-stop(15%,#fff));background:url(chosen-sprite.png) no-repeat -30px -20px,-webkit-linear-gradient(#eee 1%,#fff 15%);background:url(chosen-sprite.png) no-repeat -30px -20px,-moz-linear-gradient(#eee 1%,#fff 15%);background:url(chosen-sprite.png) no-repeat -30px -20px,-o-linear-gradient(#eee 1%,#fff 15%);background:url(chosen-sprite.png) no-repeat -30px -20px,linear-gradient(#eee 1%,#fff 15%);direction:rtl}.chosen-rtl.chosen-container-single .chosen-single div b{background-position:6px 2px}.chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b{background-position:-12px 2px}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-resolution:144dpi){.chosen-rtl .chosen-search input[type=text],.chosen-container-single .chosen-single abbr,.chosen-container-single .chosen-single div b,.chosen-container-single .chosen-search input[type=text],.chosen-container-multi .chosen-choices .search-choice .search-choice-close,.chosen-container .chosen-results-scroll-down span,.chosen-container .chosen-results-scroll-up span{background-image:url(chosen-sprite@2x.png)!important;background-size:52px 37px!important;background-repeat:no-repeat!important}} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/dropzone.css b/gridplatform/bootstrap/static/bootstrap/genius/css/dropzone.css new file mode 100644 index 0000000..569645a --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/dropzone.css @@ -0,0 +1,410 @@ +/* The MIT License */ +.dropzone, +.dropzone *, +.dropzone-previews, +.dropzone-previews * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.dropzone { + position: relative; + border: 1px solid rgba(0,0,0,0.08); + background: rgba(0,0,0,0.02); + padding: 1em; +} +.dropzone.dz-clickable { + cursor: pointer; +} +.dropzone.dz-clickable .dz-message, +.dropzone.dz-clickable .dz-message span { + cursor: pointer; +} +.dropzone.dz-clickable * { + cursor: default; +} +.dropzone .dz-message { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone.dz-drag-hover { + border-color: rgba(0,0,0,0.15); + background: rgba(0,0,0,0.04); +} +.dropzone.dz-started .dz-message { + display: none; +} +.dropzone .dz-preview, +.dropzone-previews .dz-preview { + background: rgba(255,255,255,0.8); + position: relative; + display: inline-block; + margin: 17px; + vertical-align: top; + border: 1px solid #acacac; + padding: 6px 6px 6px 6px; +} +.dropzone .dz-preview.dz-file-preview [data-dz-thumbnail], +.dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail] { + display: none; +} +.dropzone .dz-preview .dz-details, +.dropzone-previews .dz-preview .dz-details { + width: 100px; + height: 100px; + position: relative; + background: #ebebeb; + padding: 5px; + margin-bottom: 22px; +} +.dropzone .dz-preview .dz-details .dz-filename, +.dropzone-previews .dz-preview .dz-details .dz-filename { + overflow: hidden; + height: 100%; +} +.dropzone .dz-preview .dz-details img, +.dropzone-previews .dz-preview .dz-details img { + position: absolute; + top: 0; + left: 0; + width: 100px; + height: 100px; +} +.dropzone .dz-preview .dz-details .dz-size, +.dropzone-previews .dz-preview .dz-details .dz-size { + position: absolute; + bottom: -28px; + left: 3px; + height: 28px; + line-height: 28px; +} +.dropzone .dz-preview.dz-error .dz-error-mark, +.dropzone-previews .dz-preview.dz-error .dz-error-mark { + display: block; +} +.dropzone .dz-preview.dz-success .dz-success-mark, +.dropzone-previews .dz-preview.dz-success .dz-success-mark { + display: block; +} +.dropzone .dz-preview:hover .dz-details img, +.dropzone-previews .dz-preview:hover .dz-details img { + display: none; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark, +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + display: none; + position: absolute; + width: 40px; + height: 40px; + font-size: 30px; + text-align: center; + right: -10px; + top: -10px; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + color: #8cc657; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + color: #ee162d; +} +.dropzone .dz-preview .dz-progress, +.dropzone-previews .dz-preview .dz-progress { + position: absolute; + top: 100px; + left: 6px; + right: 6px; + height: 6px; + background: #d7d7d7; + display: none; +} +.dropzone .dz-preview .dz-progress .dz-upload, +.dropzone-previews .dz-preview .dz-progress .dz-upload { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 0%; + background-color: #8cc657; +} +.dropzone .dz-preview.dz-processing .dz-progress, +.dropzone-previews .dz-preview.dz-processing .dz-progress { + display: block; +} +.dropzone .dz-preview .dz-error-message, +.dropzone-previews .dz-preview .dz-error-message { + display: none; + position: absolute; + top: -5px; + left: -20px; + background: rgba(245,245,245,0.8); + padding: 8px 10px; + color: #800; + min-width: 140px; + max-width: 500px; + z-index: 500; +} +.dropzone .dz-preview:hover.dz-error .dz-error-message, +.dropzone-previews .dz-preview:hover.dz-error .dz-error-message { + display: block; +} +.dropzone { + border: 1px solid rgba(0,0,0,0.03); + min-height: 360px; + -webkit-border-radius: 3px; + border-radius: 3px; + background: rgba(0,0,0,0.03); + padding: 23px; +} +.dropzone .dz-default.dz-message { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transition: opacity 0.3s ease-in-out; + -moz-transition: opacity 0.3s ease-in-out; + -o-transition: opacity 0.3s ease-in-out; + -ms-transition: opacity 0.3s ease-in-out; + transition: opacity 0.3s ease-in-out; + background-image: url("../img/spritemap.png"); + background-repeat: no-repeat; + background-position: 0 0; + position: absolute; + width: 428px; + height: 123px; + margin-left: -214px; + margin-top: -61.5px; + top: 50%; + left: 50%; +} +@media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { + .dropzone .dz-default.dz-message { + background-image: url("../img/spritemap@2x.png"); + -webkit-background-size: 428px 406px; + -moz-background-size: 428px 406px; + background-size: 428px 406px; + } +} +.dropzone .dz-default.dz-message span { + display: none; +} +.dropzone.dz-square .dz-default.dz-message { + background-position: 0 -123px; + width: 268px; + margin-left: -134px; + height: 174px; + margin-top: -87px; +} +.dropzone.dz-drag-hover .dz-message { + opacity: 0.15; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=15)"; + filter: alpha(opacity=15); +} +.dropzone.dz-started .dz-message { + display: block; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.dropzone .dz-preview, +.dropzone-previews .dz-preview { + -webkit-box-shadow: 1px 1px 4px rgba(0,0,0,0.16); + box-shadow: 1px 1px 4px rgba(0,0,0,0.16); + font-size: 14px; +} +.dropzone .dz-preview.dz-image-preview:hover .dz-details img, +.dropzone-previews .dz-preview.dz-image-preview:hover .dz-details img { + display: block; + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); +} +.dropzone .dz-preview.dz-success .dz-success-mark, +.dropzone-previews .dz-preview.dz-success .dz-success-mark { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone .dz-preview.dz-error .dz-error-mark, +.dropzone-previews .dz-preview.dz-error .dz-error-mark { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone .dz-preview.dz-error .dz-progress .dz-upload, +.dropzone-previews .dz-preview.dz-error .dz-progress .dz-upload { + background: #ee1e2d; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark, +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + display: block; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.4s ease-in-out; + -moz-transition: opacity 0.4s ease-in-out; + -o-transition: opacity 0.4s ease-in-out; + -ms-transition: opacity 0.4s ease-in-out; + transition: opacity 0.4s ease-in-out; + background-image: url("../img/spritemap.png"); + background-repeat: no-repeat; +} +@media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { + .dropzone .dz-preview .dz-error-mark, + .dropzone-previews .dz-preview .dz-error-mark, + .dropzone .dz-preview .dz-success-mark, + .dropzone-previews .dz-preview .dz-success-mark { + background-image: url("../img/spritemap@2x.png"); + -webkit-background-size: 428px 406px; + -moz-background-size: 428px 406px; + background-size: 428px 406px; + } +} +.dropzone .dz-preview .dz-error-mark span, +.dropzone-previews .dz-preview .dz-error-mark span, +.dropzone .dz-preview .dz-success-mark span, +.dropzone-previews .dz-preview .dz-success-mark span { + display: none; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + background-position: -268px -123px; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + background-position: -268px -163px; +} +.dropzone .dz-preview .dz-progress .dz-upload, +.dropzone-previews .dz-preview .dz-progress .dz-upload { + -webkit-animation: loading 0.4s linear infinite; + -moz-animation: loading 0.4s linear infinite; + -o-animation: loading 0.4s linear infinite; + -ms-animation: loading 0.4s linear infinite; + animation: loading 0.4s linear infinite; + -webkit-transition: width 0.3s ease-in-out; + -moz-transition: width 0.3s ease-in-out; + -o-transition: width 0.3s ease-in-out; + -ms-transition: width 0.3s ease-in-out; + transition: width 0.3s ease-in-out; + -webkit-border-radius: 2px; + border-radius: 2px; + position: absolute; + top: 0; + left: 0; + width: 0%; + height: 100%; + background-image: url("../img/spritemap.png"); + background-repeat: repeat-x; + background-position: 0px -400px; +} +@media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { + .dropzone .dz-preview .dz-progress .dz-upload, + .dropzone-previews .dz-preview .dz-progress .dz-upload { + background-image: url("../img/spritemap@2x.png"); + -webkit-background-size: 428px 406px; + -moz-background-size: 428px 406px; + background-size: 428px 406px; + } +} +.dropzone .dz-preview.dz-success .dz-progress, +.dropzone-previews .dz-preview.dz-success .dz-progress { + display: block; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.4s ease-in-out; + -moz-transition: opacity 0.4s ease-in-out; + -o-transition: opacity 0.4s ease-in-out; + -ms-transition: opacity 0.4s ease-in-out; + transition: opacity 0.4s ease-in-out; +} +.dropzone .dz-preview .dz-error-message, +.dropzone-previews .dz-preview .dz-error-message { + display: block; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.3s ease-in-out; + -moz-transition: opacity 0.3s ease-in-out; + -o-transition: opacity 0.3s ease-in-out; + -ms-transition: opacity 0.3s ease-in-out; + transition: opacity 0.3s ease-in-out; +} +.dropzone .dz-preview:hover.dz-error .dz-error-message, +.dropzone-previews .dz-preview:hover.dz-error .dz-error-message { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone a.dz-remove, +.dropzone-previews a.dz-remove { + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fafafa), color-stop(1, #eee)); + background-image: -webkit-linear-gradient(top, #fafafa 0, #eee 100%); + background-image: -moz-linear-gradient(top, #fafafa 0, #eee 100%); + background-image: -o-linear-gradient(top, #fafafa 0, #eee 100%); + background-image: -ms-linear-gradient(top, #fafafa 0, #eee 100%); + background-image: linear-gradient(top, #fafafa 0, #eee 100%); + -webkit-border-radius: 2px; + border-radius: 2px; + border: 1px solid #eee; + text-decoration: none; + display: block; + padding: 4px 5px; + text-align: center; + color: #aaa; + margin-top: 26px; +} +.dropzone a.dz-remove:hover, +.dropzone-previews a.dz-remove:hover { + color: #666; +} +@-moz-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@-webkit-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@-o-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@-ms-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/elfinder.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/elfinder.min.css new file mode 100755 index 0000000..7109563 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/elfinder.min.css @@ -0,0 +1,9 @@ +/*! + * elFinder - file manager for web + * Version 2.0 rc1 (2012-04-10) + * http://elfinder.org + * + * Copyright 2009-2012, Studio 42 + * Licensed under a 3 clauses BSD license + */ +.elfinder-dialog-resize{margin-top:.3em}.elfinder-resize-type{float:left;margin-bottom:.4em}.elfinder-resize-control{padding-top:3em}.elfinder-resize-control input[type=text]{border:1px solid #aaa;text-align:right}.elfinder-resize-preview{width:400px;height:400px;padding:10px;background:#fff;border:1px solid #aaa;float:right;position:relative;overflow:auto}.elfinder-resize-handle{position:relative}.elfinder-resize-handle-hline,.elfinder-resize-handle-vline{position:absolute;background-image:url("../img/crop.gif")}.elfinder-resize-handle-hline{width:100%;height:1px!important;background-repeat:repeat-x}.elfinder-resize-handle-vline{width:1px!important;height:100%;background-repeat:repeat-y}.elfinder-resize-handle-hline-top{top:0;left:0}.elfinder-resize-handle-hline-bottom{bottom:0;left:0}.elfinder-resize-handle-vline-left{top:0;left:0}.elfinder-resize-handle-vline-right{top:0;right:0}.elfinder-resize-handle-point{position:absolute;width:8px;height:8px;border:1px solid #777;background:0 0}.elfinder-resize-handle-point-n{top:0;left:50%;margin-top:-5px;margin-left:-5px}.elfinder-resize-handle-point-ne{top:0;right:0;margin-top:-5px;margin-right:-5px}.elfinder-resize-handle-point-e{top:50%;right:0;margin-top:-5px;margin-right:-5px}.elfinder-resize-handle-point-se{bottom:0;right:0;margin-bottom:-5px;margin-right:-5px}.elfinder-resize-handle-point-s{bottom:0;left:50%;margin-bottom:-5px;margin-left:-5px}.elfinder-resize-handle-point-sw{bottom:0;left:0;margin-bottom:-5px;margin-left:-5px}.elfinder-resize-handle-point-w{top:50%;left:0;margin-top:-5px;margin-left:-5px}.elfinder-resize-handle-point-nw{top:0;left:0;margin-top:-5px;margin-left:-5px}.elfinder-resize-spinner{position:absolute;width:200px;height:30px;top:50%;margin-top:-25px;left:50%;margin-left:-100px;text-align:center;background:url(../img/progress.gif) center bottom repeat-x}.elfinder-resize-row{margin-bottom:7px;position:relative}.elfinder-resize-label{float:left;width:80px;padding-top:3px}.elfinder-resize-reset{width:16px;height:16px;position:absolute;margin-top:-8px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-e{height:100%;width:10px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-s{width:100%;height:10px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-se{background:0 0;bottom:0;right:0;margin-right:-7px;margin-bottom:-7px}.elfinder-dialog-resize .ui-icon-grip-solid-vertical{position:absolute;top:50%;right:0;margin-top:-8px;margin-right:-11px}.elfinder-dialog-resize .ui-icon-grip-solid-horizontal{position:absolute;left:50%;bottom:0;margin-left:-8px;margin-bottom:-11px}.elfinder-resize-row .elfinder-buttonset{float:right}.elfinder-resize-rotate-slider{float:left;width:195px;margin:7px 7px 0}.elfinder-file-edit{width:99%;height:99%;margin:0;padding:2px;border:1px solid #ccc}.elfinder-help{margin-bottom:.5em}.elfinder-help .ui-tabs-panel{padding:.5em}.elfinder-dialog .ui-tabs .ui-tabs-nav li a{padding:.2em 1em}.elfinder-help-shortcuts{height:300px;padding:1em;margin:.5em 0;overflow:auto}.elfinder-help-shortcut{white-space:nowrap;clear:both}.elfinder-help-shortcut-pattern{float:left;width:160px}.elfinder-help-logo{width:100px;height:96px;float:left;margin-right:1em;}.elfinder-help h3{font-size:1.5em;margin:.2em 0 .3em}.elfinder-help-separator{clear:both;padding:.5em}.elfinder-help-link{padding:2px}.elfinder-help .ui-priority-secondary{font-size:.9em}.elfinder-help .ui-priority-primary{margin-bottom:7px}.elfinder-help-team{clear:both;text-align:right;border-bottom:1px solid #ccc;margin:.5em 0;font-size:.9em}.elfinder-help-team div{float:left}.elfinder-help-license{font-size:.9em}.elfinder-help-disabled{font-weight:700;text-align:center;margin:90px 0}.elfinder-help .elfinder-dont-panic{display:block;border:1px solid transparent;width:200px;height:200px;margin:30px auto;text-decoration:none;text-align:center;position:relative;background:#d90004;-moz-box-shadow:5px 5px 9px #111;-webkit-box-shadow:5px 5px 9px #111;box-shadow:5px 5px 9px #111;background:-moz-radial-gradient(80px 80px,circle farthest-corner,#d90004 35%,#960004 100%);background:-webkit-gradient(radial,80 80,60,80 80,120,from(#d90004),to(#960004));-moz-border-radius:100px;-webkit-border-radius:100px;border-radius:100px;outline:none}.elfinder-help .elfinder-dont-panic span{font-size:3em;font-weight:700;text-align:center;color:#fff;position:absolute;left:0;top:45px}.elfinder{padding:0;position:relative;display:block}.elfinder-rtl{text-align:right;direction:rtl}.elfinder-workzone{padding:0;position:relative;overflow:hidden}.elfinder-perms,.elfinder-symlink{position:absolute;width:16px;height:16px;background-image:url(../img/toolbar.png);background-repeat:no-repeat;background-position:0 -528px}.elfinder-na .elfinder-perms{background-position:0 -96px}.elfinder-ro .elfinder-perms{background-position:0 -64px}.elfinder-wo .elfinder-perms{background-position:0 -80px}.elfinder-drag-helper{width:60px;height:50px;padding:0 0 0 25px;z-index:100000}.elfinder-drag-helper-icon-plus{position:absolute;width:16px;height:16px;left:43px;top:55px;background:url('../img/toolbar.png') 0 -544px no-repeat;display:none}.elfinder-drag-helper-plus .elfinder-drag-helper-icon-plus{display:block}.elfinder-drag-num{position:absolute;top:0;left:0;width:16px;height:14px;text-align:center;padding-top:2px;font-size:12px;font-weight:700;color:#fff;background-color:red;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}.elfinder-drag-helper .elfinder-cwd-icon{margin:0 0 0 -24px;float:left}.elfinder-overlay{opacity:0;filter:Alpha(Opacity=0)}.elfinder .elfinder-panel{position:relative;background-image:none;padding:7px 12px}.elfinder-contextmenu,.elfinder-contextmenu-sub{display:none;position:absolute;border:1px solid #aaa;background:#fff;color:#555;padding:4px 0}.elfinder-contextmenu-sub{top:5px}.elfinder-contextmenu-ltr .elfinder-contextmenu-sub{margin-left:-5px}.elfinder-contextmenu-rtl .elfinder-contextmenu-sub{margin-right:-5px}.elfinder-contextmenu-item{position:relative;display:block;padding:4px 30px;text-decoration:none;white-space:nowrap;cursor:default}.elfinder-contextmenu .elfinder-contextmenu-item span{font-size:.76em;display:block}.elfinder-contextmenu-ltr .elfinder-contextmenu-item{text-align:left}.elfinder-contextmenu-rtl .elfinder-contextmenu-item{text-align:right}.elfinder-contextmenu-ltr .elfinder-contextmenu-sub .elfinder-contextmenu-item{padding-left:12px}.elfinder-contextmenu-rtl .elfinder-contextmenu-sub .elfinder-contextmenu-item{padding-right:12px}.elfinder-contextmenu-arrow,.elfinder-contextmenu-icon{position:absolute;top:50%;margin-top:-8px}.elfinder-contextmenu-ltr .elfinder-contextmenu-icon{left:8px}.elfinder-contextmenu-rtl .elfinder-contextmenu-icon{right:8px}.elfinder-contextmenu-arrow{width:16px;height:16px;background:url('../img/arrows-normal.png') 5px 4px no-repeat}.elfinder-contextmenu-ltr .elfinder-contextmenu-arrow{right:5px}.elfinder-contextmenu-rtl .elfinder-contextmenu-arrow{left:5px;background-position:0 -10px}.elfinder-contextmenu .ui-state-hover{border:0 solid;background-image:none}.elfinder-contextmenu-separator{height:0;border-top:1px solid #ccc;margin:0 1px}.elfinder-cwd-wrapper{overflow:auto;position:relative;padding:2px;margin:0}.elfinder-cwd-wrapper-list{padding:0}.elfinder-cwd{position:relative;font-size:.7em;cursor:default;padding:0;margin:0;-moz-user-select:-moz-none;-khtml-user-select:none;-webkit-user-select:none;user-select:none}.elfinder .elfinder-cwd-wrapper.elfinder-droppable-active{padding:0;border:2px solid #8cafed}.elfinder-cwd-view-icons .elfinder-cwd-file{width:120px;height:80px;padding-bottom:2px;cursor:default;overflow:hidden}.elfinder-ltr .elfinder-cwd-view-icons .elfinder-cwd-file{float:left;margin:0 3px 12px 0}.elfinder-rtl .elfinder-cwd-view-icons .elfinder-cwd-file{float:right;margin:0 0 5px 3px}.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-hover{border:0 solid}.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper{width:52px;height:52px;margin:1px auto;padding:2px;position:relative}.elfinder-cwd-view-icons .elfinder-cwd-filename{text-align:center;white-space:pre;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis;margin:3px 1px 0;padding:1px;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}.elfinder-cwd-view-icons .elfinder-perms{bottom:4px;right:2px}.elfinder-cwd-view-icons .elfinder-symlink{bottom:6px;left:0}.elfinder-cwd-icon{display:block;width:48px;height:48px;margin:0 auto;background:url('../img/icons-big.png') 0 0 no-repeat;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.elfinder-cwd .elfinder-droppable-active .elfinder-cwd-icon{background-position:0 -100px}.elfinder-cwd-icon-directory{background-position:0 -50px}.elfinder-cwd-icon-application{background-position:0 -150px}.elfinder-cwd-icon-x-empty,.elfinder-cwd-icon-text{background-position:0 -200px}.elfinder-cwd-icon-image,.elfinder-cwd-icon-vnd-adobe-photoshop,.elfinder-cwd-icon-postscript{background-position:0 -250px}.elfinder-cwd-icon-audio{background-position:0 -300px}.elfinder-cwd-icon-video,.elfinder-cwd-icon-flash-video{background-position:0 -350px}.elfinder-cwd-icon-rtf,.elfinder-cwd-icon-rtfd{background-position:0 -401px}.elfinder-cwd-icon-pdf{background-position:0 -450px}.elfinder-cwd-icon-vnd-ms-office,.elfinder-cwd-icon-msword,.elfinder-cwd-icon-vnd-ms-word,.elfinder-cwd-icon-vnd-oasis-opendocument-text,.elfinder-cwd-icon-ms-excel,.elfinder-cwd-icon-vnd-ms-excel,.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet,.elfinder-cwd-icon-vnd-ms-powerpoint,.elfinder-cwd-icon-vnd-oasis-opendocument-presentation{background-position:0 -500px}.elfinder-cwd-icon-html{background-position:0 -550px}.elfinder-cwd-icon-css{background-position:0 -600px}.elfinder-cwd-icon-javascript,.elfinder-cwd-icon-x-javascript{background-position:0 -650px}.elfinder-cwd-icon-x-perl{background-position:0 -700px}.elfinder-cwd-icon-x-python{background-position:0 -750px}.elfinder-cwd-icon-x-ruby{background-position:0 -800px}.elfinder-cwd-icon-x-sh,.elfinder-cwd-icon-x-shellscript{background-position:0 -850px}.elfinder-cwd-icon-x-c,.elfinder-cwd-icon-x-csrc,.elfinder-cwd-icon-x-chdr,.elfinder-cwd-icon-x-c--,.elfinder-cwd-icon-x-c--src,.elfinder-cwd-icon-x-c--hdr,.elfinder-cwd-icon-x-java,.elfinder-cwd-icon-x-java-source{background-position:0 -900px}.elfinder-cwd-icon-x-php{background-position:0 -950px}.elfinder-cwd-icon-xml{background-position:0 -1000px}.elfinder-cwd-icon-zip,.elfinder-cwd-icon-x-zip,.elfinder-cwd-icon-x-7z-compressed{background-position:0 -1050px}.elfinder-cwd-icon-x-gzip,.elfinder-cwd-icon-x-tar{background-position:0 -1100px}.elfinder-cwd-icon-x-bzip,.elfinder-cwd-icon-x-bzip2{background-position:0 -1150px}.elfinder-cwd-icon-x-rar,.elfinder-cwd-icon-x-rar-compressed{background-position:0 -1200px}.elfinder-cwd-icon-x-shockwave-flash{background-position:0 -1250px}.elfinder-cwd-icon-group{background-position:0 -1300px}.elfinder-cwd input{width:100%;border:0 solid;margin:0;padding:0}.elfinder-cwd-view-icons input,.elfinder-cwd-view-icons{text-align:center}.elfinder-cwd table{width:100%;border-collapse:collapse;border:0 solid;margin:0 0 10px}.elfinder .elfinder-cwd table thead tr{border-left:0 solid;border-top:0 solid;border-right:0 solid}.elfinder .elfinder-cwd table thead td{font-size:.9em}.elfinder .elfinder-cwd table td{padding:3px 12px;white-space:pre;overflow:hidden;text-align:right;cursor:default;border:0 solid}.elfinder-ltr .elfinder-cwd table td{text-align:right}.elfinder-ltr .elfinder-cwd table td:first-child{text-align:left}.elfinder-rtl .elfinder-cwd table td{text-align:left}.elfinder-rtl .elfinder-cwd table td:first-child{text-align:right}.elfinder-odd-row{background:#eee}.elfinder-cwd-view-list .elfinder-cwd-file-wrapper{width:97%;position:relative}.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-file-wrapper{padding-left:23px}.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-file-wrapper{padding-right:23px}.elfinder-cwd-view-list .elfinder-perms,.elfinder-cwd-view-list .elfinder-symlink{top:50%;margin-top:-6px}.elfinder-ltr .elfinder-cwd-view-list .elfinder-perms{left:7px}.elfinder-ltr .elfinder-cwd-view-list .elfinder-symlink{left:-7px}.elfinder-cwd-view-list td .elfinder-cwd-icon{width:16px;height:16px;position:absolute;top:50%;margin-top:-8px;background-image:url(../img/icons-small.png)}.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-icon{left:0}.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-icon{right:0}.std42-dialog{padding:0}.std42-dialog .ui-dialog-titlebar{border-left:0 solid transparent;border-top:0 solid transparent;border-right:0 solid transparent;-moz-border-radius-bottomleft:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomright:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;font-size:.82em;font-weight:400;padding:.2em 1em}.std42-dialog .ui-dialog-titlebar-close,.std42-dialog .ui-dialog-titlebar-close:hover{padding:1px}.elfinder-rtl .elfinder-dialog .ui-dialog-titlebar{text-align:right}.elfinder-rtl .elfinder-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close{right:auto;left:.3em}.std42-dialog .ui-dialog-content{padding:.3em .5em;font-size:.72em}.std42-dialog .ui-dialog-buttonpane{border:0 solid;margin:0;padding:.5em .7em;font-size:.76em}.std42-dialog .ui-dialog-buttonpane button{margin:0 0 0 .4em;padding:0;outline:0 solid}.std42-dialog .ui-dialog-buttonpane button span{padding:2px 9px}.elfinder-dialog .ui-resizable-e,.elfinder-dialog .ui-resizable-s{width:0;height:0}.std42-dialog .ui-button input{cursor:pointer}.elfinder-dialog-icon{position:absolute;width:32px;height:32px;left:12px;top:50%;margin-top:-15px;background:url("../img/dialogs.png") 0 0 no-repeat}.elfinder-rtl .elfinder-dialog-icon{left:auto;right:12px}.elfinder-dialog-error .ui-dialog-content,.elfinder-dialog-confirm .ui-dialog-content{padding-left:56px;min-height:35px}.elfinder-rtl .elfinder-dialog-error .ui-dialog-content,.elfinder-rtl .elfinder-dialog-confirm .ui-dialog-content{padding-left:0;padding-right:56px}.elfinder-dialog-notify .ui-dialog-titlebar-close{display:none}.elfinder-dialog-notify .ui-dialog-content{padding:0}.elfinder-notify{border-bottom:1px solid #ccc;position:relative;padding:.5em;text-align:center;overflow:hidden}.elfinder-ltr .elfinder-notify{padding-left:30px}.elfinder-rtl .elfinder-notify{padding-right:30px}.elfinder-notify:last-child{border:0 solid}.elfinder-notify-progressbar{width:180px;height:8px;border:1px solid #aaa;background:#f5f5f5;margin:5px auto;overflow:hidden}.elfinder-notify-progress{width:100%;height:8px;background:url(../img/progress.gif) center center repeat-x}.elfinder-notify-progressbar,.elfinder-notify-progress{-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px}.elfinder-dialog-icon-open,.elfinder-dialog-icon-file,.elfinder-dialog-icon-reload{background-position:0 -225px}.elfinder-dialog-icon-mkdir{background-position:0 -64px}.elfinder-dialog-icon-mkfile{background-position:0 -96px}.elfinder-dialog-icon-copy,.elfinder-dialog-icon-prepare,.elfinder-dialog-icon-move{background-position:0 -128px}.elfinder-dialog-icon-upload{background-position:0 -160px}.elfinder-dialog-icon-rm{background-position:0 -192px}.elfinder-dialog-icon-download{background-position:0 -260px}.elfinder-dialog-icon-save{background-position:0 -295px}.elfinder-dialog-icon-rename{background-position:0 -330px}.elfinder-dialog-icon-archive,.elfinder-dialog-icon-extract{background-position:0 -365px}.elfinder-dialog-icon-search{background-position:0 -402px}.elfinder-dialog-confirm-applyall{padding-top:3px}.elfinder-dialog-confirm .elfinder-dialog-icon{background-position:0 -32px}.elfinder-info-title .elfinder-cwd-icon{float:left;width:48px;height:48px;margin-right:1em}.elfinder-info-title strong{display:block;padding:.3em 0 .5em}.elfinder-info-tb{min-width:200px;border:0 solid;margin:1em .2em;font-size:.9em}.elfinder-info-tb td{white-space:nowrap;padding:2px}.elfinder-info-tb tr td:first-child{text-align:right}.elfinder-info-tb span{float:left}.elfinder-info-tb a{outline:none;text-decoration:underline}.elfinder-info-tb a:hover{text-decoration:none}.elfinder-info-spinner{width:14px;height:14px;float:left;background:url("../img/spinner-mini.gif") center center no-repeat;margin:0 5px}.elfinder-upload-dropbox{font-size:1.2em;text-align:center;padding:2em 0;border:3px dashed #aaa}.elfinder-upload-dropbox.ui-state-hover{background:#dfdfdf;border:3px dashed #555}.elfinder-upload-dialog-or{font-size:1.2em;margin:.3em 0;text-align:center}.elfinder-upload-dialog-wrapper{text-align:center}.elfinder-upload-dialog-wrapper .ui-button{position:relative;overflow:hidden}.elfinder-upload-dialog-wrapper .ui-button form{position:absolute;right:0;top:0;opacity:0;filter:Alpha(Opacity=0)}.elfinder-upload-dialog-wrapper .ui-button form input{padding:0 20px;font-size:3em}.dialogelfinder .dialogelfinder-drag{border-left:0 solid;border-top:0 solid;border-right:0 solid;font-weight:400;font-size:.9em;padding:2px 12px;cursor:move;position:relative;text-align:left}.elfinder-rtl .dialogelfinder-drag{text-align:right}.dialogelfinder-drag-close{position:absolute;top:50%;margin-top:-8px}.elfinder-ltr .dialogelfinder-drag-close{right:12px}.elfinder-rtl .dialogelfinder-drag-close{left:12px}.elfinder .elfinder-navbar{width:230px;padding:3px 5px;font-size:.72em;background-image:none;border-top:0 solid;border-bottom:0 solid;overflow:auto;display:none;position:relative;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none}.elfinder-ltr .elfinder-navbar{float:left;border-left:0 solid}.elfinder-rtl .elfinder-navbar{float:right;border-right:0 solid}.elfinder-ltr .ui-resizable-e{margin-left:10px}.elfinder-tree{display:table;width:100%;margin:0 0 .5em}.elfinder-navbar-dir{position:relative;display:block;white-space:nowrap;padding:3px 12px;margin:0;outline:0 solid;border:1px solid transparent;cursor:default}.elfinder-ltr .elfinder-navbar-dir{padding-left:35px}.elfinder-rtl .elfinder-navbar-dir{padding-right:35px}.elfinder-navbar-arrow{width:12px;height:14px;position:absolute;display:none;top:50%;margin-top:-8px;background-image:url("../img/arrows-normal.png");background-repeat:no-repeat}.ui-state-active .elfinder-navbar-arrow{background-image:url("../img/arrows-active.png")}.elfinder-navbar-collapsed .elfinder-navbar-arrow{display:block}.elfinder-ltr .elfinder-navbar-collapsed .elfinder-navbar-arrow{background-position:0 4px;left:0}.elfinder-rtl .elfinder-navbar-collapsed .elfinder-navbar-arrow{background-position:0 -10px;right:0}.elfinder-ltr .elfinder-navbar-expanded .elfinder-navbar-arrow,.elfinder-rtl .elfinder-navbar-expanded .elfinder-navbar-arrow{background-position:0 -21px}.elfinder-navbar-icon{width:16px;height:16px;position:absolute;top:50%;margin-top:-8px;background-image:url("../img/toolbar.png");background-repeat:no-repeat;background-position:0 -16px}.elfinder-ltr .elfinder-navbar-icon{left:14px}.elfinder-rtl .elfinder-navbar-icon{right:14px}.elfinder-tree .elfinder-navbar-root .elfinder-navbar-icon{background-position:0 0}.elfinder-places .elfinder-navbar-root .elfinder-navbar-icon{background-position:0 -48px}.ui-state-active .elfinder-navbar-icon,.elfinder-droppable-active .elfinder-navbar-icon,.ui-state-hover .elfinder-navbar-icon{background-position:0 -32px}.elfinder-navbar-subtree{display:none}.elfinder-ltr .elfinder-navbar-subtree{margin-left:12px}.elfinder-rtl .elfinder-navbar-subtree{margin-right:12px}.elfinder-navbar-spinner{width:14px;height:14px;position:absolute;display:block;top:50%;margin-top:-7px;background:url("../img/spinner-mini.gif") center center no-repeat}.elfinder-ltr .elfinder-navbar-spinner{left:0;margin-left:-2px}.elfinder-rtl .elfinder-navbar-spinner{right:0;margin-right:-2px}.elfinder-navbar .elfinder-perms{top:50%;margin-top:-8px}.elfinder-ltr .elfinder-navbar .elfinder-perms{left:18px}.elfinder-rtl .elfinder-navbar .elfinder-perms{right:18px}.elfinder-ltr .elfinder-navbar .elfinder-symlink{left:8px}.elfinder-rtl .elfinder-navbar .elfinder-symlink{right:8px}.elfinder-navbar .ui-resizable-handle{width:12px;background:url('../img/resize.png') center center no-repeat;left:0}.elfinder-nav-handle-icon{position:absolute;top:50%;margin:-8px 2px 0;opacity:.5;filter:Alpha(Opacity=50)}.elfinder-places{border:1px solid transparent}.elfinder-places.elfinder-droppable-active{border:1px solid #8cafed}.elfinder-place-drag .elfinder-navbar-dir{font-size:.9em}.elfinder-quicklook{position:absolute;background:url("../img/quicklook-bg.png");display:none;overflow:hidden;border-radius:7px;-moz-border-radius:7px;-webkit-border-radius:7px;padding:20px 0 40px}.elfinder-quicklook .ui-resizable-se{width:14px;height:14px;right:5px;bottom:3px;background:url("../img/toolbar.png") 0 -496px no-repeat}.elfinder-quicklook-fullscreen{border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;-webkit-background-clip:padding-box;padding:0;background:#000;z-index:90000;display:block}.elfinder-quicklook-fullscreen .elfinder-quicklook-titlebar{display:none}.elfinder-quicklook-fullscreen .elfinder-quicklook-preview{border:0 solid}.elfinder-quicklook-titlebar{text-align:center;background:#777;position:absolute;left:0;top:0;width:100%;height:20px;-moz-border-radius-topleft:7px;-webkit-border-top-left-radius:7px;border-top-left-radius:7px;-moz-border-radius-topright:7px;-webkit-border-top-right-radius:7px;border-top-right-radius:7px;cursor:move}.elfinder-quicklook-title{font-size:.7em;color:#fff;white-space:nowrap;overflow:hidden;padding:2px 0}.elfinder-quicklook-titlebar .ui-icon{position:absolute;left:4px;top:50%;margin-top:-8px;width:16px;height:16px;cursor:default}.elfinder-quicklook-preview{overflow:hidden;position:relative;border:0 solid;border-left:1px solid transparent;border-right:1px solid transparent;height:100%}.elfinder-quicklook-info-wrapper{position:absolute;width:100%;left:0;top:50%;margin-top:-50px}.elfinder-quicklook-info{padding:0 12px 0 112px}.elfinder-quicklook-info .elfinder-quicklook-info-data:first-child{color:#fff;font-weight:700;padding-bottom:.5em}.elfinder-quicklook-info-data{font-size:.72em;padding-bottom:.2em;color:#fff}.elfinder-quicklook .elfinder-cwd-icon{position:absolute;left:32px;top:50%;margin-top:-20px}.elfinder-quicklook-preview img{display:block;margin:0 auto}.elfinder-quicklook-navbar{position:absolute;left:50%;bottom:4px;width:140px;height:32px;padding:0;margin-left:-70px;border:1px solid transparent;border-radius:19px;-moz-border-radius:19px;-webkit-border-radius:19px}.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar{width:188px;margin-left:-94px;padding:5px;border:1px solid #eee;background:#000}.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-icon-close,.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-separator{display:inline}.elfinder-quicklook-navbar-icon{width:32px;height:32px;margin:0 7px;float:left;background:url("../img/quicklook-icons.png") 0 0 no-repeat}.elfinder-quicklook-navbar-icon-fullscreen{background-position:0 -64px}.elfinder-quicklook-navbar-icon-fullscreen-off{background-position:0 -96px}.elfinder-quicklook-navbar-icon-prev{background-position:0 0}.elfinder-quicklook-navbar-icon-next{background-position:0 -32px}.elfinder-quicklook-navbar-icon-close{background-position:0 -128px;display:none}.elfinder-quicklook-navbar-separator{width:1px;height:32px;float:left;border-left:1px solid #fff;display:none}.elfinder-quicklook-preview-text-wrapper{width:100%;height:100%;background:#fff;color:#222;font-size:.9em;overflow:auto}pre.elfinder-quicklook-preview-text{margin:0;padding:3px 9px}.elfinder-quicklook-preview-html,.elfinder-quicklook-preview-pdf{width:100%;height:100%;background:#fff;border:0 solid;margin:0}.elfinder-quicklook-preview-flash{width:100%;height:100%}.elfinder-quicklook-preview-audio{width:100%;position:absolute;bottom:0;left:0}embed.elfinder-quicklook-preview-audio{height:30px;background:0 0}.elfinder-quicklook-preview-video{width:100%;height:100%}.elfinder-statusbar{text-align:center;font-weight:400;padding:.2em .5em;border-right:0 solid transparent;border-bottom:0 solid transparent;border-left:0 solid transparent}.elfinder-statusbar a{text-decoration:none}.elfinder-statusbar div{font-size:.7em}.elfinder-path{max-width:30%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis}.elfinder-ltr .elfinder-path{float:left}.elfinder-rtl .elfinder-path{float:right}.elfinder-stat-size{white-space:nowrap}.elfinder-ltr .elfinder-stat-size{float:right}.elfinder-rtl .elfinder-stat-size{float:left}.elfinder-stat-selected{white-space:nowrap;overflow:hidden}.elfinder-toolbar{padding:4px 0 3px;border-left:0 solid transparent;border-top:0 solid transparent;border-right:0 solid transparent}.elfinder-buttonset{margin:1px 4px;float:left;background:0 0;padding:0;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px}.elfinder .elfinder-button{width:16px;height:16px;margin:0;padding:4px;float:left;overflow:hidden;position:relative;border:0 solid}.elfinder .ui-icon-search{cursor:pointer}.elfinder-button:first-child{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px}.elfinder-button:last-child{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.elfinder-toolbar-button-separator{float:left;padding:0;height:24px;border-top:0 solid;border-right:0 solid;border-bottom:0 solid;width:0}.elfinder .elfinder-button.ui-state-disabled{opacity:1;filter:Alpha(Opacity=100)}.elfinder .elfinder-button.ui-state-disabled .elfinder-button-icon{opacity:.4;filter:Alpha(Opacity=40)}.elfinder-rtl .elfinder-buttonset{float:right}.elfinder-button-icon{width:16px;height:16px;display:block;background:url('../img/toolbar.png') no-repeat}.elfinder-button-icon-home{background-position:0 0}.elfinder-button-icon-back{background-position:0 -112px}.elfinder-button-icon-forward{background-position:0 -128px}.elfinder-button-icon-up{background-position:0 -144px}.elfinder-button-icon-reload{background-position:0 -160px}.elfinder-button-icon-open{background-position:0 -176px}.elfinder-button-icon-mkdir{background-position:0 -192px}.elfinder-button-icon-mkfile{background-position:0 -208px}.elfinder-button-icon-rm{background-position:0 -224px}.elfinder-button-icon-copy{background-position:0 -240px}.elfinder-button-icon-cut{background-position:0 -256px}.elfinder-button-icon-paste{background-position:0 -272px}.elfinder-button-icon-getfile{background-position:0 -288px}.elfinder-button-icon-duplicate{background-position:0 -304px}.elfinder-button-icon-rename{background-position:0 -320px}.elfinder-button-icon-edit{background-position:0 -336px}.elfinder-button-icon-quicklook{background-position:0 -352px}.elfinder-button-icon-upload{background-position:0 -368px}.elfinder-button-icon-download{background-position:0 -384px}.elfinder-button-icon-info{background-position:0 -400px}.elfinder-button-icon-extract{background-position:0 -416px}.elfinder-button-icon-archive{background-position:0 -432px}.elfinder-button-icon-view{background-position:0 -448px}.elfinder-button-icon-view-list{background-position:0 -464px}.elfinder-button-icon-help{background-position:0 -480px}.elfinder-button-icon-resize{background-position:0 -512px}.elfinder-button-icon-search{background-position:0 -561px}.elfinder-button-icon-sort{background-position:0 -577px}.elfinder-button-icon-rotate-r{background-position:0 -625px}.elfinder-button-icon-rotate-l{background-position:0 -641px}.elfinder .elfinder-menubutton{overflow:visible}.elfinder-button-menu{position:absolute;left:0;top:26px;padding:3px 0}.elfinder-button-menu-item{white-space:nowrap;font-size:.72em;cursor:default;padding:5px 19px;position:relative}.elfinder-button-menu .ui-state-hover{border:0 solid}.elfinder-menu-item-sort-dir{width:16px;height:16px;position:absolute;left:2px;top:50%;margin-top:-8px;background:url("../img/toolbar.png") 0 -594px no-repeat;display:none}.elfinder-button-menu-item-selected .elfinder-menu-item-sort-dir{display:block}.elfinder-menu-item-sort-desc .elfinder-menu-item-sort-dir{background-position:0 -608px}.elfinder-button form{position:absolute;top:0;right:0;opacity:0;filter:Alpha(Opacity=0);cursor:pointer}.elfinder .elfinder-button form input{background:0 0;cursor:default}.elfinder .elfinder-button-search{border:0 solid;background:0 0;padding:0;margin:1px 4px;height:auto;min-height:26px;float:right;width:202px}.elfinder-ltr .elfinder-button-search{float:right;margin-right:10px}.elfinder-rtl .elfinder-button-search{float:left;margin-left:10px}.elfinder-button-search input{width:160px;height:22px;padding:0 20px;font-size:.8em;line-height:22px;border:1px solid #aaa;-moz-border-radius:12px;-webkit-border-radius:12px;border-radius:12px;outline:0 solid}.elfinder-rtl .elfinder-button-search input{direction:rtl}.elfinder-button-search .ui-icon{position:absolute;height:18px;top:50%;margin:-9px 4px 0;opacity:.6;filter:Alpha(Opacity=60)}.elfinder-ltr .elfinder-button-search .ui-icon-search{left:0}.elfinder-rtl .elfinder-button-search .ui-icon-search,.elfinder-ltr .elfinder-button-search .ui-icon-close{right:0}.elfinder-rtl .elfinder-button-search .ui-icon-close{left:0} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/elfinder.theme.css b/gridplatform/bootstrap/static/bootstrap/genius/css/elfinder.theme.css new file mode 100755 index 0000000..369270a --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/elfinder.theme.css @@ -0,0 +1,49 @@ +/** + * MacOS X like theme for elFinder. + * Required jquery ui "smoothness" theme. + * + * @author Dmitry (dio) Levashov + **/ + +/* dialogs */ +.std42-dialog, .std42-dialog .ui-widget-content { background-color:#ededed; background-image:none; background-clip: content-box; } + +/* navbar */ +.elfinder .elfinder-navbar { background:#dde4eb; } +.elfinder-navbar .ui-state-hover { background:transparent; border-color:transparent; } +.elfinder-navbar .ui-state-active { background: #3875d7; border-color:#3875d7; color:#fff; } +/* disabled elfinder */ +.elfinder-disabled .elfinder-navbar .ui-state-active { background: #dadada; border-color:#aaa; color:#fff; } + + +/* current directory */ +/* selected file in "icons" view */ +.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-hover { background:#ccc; } +/* list view*/ +.elfinder-cwd table tr:nth-child(odd) { background-color:#edf3fe; } +.elfinder-cwd table tr { border-top:1px solid #fff; } + +/* common selected background/color */ +.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-filename.ui-state-hover, +.elfinder-cwd table td.ui-state-hover, +.elfinder-button-menu .ui-state-hover { background: #3875d7; color:#fff;} +/* disabled elfinder */ +.elfinder-disabled .elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-filename.ui-state-hover, +.elfinder-disabled .elfinder-cwd table td.ui-state-hover { background:#dadada;} + +/* statusbar */ +.elfinder .elfinder-statusbar { color:#555; } +.elfinder .elfinder-statusbar a { text-decoration:none; color:#555;} + + +.std42-dialog .elfinder-help, .std42-dialog .elfinder-help .ui-widget-content { background:#fff;} + +/* contextmenu */ +.elfinder-contextmenu .ui-state-hover { background: #3875d7; color:#fff; } +.elfinder-contextmenu .ui-state-hover .elfinder-contextmenu-arrow { background-image:url('../img/arrows-active.png'); } + + + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/filetypes.css b/gridplatform/bootstrap/static/bootstrap/genius/css/filetypes.css new file mode 100644 index 0000000..bb3be76 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/filetypes.css @@ -0,0 +1,839 @@ +/*! + * + * Project: GLYPHICONS HALFLINGS + * Author: Jan Kovarik - www.glyphicons.com + * Twitter: @glyphicons + * + */ +@font-face { + font-family: 'Glyphicons Filetypes Regular'; + src: url('../fonts/glyphicons-filetypes-regular.eot'); + src: url('../fonts/glyphicons-filetypes-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-filetypes-regular.woff') format('woff'); + font-weight: normal; + font-style: normal; +} +.filetype { + display: inline-block; + position: relative; + padding-left: 30px; + color: #1d1d1b; + text-decoration: none; + *display: inline; + *zoom: 1; + vertical-align: middle; +} +.filetype:before { + position: absolute; + left: 0; + top: 0; + display: inline-block; + margin: 0 5px 0 0; + font: 24px/1em 'Glyphicons Filetypes Regular'; + font-style: normal; + font-weight: normal; + color: #1d1d1b; + *display: inline; + *zoom: 1; + vertical-align: middle; + text-transform: none; + -webkit-font-smoothing: antialiased; +} +.filetype.white:before { + color: #fff; +} +.filetype.txt:before { + content: "\E001"; +} +.filetype.doc:before { + content: "\E002"; +} +.filetype.rtf:before { + content: "\E003"; +} +.filetype.log:before { + content: "\E004"; +} +.filetype.tex:before { + content: "\E005"; +} +.filetype.msg:before { + content: "\E006"; +} +.filetype.text:before { + content: "\E007"; +} +.filetype.wpd:before { + content: "\E008"; +} +.filetype.wps:before { + content: "\E009"; +} +.filetype.docx:before { + content: "\E010"; +} +.filetype.page:before { + content: "\E011"; +} +.filetype.csv:before { + content: "\E012"; +} +.filetype.dat:before { + content: "\E013"; +} +.filetype.tar:before { + content: "\E014"; +} +.filetype.xml:before { + content: "\E015"; +} +.filetype.vcf:before { + content: "\E016"; +} +.filetype.pps:before { + content: "\E017"; +} +.filetype.key:before { + content: "\1F511"; +} +.filetype.ppt:before { + content: "\E019"; +} +.filetype.pptx:before { + content: "\E020"; +} +.filetype.sdf:before { + content: "\E021"; +} +.filetype.gbr:before { + content: "\E022"; +} +.filetype.ged:before { + content: "\E023"; +} +.filetype.mp3:before { + content: "\E024"; +} +.filetype.m4a:before { + content: "\E025"; +} +.filetype.waw:before { + content: "\E026"; +} +.filetype.wma:before { + content: "\E027"; +} +.filetype.mpa:before { + content: "\E028"; +} +.filetype.iff:before { + content: "\E029"; +} +.filetype.aif:before { + content: "\E030"; +} +.filetype.ra:before { + content: "\E031"; +} +.filetype.mid:before { + content: "\E032"; +} +.filetype.m3v:before { + content: "\E033"; +} +.filetype.e_3gp:before { + content: "\E034"; +} +.filetype.shf:before { + content: "\E035"; +} +.filetype.avi:before { + content: "\E036"; +} +.filetype.asx:before { + content: "\E037"; +} +.filetype.mp4:before { + content: "\E038"; +} +.filetype.e_3g2:before { + content: "\E039"; +} +.filetype.mpg:before { + content: "\E040"; +} +.filetype.asf:before { + content: "\E041"; +} +.filetype.vob:before { + content: "\E042"; +} +.filetype.wmv:before { + content: "\E043"; +} +.filetype.mov:before { + content: "\E044"; +} +.filetype.srt:before { + content: "\E045"; +} +.filetype.m4v:before { + content: "\E046"; +} +.filetype.flv:before { + content: "\E047"; +} +.filetype.rm:before { + content: "\E048"; +} +.filetype.png:before { + content: "\E049"; +} +.filetype.psd:before { + content: "\E050"; +} +.filetype.psp:before { + content: "\E051"; +} +.filetype.jpg:before { + content: "\E052"; +} +.filetype.tif:before { + content: "\E053"; +} +.filetype.tiff:before { + content: "\E054"; +} +.filetype.gif:before { + content: "\E055"; +} +.filetype.bmp:before { + content: "\E056"; +} +.filetype.tga:before { + content: "\E057"; +} +.filetype.thm:before { + content: "\E058"; +} +.filetype.yuv:before { + content: "\E059"; +} +.filetype.dds:before { + content: "\E060"; +} +.filetype.ai:before { + content: "\E061"; +} +.filetype.eps:before { + content: "\E062"; +} +.filetype.ps:before { + content: "\E063"; +} +.filetype.svg:before { + content: "\E064"; +} +.filetype.pdf:before { + content: "\E065"; +} +.filetype.pct:before { + content: "\E066"; +} +.filetype.indd:before { + content: "\E067"; +} +.filetype.xlr:before { + content: "\E068"; +} +.filetype.xls:before { + content: "\E069"; +} +.filetype.xlsx:before { + content: "\E070"; +} +.filetype.db:before { + content: "\E071"; +} +.filetype.dbf:before { + content: "\E072"; +} +.filetype.mdb:before { + content: "\E073"; +} +.filetype.pdb:before { + content: "\E074"; +} +.filetype.sql:before { + content: "\E075"; +} +.filetype.aacd:before { + content: "\E076"; +} +.filetype.app:before { + content: "\E077"; +} +.filetype.exe:before { + content: "\E078"; +} +.filetype.com:before { + content: "\E079"; +} +.filetype.bat:before { + content: "\E080"; +} +.filetype.apk:before { + content: "\E081"; +} +.filetype.jar:before { + content: "\E082"; +} +.filetype.hsf:before { + content: "\E083"; +} +.filetype.pif:before { + content: "\E084"; +} +.filetype.vb:before { + content: "\E085"; +} +.filetype.cgi:before { + content: "\E086"; +} +.filetype.css:before { + content: "\E087"; +} +.filetype.js:before { + content: "\E088"; +} +.filetype.php:before { + content: "\E089"; +} +.filetype.xhtml:before { + content: "\E090"; +} +.filetype.htm:before { + content: "\E091"; +} +.filetype.html:before { + content: "\E092"; +} +.filetype.asp:before { + content: "\E093"; +} +.filetype.cer:before { + content: "\E094"; +} +.filetype.jsp:before { + content: "\E095"; +} +.filetype.cfm:before { + content: "\E096"; +} +.filetype.aspx:before { + content: "\E097"; +} +.filetype.rss:before { + content: "\E098"; +} +.filetype.csr:before { + content: "\E099"; +} +.filetype.less:before { + content: "\003C"; +} +.filetype.otf:before { + content: "\E101"; +} +.filetype.ttf:before { + content: "\E102"; +} +.filetype.font:before { + content: "\E103"; +} +.filetype.fnt:before { + content: "\E104"; +} +.filetype.eot:before { + content: "\E105"; +} +.filetype.woff:before { + content: "\E106"; +} +.filetype.zip:before { + content: "\E107"; +} +.filetype.zipx:before { + content: "\E108"; +} +.filetype.rar:before { + content: "\E109"; +} +.filetype.targ:before { + content: "\E110"; +} +.filetype.sitx:before { + content: "\E111"; +} +.filetype.deb:before { + content: "\E112"; +} +.filetype.e_7z:before { + content: "\E113"; +} +.filetype.pkg:before { + content: "\E114"; +} +.filetype.rpm:before { + content: "\E115"; +} +.filetype.cbr:before { + content: "\E116"; +} +.filetype.gz:before { + content: "\E117"; +} +.filetype.dmg:before { + content: "\E118"; +} +.filetype.cue:before { + content: "\E119"; +} +.filetype.bin:before { + content: "\E120"; +} +.filetype.iso:before { + content: "\E121"; +} +.filetype.hdf:before { + content: "\E122"; +} +.filetype.vcd:before { + content: "\E123"; +} +.filetype.bak:before { + content: "\E124"; +} +.filetype.tmp:before { + content: "\E125"; +} +.filetype.ics:before { + content: "\E126"; +} +.filetype.msi:before { + content: "\E127"; +} +.filetype.cfg:before { + content: "\E128"; +} +.filetype.ini:before { + content: "\E129"; +} +.filetype.prf:before { + content: "\E130"; +} +.filetype-icon { + display: inline-block; + width: 19px; + height: 24px; + margin: 0 8px 0 0; + line-height: 14px; + vertical-align: text-top; + background-position: 0 0; + background-repeat: no-repeat; + vertical-align: top; + *display: inline; + *zoom: 1; + *margin-right: .3em; +} +.filetype-icon _:-o-prefocus, +.filetype-icon.white _:-o-prefocus, +.filetype-icon.txt { + background-position: 0px 0px; +} +.filetype-icon.doc { + background-position: -48px 0px; +} +.filetype-icon.rtf { + background-position: -96px 0px; +} +.filetype-icon.log { + background-position: -144px 0px; +} +.filetype-icon.tex { + background-position: -192px 0px; +} +.filetype-icon.msg { + background-position: -240px 0px; +} +.filetype-icon.text { + background-position: -288px 0px; +} +.filetype-icon.wpd { + background-position: -336px 0px; +} +.filetype-icon.wps { + background-position: -384px 0px; +} +.filetype-icon.docx { + background-position: -432px 0px; +} +.filetype-icon.page { + background-position: 0px -48px; +} +.filetype-icon.csv { + background-position: -48px -48px; +} +.filetype-icon.dat { + background-position: -96px -48px; +} +.filetype-icon.tar { + background-position: -144px -48px; +} +.filetype-icon.xml { + background-position: -192px -48px; +} +.filetype-icon.vcf { + background-position: -240px -48px; +} +.filetype-icon.pps { + background-position: -288px -48px; +} +.filetype-icon.key { + background-position: -336px -48px; +} +.filetype-icon.ppt { + background-position: -384px -48px; +} +.filetype-icon.pptx { + background-position: -432px -48px; +} +.filetype-icon.sdf { + background-position: 0px -96px; +} +.filetype-icon.gbr { + background-position: -48px -96px; +} +.filetype-icon.ged { + background-position: -96px -96px; +} +.filetype-icon.mp3 { + background-position: -144px -96px; +} +.filetype-icon.m4a { + background-position: -192px -96px; +} +.filetype-icon.waw { + background-position: -240px -96px; +} +.filetype-icon.wma { + background-position: -288px -96px; +} +.filetype-icon.mpa { + background-position: -336px -96px; +} +.filetype-icon.iff { + background-position: -384px -96px; +} +.filetype-icon.aif { + background-position: -432px -96px; +} +.filetype-icon.ra { + background-position: 0px -144px; +} +.filetype-icon.mid { + background-position: -48px -144px; +} +.filetype-icon.m3v { + background-position: -96px -144px; +} +.filetype-icon.e_3gp { + background-position: -144px -144px; +} +.filetype-icon.shf { + background-position: -192px -144px; +} +.filetype-icon.avi { + background-position: -240px -144px; +} +.filetype-icon.asx { + background-position: -288px -144px; +} +.filetype-icon.mp4 { + background-position: -336px -144px; +} +.filetype-icon.e_3g2 { + background-position: -384px -144px; +} +.filetype-icon.mpg { + background-position: -432px -144px; +} +.filetype-icon.asf { + background-position: 0px -192px; +} +.filetype-icon.vob { + background-position: -48px -192px; +} +.filetype-icon.wmv { + background-position: -96px -192px; +} +.filetype-icon.mov { + background-position: -144px -192px; +} +.filetype-icon.srt { + background-position: -192px -192px; +} +.filetype-icon.m4v { + background-position: -240px -192px; +} +.filetype-icon.flv { + background-position: -288px -192px; +} +.filetype-icon.rm { + background-position: -336px -192px; +} +.filetype-icon.png { + background-position: -384px -192px; +} +.filetype-icon.psd { + background-position: -432px -192px; +} +.filetype-icon.psp { + background-position: 0px -240px; +} +.filetype-icon.jpg { + background-position: -48px -240px; +} +.filetype-icon.tif { + background-position: -96px -240px; +} +.filetype-icon.tiff { + background-position: -144px -240px; +} +.filetype-icon.gif { + background-position: -192px -240px; +} +.filetype-icon.bmp { + background-position: -240px -240px; +} +.filetype-icon.tga { + background-position: -288px -240px; +} +.filetype-icon.thm { + background-position: -336px -240px; +} +.filetype-icon.yuv { + background-position: -384px -240px; +} +.filetype-icon.dds { + background-position: -432px -240px; +} +.filetype-icon.ai { + background-position: 0px -288px; +} +.filetype-icon.eps { + background-position: -48px -288px; +} +.filetype-icon.ps { + background-position: -96px -288px; +} +.filetype-icon.svg { + background-position: -144px -288px; +} +.filetype-icon.pdf { + background-position: -192px -288px; +} +.filetype-icon.pct { + background-position: -240px -288px; +} +.filetype-icon.indd { + background-position: -288px -288px; +} +.filetype-icon.xlr { + background-position: -336px -288px; +} +.filetype-icon.xls { + background-position: -384px -288px; +} +.filetype-icon.xlsx { + background-position: -432px -288px; +} +.filetype-icon.db { + background-position: 0px -336px; +} +.filetype-icon.dbf { + background-position: -48px -336px; +} +.filetype-icon.mdb { + background-position: -96px -336px; +} +.filetype-icon.pdb { + background-position: -144px -336px; +} +.filetype-icon.sql { + background-position: -192px -336px; +} +.filetype-icon.aacd { + background-position: -240px -336px; +} +.filetype-icon.app { + background-position: -288px -336px; +} +.filetype-icon.exe { + background-position: -336px -336px; +} +.filetype-icon.com { + background-position: -384px -336px; +} +.filetype-icon.bat { + background-position: -432px -336px; +} +.filetype-icon.apk { + background-position: 0px -384px; +} +.filetype-icon.jar { + background-position: -48px -384px; +} +.filetype-icon.hsf { + background-position: -96px -384px; +} +.filetype-icon.pif { + background-position: -144px -384px; +} +.filetype-icon.vb { + background-position: -192px -384px; +} +.filetype-icon.cgi { + background-position: -240px -384px; +} +.filetype-icon.css { + background-position: -288px -384px; +} +.filetype-icon.js { + background-position: -336px -384px; +} +.filetype-icon.php { + background-position: -384px -384px; +} +.filetype-icon.xhtml { + background-position: -432px -384px; +} +.filetype-icon.htm { + background-position: 0px -432px; +} +.filetype-icon.html { + background-position: -48px -432px; +} +.filetype-icon.asp { + background-position: -96px -432px; +} +.filetype-icon.cer { + background-position: -144px -432px; +} +.filetype-icon.jsp { + background-position: -192px -432px; +} +.filetype-icon.cfm { + background-position: -240px -432px; +} +.filetype-icon.aspx { + background-position: -288px -432px; +} +.filetype-icon.rss { + background-position: -336px -432px; +} +.filetype-icon.csr { + background-position: -384px -432px; +} +.filetype-icon.less { + background-position: -432px -432px; +} +.filetype-icon.otf { + background-position: 0px -480px; +} +.filetype-icon.ttf { + background-position: -48px -480px; +} +.filetype-icon.font { + background-position: -96px -480px; +} +.filetype-icon.fnt { + background-position: -144px -480px; +} +.filetype-icon.eot { + background-position: -192px -480px; +} +.filetype-icon.woff { + background-position: -240px -480px; +} +.filetype-icon.zip { + background-position: -288px -480px; +} +.filetype-icon.zipx { + background-position: -336px -480px; +} +.filetype-icon.rar { + background-position: -384px -480px; +} +.filetype-icon.targ { + background-position: -432px -480px; +} +.filetype-icon.sitx { + background-position: 0px -528px; +} +.filetype-icon.deb { + background-position: -48px -528px; +} +.filetype-icon.e_7z { + background-position: -96px -528px; +} +.filetype-icon.pkg { + background-position: -144px -528px; +} +.filetype-icon.rpm { + background-position: -192px -528px; +} +.filetype-icon.cbr { + background-position: -240px -528px; +} +.filetype-icon.gz { + background-position: -288px -528px; +} +.filetype-icon.dmg { + background-position: -336px -528px; +} +.filetype-icon.cue { + background-position: -384px -528px; +} +.filetype-icon.bin { + background-position: -432px -528px; +} +.filetype-icon.iso { + background-position: 0px -576px; +} +.filetype-icon.hdf { + background-position: -48px -576px; +} +.filetype-icon.vcd { + background-position: -96px -576px; +} +.filetype-icon.bak { + background-position: -144px -576px; +} +.filetype-icon.tmp { + background-position: -192px -576px; +} +.filetype-icon.ics { + background-position: -240px -576px; +} +.filetype-icon.msi { + background-position: -288px -576px; +} +.filetype-icon.cfg { + background-position: -336px -576px; +} +.filetype-icon.ini { + background-position: -384px -576px; +} +.filetype-icon.prf { + background-position: -432px -576px; +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome-ie7.css b/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome-ie7.css new file mode 100644 index 0000000..17f0776 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome-ie7.css @@ -0,0 +1,1203 @@ +/*! + * Font Awesome 3.2.1 + * the iconic font designed for Bootstrap + * ------------------------------------------------------------------------------ + * The full suite of pictographic icons, examples, and documentation can be + * found at http://fontawesome.io. Stay up to date on Twitter at + * http://twitter.com/fontawesome. + * + * License + * ------------------------------------------------------------------------------ + * - The Font Awesome font is licensed under SIL OFL 1.1 - + * http://scripts.sil.org/OFL + * - Font Awesome CSS, LESS, and SASS files are licensed under MIT License - + * http://opensource.org/licenses/mit-license.html + * - Font Awesome documentation licensed under CC BY 3.0 - + * http://creativecommons.org/licenses/by/3.0/ + * - Attribution is no longer required in Font Awesome 3.0, but much appreciated: + * "Font Awesome by Dave Gandy - http://fontawesome.io" + * + * Author - Dave Gandy + * ------------------------------------------------------------------------------ + * Email: dave@fontawesome.io + * Twitter: http://twitter.com/davegandy + * Work: Lead Product Designer @ Kyruus - http://kyruus.com + */ +.icon-large { + font-size: 1.3333333333333333em; + margin-top: -4px; + padding-top: 3px; + margin-bottom: -4px; + padding-bottom: 3px; + vertical-align: middle; +} +.nav [class^="icon-"], +.nav [class*=" icon-"] { + vertical-align: inherit; + margin-top: -4px; + padding-top: 3px; + margin-bottom: -4px; + padding-bottom: 3px; +} +.nav [class^="icon-"].icon-large, +.nav [class*=" icon-"].icon-large { + vertical-align: -25%; +} +.nav-pills [class^="icon-"].icon-large, +.nav-tabs [class^="icon-"].icon-large, +.nav-pills [class*=" icon-"].icon-large, +.nav-tabs [class*=" icon-"].icon-large { + line-height: .75em; + margin-top: -7px; + padding-top: 5px; + margin-bottom: -5px; + padding-bottom: 4px; +} +.btn [class^="icon-"].pull-left, +.btn [class*=" icon-"].pull-left, +.btn [class^="icon-"].pull-right, +.btn [class*=" icon-"].pull-right { + vertical-align: inherit; +} +.btn [class^="icon-"].icon-large, +.btn [class*=" icon-"].icon-large { + margin-top: -0.5em; +} +a [class^="icon-"], +a [class*=" icon-"] { + cursor: pointer; +} +.icon-glass { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-music { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-search { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-envelope-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-heart { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-star { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-star-empty { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-user { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-film { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-th-large { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-th { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-th-list { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-ok { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-remove { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-zoom-in { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-zoom-out { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-off { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-power-off { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-signal { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-cog { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-gear { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-trash { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-home { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-file-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-time { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-road { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-download-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-download { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-upload { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-inbox { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-play-circle { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-repeat { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-rotate-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-refresh { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-list-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-lock { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-flag { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-headphones { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-volume-off { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-volume-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-volume-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-qrcode { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-barcode { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-tag { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-tags { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-book { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bookmark { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-print { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-camera { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-font { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bold { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-italic { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-text-height { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-text-width { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-align-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-align-center { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-align-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-align-justify { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-list { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-indent-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-indent-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-facetime-video { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-picture { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-pencil { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-map-marker { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-adjust { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-tint { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-edit { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-share { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-check { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-move { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-step-backward { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-fast-backward { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-backward { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-play { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-pause { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-stop { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-forward { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-fast-forward { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-step-forward { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-eject { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-chevron-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-chevron-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-plus-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-minus-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-remove-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-ok-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-question-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-info-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-screenshot { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-remove-circle { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-ok-circle { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-ban-circle { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-arrow-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-arrow-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-arrow-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-arrow-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-share-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-mail-forward { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-resize-full { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-resize-small { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-plus { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-minus { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-asterisk { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-exclamation-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-gift { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-leaf { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-fire { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-eye-open { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-eye-close { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-warning-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-plane { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-calendar { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-random { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-comment { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-magnet { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-chevron-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-chevron-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-retweet { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-shopping-cart { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-folder-close { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-folder-open { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-resize-vertical { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-resize-horizontal { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bar-chart { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-twitter-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-facebook-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-camera-retro { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-key { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-cogs { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-gears { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-comments { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-thumbs-up-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-thumbs-down-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-star-half { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-heart-empty { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-signout { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-linkedin-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-pushpin { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-external-link { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-signin { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-trophy { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-github-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-upload-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-lemon { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-phone { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-check-empty { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-unchecked { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bookmark-empty { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-phone-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-twitter { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-facebook { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-github { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-unlock { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-credit-card { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-rss { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-hdd { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bullhorn { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bell { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-certificate { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-hand-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-hand-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-hand-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-hand-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-circle-arrow-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-circle-arrow-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-circle-arrow-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-circle-arrow-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-globe { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-wrench { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-tasks { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-filter { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-briefcase { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-fullscreen { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-group { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-link { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-cloud { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-beaker { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-cut { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-copy { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-paper-clip { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-paperclip { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-save { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sign-blank { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-reorder { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-list-ul { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-list-ol { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-strikethrough { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-underline { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-table { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-magic { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-truck { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-pinterest { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-pinterest-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-google-plus-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-google-plus { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-money { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-caret-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-caret-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-caret-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-caret-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-columns { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sort { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sort-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sort-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-envelope { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-linkedin { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-undo { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-rotate-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-legal { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-dashboard { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-comment-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-comments-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bolt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sitemap { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-umbrella { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-paste { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-lightbulb { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-exchange { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-cloud-download { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-cloud-upload { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-user-md { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-stethoscope { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-suitcase { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bell-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-coffee { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-food { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-file-text-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-building { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-hospital { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-ambulance { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-medkit { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-fighter-jet { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-beer { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-h-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-plus-sign-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-double-angle-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-double-angle-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-double-angle-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-double-angle-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-angle-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-angle-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-angle-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-angle-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-desktop { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-laptop { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-tablet { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-mobile-phone { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-circle-blank { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-quote-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-quote-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-spinner { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-circle { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-reply { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-mail-reply { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-github-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-folder-close-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-folder-open-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-expand-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-collapse-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-smile { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-frown { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-meh { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-gamepad { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-keyboard { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-flag-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-flag-checkered { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-terminal { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-code { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-reply-all { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-mail-reply-all { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-star-half-empty { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-star-half-full { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-location-arrow { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-crop { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-code-fork { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-unlink { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-question { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-info { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-exclamation { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-superscript { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-subscript { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-eraser { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-puzzle-piece { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-microphone { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-microphone-off { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-shield { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-calendar-empty { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-fire-extinguisher { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-rocket { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-maxcdn { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-chevron-sign-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-chevron-sign-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-chevron-sign-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-chevron-sign-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-html5 { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-css3 { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-anchor { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-unlock-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bullseye { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-ellipsis-horizontal { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-ellipsis-vertical { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-rss-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-play-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-ticket { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-minus-sign-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-check-minus { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-level-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-level-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-check-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-edit-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-external-link-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-share-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-compass { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-collapse { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-collapse-top { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-expand { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-eur { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-euro { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-gbp { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-usd { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-dollar { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-inr { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-rupee { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-jpy { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-yen { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-cny { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-renminbi { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-krw { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-won { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-btc { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bitcoin { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-file { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-file-text { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sort-by-alphabet { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sort-by-alphabet-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sort-by-attributes { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sort-by-attributes-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sort-by-order { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sort-by-order-alt { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-thumbs-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-thumbs-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-youtube-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-youtube { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-xing { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-xing-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-youtube-play { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-dropbox { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-stackexchange { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-instagram { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-flickr { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-adn { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bitbucket { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bitbucket-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-tumblr { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-tumblr-sign { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-long-arrow-down { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-long-arrow-up { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-long-arrow-left { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-long-arrow-right { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-apple { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-windows { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-android { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-linux { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-dribbble { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-skype { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-foursquare { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-trello { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-female { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-male { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-gittip { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-sun { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-moon { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-archive { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-bug { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-vk { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-weibo { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} +.icon-renren { + *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ''); +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome-ie7.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome-ie7.min.css new file mode 100644 index 0000000..d3dae63 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome-ie7.min.css @@ -0,0 +1,384 @@ +.icon-large{font-size:1.3333333333333333em;margin-top:-4px;padding-top:3px;margin-bottom:-4px;padding-bottom:3px;vertical-align:middle;} +.nav [class^="icon-"],.nav [class*=" icon-"]{vertical-align:inherit;margin-top:-4px;padding-top:3px;margin-bottom:-4px;padding-bottom:3px;}.nav [class^="icon-"].icon-large,.nav [class*=" icon-"].icon-large{vertical-align:-25%;} +.nav-pills [class^="icon-"].icon-large,.nav-tabs [class^="icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large{line-height:.75em;margin-top:-7px;padding-top:5px;margin-bottom:-5px;padding-bottom:4px;} +.btn [class^="icon-"].pull-left,.btn [class*=" icon-"].pull-left,.btn [class^="icon-"].pull-right,.btn [class*=" icon-"].pull-right{vertical-align:inherit;} +.btn [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large{margin-top:-0.5em;} +a [class^="icon-"],a [class*=" icon-"]{cursor:pointer;} +.icon-glass{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-music{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-search{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-envelope-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-heart{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-user{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-film{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-th-large{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-th{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-th-list{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ok{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-remove{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-zoom-in{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-zoom-out{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-off{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-power-off{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-signal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cog{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gear{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-trash{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-home{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-file-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-time{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-road{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-download-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-download{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-upload{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-inbox{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-play-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-repeat{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rotate-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-refresh{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-list-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-lock{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-flag{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-headphones{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-volume-off{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-volume-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-volume-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-qrcode{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-barcode{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tag{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tags{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-book{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bookmark{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-print{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-camera{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-font{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bold{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-italic{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-text-height{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-text-width{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-align-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-align-center{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-align-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-align-justify{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-list{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-indent-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-indent-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-facetime-video{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-picture{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pencil{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-map-marker{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-adjust{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tint{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-edit{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-share{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-check{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-move{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-step-backward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fast-backward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-backward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-play{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pause{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-stop{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-forward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fast-forward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-step-forward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eject{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-plus-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-minus-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-remove-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ok-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-question-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-info-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-screenshot{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-remove-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ok-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ban-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-arrow-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-arrow-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-arrow-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-arrow-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-share-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-mail-forward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-resize-full{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-resize-small{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-plus{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-minus{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-asterisk{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-exclamation-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gift{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-leaf{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fire{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eye-open{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eye-close{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-warning-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-plane{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-calendar{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-random{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-comment{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-magnet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-retweet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-shopping-cart{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-folder-close{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-folder-open{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-resize-vertical{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-resize-horizontal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bar-chart{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-twitter-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-facebook-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-camera-retro{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-key{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cogs{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gears{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-comments{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-thumbs-up-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-thumbs-down-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star-half{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-heart-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-signout{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-linkedin-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pushpin{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-external-link{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-signin{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-trophy{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-github-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-upload-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-lemon{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-phone{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-check-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-unchecked{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bookmark-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-phone-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-twitter{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-facebook{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-github{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-unlock{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-credit-card{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rss{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hdd{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bullhorn{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bell{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-certificate{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hand-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hand-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hand-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hand-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-arrow-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-arrow-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-arrow-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-arrow-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-globe{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-wrench{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tasks{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-filter{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-briefcase{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fullscreen{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-group{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-link{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cloud{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-beaker{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cut{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-copy{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-paper-clip{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-paperclip{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-save{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sign-blank{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-reorder{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-list-ul{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-list-ol{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-strikethrough{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-underline{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-table{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-magic{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-truck{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pinterest{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pinterest-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-google-plus-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-google-plus{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-money{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-caret-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-caret-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-caret-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-caret-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-columns{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-envelope{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-linkedin{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-undo{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rotate-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-legal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-dashboard{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-comment-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-comments-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bolt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sitemap{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-umbrella{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-paste{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-lightbulb{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-exchange{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cloud-download{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cloud-upload{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-user-md{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-stethoscope{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-suitcase{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bell-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-coffee{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-food{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-file-text-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-building{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hospital{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ambulance{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-medkit{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fighter-jet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-beer{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-h-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-plus-sign-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-double-angle-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-double-angle-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-double-angle-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-double-angle-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-angle-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-angle-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-angle-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-angle-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-desktop{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-laptop{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tablet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-mobile-phone{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-blank{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-quote-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-quote-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-spinner{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-reply{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-mail-reply{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-github-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-folder-close-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-folder-open-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-expand-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-collapse-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-smile{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-frown{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-meh{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gamepad{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-keyboard{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-flag-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-flag-checkered{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-terminal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-code{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-reply-all{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-mail-reply-all{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star-half-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star-half-full{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-location-arrow{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-crop{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-code-fork{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-unlink{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-question{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-info{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-exclamation{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-superscript{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-subscript{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eraser{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-puzzle-piece{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-microphone{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-microphone-off{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-shield{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-calendar-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fire-extinguisher{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rocket{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-maxcdn{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-sign-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-sign-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-sign-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-sign-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-html5{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-css3{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-anchor{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-unlock-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bullseye{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ellipsis-horizontal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ellipsis-vertical{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rss-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-play-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ticket{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-minus-sign-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-check-minus{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-level-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-level-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-check-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-edit-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-external-link-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-share-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-compass{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-collapse{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-collapse-top{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-expand{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eur{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-euro{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gbp{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-usd{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-dollar{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-inr{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rupee{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-jpy{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-yen{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cny{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-renminbi{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-krw{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-won{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-btc{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bitcoin{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-file{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-file-text{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-alphabet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-alphabet-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-attributes{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-attributes-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-order{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-order-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-thumbs-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-thumbs-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-youtube-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-youtube{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-xing{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-xing-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-youtube-play{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-dropbox{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-stackexchange{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-instagram{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-flickr{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-adn{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bitbucket{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bitbucket-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tumblr{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tumblr-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-long-arrow-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-long-arrow-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-long-arrow-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-long-arrow-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-apple{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-windows{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-android{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-linux{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-dribbble{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-skype{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-foursquare{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-trello{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-female{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-male{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gittip{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sun{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-moon{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-archive{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bug{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-vk{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-weibo{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-renren{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome.css b/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome.css new file mode 100644 index 0000000..048cff9 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome.css @@ -0,0 +1,1338 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.0.3'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.3333333333333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.2857142857142858em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.142857142857143em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.142857142857143em; + width: 2.142857142857143em; + top: 0.14285714285714285em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.8571428571428572em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@-ms-keyframes spin { + 0% { + -ms-transform: rotate(0deg); + } + 100% { + -ms-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-asc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-desc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-reply-all:before { + content: "\f122"; +} +.fa-mail-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome.min.css new file mode 100644 index 0000000..449d6ac --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.0.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857142858em;text-align:center}.fa-ul{padding-left:0;margin-left:2.142857142857143em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;top:.14285714285714285em;text-align:center}.fa-li.fa-lg{left:-1.8571428571428572em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0,mirror=1);-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1);-ms-transform:scale(-1,1);-o-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2,mirror=1);-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-asc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-desc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-reply-all:before{content:"\f122"}.fa-mail-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/fullcalendar.css b/gridplatform/bootstrap/static/bootstrap/genius/css/fullcalendar.css new file mode 100755 index 0000000..5b8c56b --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/fullcalendar.css @@ -0,0 +1,582 @@ +/*! + * FullCalendar v1.6.1 Stylesheet + * Docs & License: http://arshaw.com/fullcalendar/ + * (c) 2013 Adam Shaw + */ + + +.fc { + direction: ltr; + text-align: left; + font-weight: normal !important; + } + +.fc table { + border-collapse: collapse; + border-spacing: 0; + } + +html .fc, +.fc table { + font-size: 1em; + } + +.fc td, +.fc th { + padding: 0; + vertical-align: top; + font-weight: normal; +} + + + +/* Header +------------------------------------------------------------------------*/ + +.fc-header td { + white-space: nowrap; + } + +.fc-header-left { + width: 25%; + text-align: left; + } + +.fc-header-center { + text-align: center; + } + +.fc-header-right { + width: 25%; + text-align: right; + } + +.fc-header-title { + display: inline-block; + vertical-align: top; + } + +.fc-header-title h2 { + margin-top: 0; + white-space: nowrap; + } + +.fc .fc-header-space { + padding-left: 10px; + } + +.fc-header .fc-button { + margin-bottom: 1em; + vertical-align: top; + } + +/* buttons edges butting together */ + +.fc-header .fc-button { + margin-right: -1px; + } + +.fc-header .fc-corner-right, /* non-theme */ +.fc-header .ui-corner-right { /* theme */ + margin-right: 0; /* back to normal */ + } + +/* button layering (for border precedence) */ + +.fc-header .fc-state-hover, +.fc-header .ui-state-hover { + z-index: 2; + } + +.fc-header .fc-state-down { + z-index: 3; + } + +.fc-header .fc-state-active, +.fc-header .ui-state-active { + z-index: 4; + } + + + +/* Content +------------------------------------------------------------------------*/ + +.fc-content { + clear: both; + } + +.fc-view { + width: 100%; /* needed for view switching (when view is absolute) */ + overflow: hidden; + } + + + +/* Cell Styles +------------------------------------------------------------------------*/ + +.fc-widget-header, /*
";if(this.o.calendarWeeks){var n='';t+=n;this.picker.find(".datepicker-days thead tr:first-child").prepend(n)}while(e'+c[this.o.language].daysMin[e++%7]+"";t+="";this.picker.find(".datepicker-days thead").append(t)},fillMonths:function(){var e="",t=0;while(t<12)e+=''+c[this.o.language].monthsShort[t++]+"";this.picker.find(".datepicker-months td").html(e)},setRange:function(t){!t||!t.length?delete this.range:this.range=e.map(t,function(e){return e.valueOf()});this.fill()},getClassNames:function(t){var n=[],r=this.viewDate.getUTCFullYear(),i=this.viewDate.getUTCMonth(),s=this.date.valueOf(),o=new Date;t.getUTCFullYear()r||t.getUTCFullYear()==r&&t.getUTCMonth()>i)&&n.push("new");this.o.todayHighlight&&t.getUTCFullYear()==o.getFullYear()&&t.getUTCMonth()==o.getMonth()&&t.getUTCDate()==o.getDate()&&n.push("today");s&&t.valueOf()==s&&n.push("active");(t.valueOf()this.o.endDate||e.inArray(t.getUTCDay(),this.o.daysOfWeekDisabled)!==-1)&&n.push("disabled");if(this.range){t>this.range[0]&&t");if(this.o.calendarWeeks){var y=new Date(+p+(this.o.weekStart-p.getUTCDay()-7)%7*864e5),b=new Date(+y+(11-y.getUTCDay())%7*864e5),w=new Date(+(w=n(b.getUTCFullYear(),0,1))+(11-w.getUTCDay())%7*864e5),E=(b-w)/864e5/7+1;m.push('")}}g=this.getClassNames(p);g.push("day");if(this.o.beforeShowDay!==e.noop){var S=this.o.beforeShowDay(this._utc_to_local(p));S===undefined?S={}:typeof S=="boolean"?S={enabled:S}:typeof S=="string"&&(S={classes:S});S.enabled===!1&&g.push("disabled");S.classes&&(g=g.concat(S.classes.split(/\s+/)));S.tooltip&&(l=S.tooltip)}g=e.unique(g);m.push('");p.getUTCDay()==this.o.weekEnd&&m.push("");p.setUTCDate(p.getUTCDate()+1)}this.picker.find(".datepicker-days tbody").empty().append(m.join(""));var x=this.date&&this.date.getUTCFullYear(),T=this.picker.find(".datepicker-months").find("th:eq(1)").text(r).end().find("span").removeClass("active");x&&x==r&&T.eq(this.date.getUTCMonth()).addClass("active");(ru)&&T.addClass("disabled");r==s&&T.slice(0,o).addClass("disabled");r==u&&T.slice(a+1).addClass("disabled");m="";r=parseInt(r/10,10)*10;var N=this.picker.find(".datepicker-years").find("th:eq(1)").text(r+"-"+(r+9)).end().find("td");r-=1;for(var C=-1;C<11;C++){m+='u?" disabled":"")+'">'+r+"";r+=1}N.html(m)},updateNavArrows:function(){if(!this._allow_update)return;var e=new Date(this.viewDate),t=e.getUTCFullYear(),n=e.getUTCMonth();switch(this.viewMode){case 0:this.o.startDate!==-Infinity&&t<=this.o.startDate.getUTCFullYear()&&n<=this.o.startDate.getUTCMonth()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"});this.o.endDate!==Infinity&&t>=this.o.endDate.getUTCFullYear()&&n>=this.o.endDate.getUTCMonth()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 1:case 2:this.o.startDate!==-Infinity&&t<=this.o.startDate.getUTCFullYear()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"});this.o.endDate!==Infinity&&t>=this.o.endDate.getUTCFullYear()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"})}},click:function(t){t.preventDefault();var r=e(t.target).closest("span, td, th");if(r.length==1)switch(r[0].nodeName.toLowerCase()){case"th":switch(r[0].className){case"datepicker-switch":this.showMode(1);break;case"prev":case"next":var i=h.modes[this.viewMode].navStep*(r[0].className=="prev"?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveMonth(this.viewDate,i);this._trigger("changeMonth",this.viewDate);break;case 1:case 2:this.viewDate=this.moveYear(this.viewDate,i);this.viewMode===1&&this._trigger("changeYear",this.viewDate)}this.fill();break;case"today":var s=new Date;s=n(s.getFullYear(),s.getMonth(),s.getDate(),0,0,0);this.showMode(-2);var o=this.o.todayBtn=="linked"?null:"view";this._setDate(s,o);break;case"clear":var u;this.isInput?u=this.element:this.component&&(u=this.element.find("input"));u&&u.val("").change();this._trigger("changeDate");this.update();this.o.autoclose&&this.hide()}break;case"span":if(!r.is(".disabled")){this.viewDate.setUTCDate(1);if(r.is(".month")){var a=1,f=r.parent().find("span").index(r),l=this.viewDate.getUTCFullYear();this.viewDate.setUTCMonth(f);this._trigger("changeMonth",this.viewDate);this.o.minViewMode===1&&this._setDate(n(l,f,a,0,0,0,0))}else{var l=parseInt(r.text(),10)||0,a=1,f=0;this.viewDate.setUTCFullYear(l);this._trigger("changeYear",this.viewDate);this.o.minViewMode===2&&this._setDate(n(l,f,a,0,0,0,0))}this.showMode(-1);this.fill()}break;case"td":if(r.is(".day")&&!r.is(".disabled")){var a=parseInt(r.text(),10)||1,l=this.viewDate.getUTCFullYear(),f=this.viewDate.getUTCMonth();if(r.is(".old"))if(f===0){f=11;l-=1}else f-=1;else if(r.is(".new"))if(f==11){f=0;l+=1}else f+=1;this._setDate(n(l,f,a,0,0,0,0))}}},_setDate:function(e,t){if(!t||t=="date")this.date=new Date(e);if(!t||t=="view")this.viewDate=new Date(e);this.fill();this.setValue();this._trigger("changeDate");var n;this.isInput?n=this.element:this.component&&(n=this.element.find("input"));n&&n.change();this.o.autoclose&&(!t||t=="date")&&this.hide()},moveMonth:function(e,t){if(!t)return e;var n=new Date(e.valueOf()),r=n.getUTCDate(),i=n.getUTCMonth(),s=Math.abs(t),o,u;t=t>0?1:-1;if(s==1){u=t==-1?function(){return n.getUTCMonth()==i}:function(){return n.getUTCMonth()!=o};o=i+t;n.setUTCMonth(o);if(o<0||o>11)o=(o+12)%12}else{for(var a=0;a=this.o.startDate&&e<=this.o.endDate},keydown:function(e){if(this.picker.is(":not(:visible)")){e.keyCode==27&&this.show();return}var t=!1,n,r,i,s,o;switch(e.keyCode){case 27:this.hide();e.preventDefault();break;case 37:case 39:if(!this.o.keyboardNavigation)break;n=e.keyCode==37?-1:1;if(e.ctrlKey){s=this.moveYear(this.date,n);o=this.moveYear(this.viewDate,n);this._trigger("changeYear",this.viewDate)}else if(e.shiftKey){s=this.moveMonth(this.date,n);o=this.moveMonth(this.viewDate,n);this._trigger("changeMonth",this.viewDate)}else{s=new Date(this.date);s.setUTCDate(this.date.getUTCDate()+n);o=new Date(this.viewDate);o.setUTCDate(this.viewDate.getUTCDate()+n)}if(this.dateWithinRange(s)){this.date=s;this.viewDate=o;this.setValue();this.update();e.preventDefault();t=!0}break;case 38:case 40:if(!this.o.keyboardNavigation)break;n=e.keyCode==38?-1:1;if(e.ctrlKey){s=this.moveYear(this.date,n);o=this.moveYear(this.viewDate,n);this._trigger("changeYear",this.viewDate)}else if(e.shiftKey){s=this.moveMonth(this.date,n);o=this.moveMonth(this.viewDate,n);this._trigger("changeMonth",this.viewDate)}else{s=new Date(this.date);s.setUTCDate(this.date.getUTCDate()+n*7);o=new Date(this.viewDate);o.setUTCDate(this.viewDate.getUTCDate()+n*7)}if(this.dateWithinRange(s)){this.date=s;this.viewDate=o;this.setValue();this.update();e.preventDefault();t=!0}break;case 13:this.hide();e.preventDefault();break;case 9:this.hide()}if(t){this._trigger("changeDate");var u;this.isInput?u=this.element:this.component&&(u=this.element.find("input"));u&&u.change()}},showMode:function(e){e&&(this.viewMode=Math.max(this.o.minViewMode,Math.min(2,this.viewMode+e)));this.picker.find(">div").hide().filter(".datepicker-"+h.modes[this.viewMode].clsName).css("display","block");this.updateNavArrows()}};var s=function(t,n){this.element=e(t);this.inputs=e.map(n.inputs,function(e){return e.jquery?e[0]:e});delete n.inputs;e(this.inputs).datepicker(n).bind("changeDate",e.proxy(this.dateUpdated,this));this.pickers=e.map(this.inputs,function(t){return e(t).data("datepicker")});this.updateDates()};s.prototype={updateDates:function(){this.dates=e.map(this.pickers,function(e){return e.date});this.updateRanges()},updateRanges:function(){var t=e.map(this.dates,function(e){return e.valueOf()});e.each(this.pickers,function(e,n){n.setRange(t)})},dateUpdated:function(t){var n=e(t.target).data("datepicker"),r=n.getUTCDate(),i=e.inArray(t.target,this.inputs),s=this.inputs.length;if(i==-1)return;if(r=0&&rthis.dates[i])while(ithis.dates[i])this.pickers[i++].setUTCDate(r);this.updateDates()},remove:function(){e.map(this.pickers,function(e){e.remove()});delete this.element.data().datepicker}};var a=e.fn.datepicker;e.fn.datepicker=function(t){var n=Array.apply(null,arguments);n.shift();var r,a;this.each(function(){var a=e(this),l=a.data("datepicker"),c=typeof t=="object"&&t;if(!l){var h=o(this,"date"),p=e.extend({},f,h,c),d=u(p.language),v=e.extend({},f,d,h,c);if(a.is(".input-daterange")||v.inputs){var m={inputs:v.inputs||a.find("input").toArray()};a.data("datepicker",l=new s(this,e.extend(v,m)))}else a.data("datepicker",l=new i(this,v))}if(typeof t=="string"&&typeof l[t]=="function"){r=l[t].apply(l,n);if(r!==undefined)return!1}});return r!==undefined?r:this};var f=e.fn.datepicker.defaults={autoclose:!1,beforeShowDay:e.noop,calendarWeeks:!1,clearBtn:!1,daysOfWeekDisabled:[],endDate:Infinity,forceParse:!0,format:"mm/dd/yyyy",keyboardNavigation:!0,language:"en",minViewMode:0,orientation:"auto",rtl:!1,startDate:-Infinity,startView:0,todayBtn:!1,todayHighlight:!1,weekStart:0},l=e.fn.datepicker.locale_opts=["format","rtl","weekStart"];e.fn.datepicker.Constructor=i;var c=e.fn.datepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",clear:"Clear"}},h={modes:[{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(e){return e%4===0&&e%100!==0||e%400===0},getDaysInMonth:function(e,t){return[31,h.isLeapYear(e)?29:28,31,30,31,30,31,31,30,31,30,31][t]},validParts:/dd?|DD?|mm?|MM?|yy(?:yy)?/g,nonpunctuation:/[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,parseFormat:function(e){var t=e.replace(this.validParts,"\0").split("\0"),n=e.match(this.validParts);if(!t||!t.length||!n||n.length===0)throw new Error("Invalid date format.");return{separators:t,parts:n}},parseDate:function(t,r,s){if(t instanceof Date)return t;typeof r=="string"&&(r=h.parseFormat(r));if(/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(t)){var o=/([\-+]\d+)([dmwy])/,u=t.match(/([\-+]\d+)([dmwy])/g),a,f;t=new Date;for(var l=0;l',contTemplate:'',footTemplate:''};h.template='
 '+(serie.label || String.fromCharCode(65+i))+'
, usually */ +.fc-widget-content { /* , usually */ + border: 1px solid #ddd; +} + +.fc-state-highlight { /* today cell */ /* TODO: add .fc-today to */ + background: #fcf8e3; + } + +.fc-cell-overlay { /* semi-transparent rectangle while dragging */ + background: #bce8f1; + opacity: .3; + filter: alpha(opacity=30); /* for IE */ +} + + + +/* Buttons +------------------------------------------------------------------------*/ + +.fc-button { + position: relative; + display: inline-block; + padding: 0 .6em; + overflow: hidden; + height: 1.9em; + line-height: 1.9em; + white-space: nowrap; + cursor: pointer; + } + +.fc-state-default { /* non-theme */ + border: 1px solid; + } + +.fc-state-default.fc-corner-left { /* non-theme */ + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + } + +.fc-state-default.fc-corner-right { /* non-theme */ + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + } + +/* + Our default prev/next buttons use HTML entities like ‹ › « » + and we'll try to make them look good cross-browser. +*/ + +.fc-text-arrow { + margin: 0 .1em; + font-size: 2em; + font-family: "Courier New", Courier, monospace; + vertical-align: baseline; /* for IE7 */ + } + +.fc-button-prev .fc-text-arrow, +.fc-button-next .fc-text-arrow { /* for ‹ › */ + font-weight: bold; + } + +/* icon (for jquery ui) */ + +.fc-button .fc-icon-wrap { + position: relative; + float: left; + top: 50%; + } + +.fc-button .ui-icon { + position: relative; + float: left; + margin-top: -50%; + *margin-top: 0; + *top: -50%; + } + +/* + button states + borrowed from twitter bootstrap (http://twitter.github.com/bootstrap/) +*/ + +.fc-state-default { + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + color: #333; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.fc-state-hover, +.fc-state-down, +.fc-state-active, +.fc-state-disabled { + color: #333333; + background-color: #e6e6e6; + } + +.fc-state-hover { + color: #333333; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; + } + +.fc-state-down, +.fc-state-active { + background-color: #cccccc; + background-image: none; + outline: 0; + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + } + +.fc-state-disabled { + cursor: default; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + box-shadow: none; + } + + + +/* Global Event Styles +------------------------------------------------------------------------*/ + +.fc-event { + border: 1px solid #3a87ad; /* default BORDER color */ + background-color: #3a87ad; /* default BACKGROUND color */ + color: #fff; /* default TEXT color */ + font-size: .85em; + cursor: default; +} + +a.fc-event { + text-decoration: none; + } + +a.fc-event, +.fc-event-draggable { + cursor: pointer; + } + +.fc-rtl .fc-event { + text-align: right; + } + +.fc-event-inner { + width: 100%; + height: 100%; + overflow: hidden; + } + +.fc-event-time, +.fc-event-title { + padding: 0 1px; + } + +.fc .ui-resizable-handle { + display: block; + position: absolute; + z-index: 99999; + overflow: hidden; /* hacky spaces (IE6/7) */ + font-size: 300%; /* */ + line-height: 50%; /* */ + } + + + +/* Horizontal Events +------------------------------------------------------------------------*/ + +.fc-event-hori { + border-width: 1px 0; + margin-bottom: 1px; + } + +.fc-ltr .fc-event-hori.fc-event-start, +.fc-rtl .fc-event-hori.fc-event-end { + border-left-width: 1px; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + } + +.fc-ltr .fc-event-hori.fc-event-end, +.fc-rtl .fc-event-hori.fc-event-start { + border-right-width: 1px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + } + +/* resizable */ + +.fc-event-hori .ui-resizable-e { + top: 0 !important; /* importants override pre jquery ui 1.7 styles */ + right: -3px !important; + width: 7px !important; + height: 100% !important; + cursor: e-resize; + } + +.fc-event-hori .ui-resizable-w { + top: 0 !important; + left: -3px !important; + width: 7px !important; + height: 100% !important; + cursor: w-resize; + } + +.fc-event-hori .ui-resizable-handle { + _padding-bottom: 14px; /* IE6 had 0 height */ + } + + + +/* Reusable Separate-border Table +------------------------------------------------------------*/ + +table.fc-border-separate { + border-collapse: separate; + } + +.fc-border-separate th, +.fc-border-separate td { + border-width: 1px 0 0 1px; + } + +.fc-border-separate th.fc-last, +.fc-border-separate td.fc-last { + border-right-width: 1px; + } + +.fc-border-separate tr.fc-last th, +.fc-border-separate tr.fc-last td { + border-bottom-width: 1px; + } + +.fc-border-separate tbody tr.fc-first td, +.fc-border-separate tbody tr.fc-first th { + border-top-width: 0; + } + + + +/* Month View, Basic Week View, Basic Day View +------------------------------------------------------------------------*/ + +.fc-grid th { + text-align: center; + } + +.fc .fc-week-number { + width: 22px; + text-align: center; + } + +.fc .fc-week-number div { + padding: 0 2px; + } + +.fc-grid .fc-day-number { + float: right; + padding: 0 2px; + } + +.fc-grid .fc-other-month .fc-day-number { + opacity: 0.3; + filter: alpha(opacity=30); /* for IE */ + /* opacity with small font can sometimes look too faded + might want to set the 'color' property instead + making day-numbers bold also fixes the problem */ + } + +.fc-grid .fc-day-content { + clear: both; + padding: 2px 2px 1px; /* distance between events and day edges */ +} + +/* event styles */ + +.fc-grid .fc-event-time { + font-weight: bold; + } + +/* right-to-left */ + +.fc-rtl .fc-grid .fc-day-number { + float: left; + } + +.fc-rtl .fc-grid .fc-event-time { + float: right; + } + + + +/* Agenda Week View, Agenda Day View +------------------------------------------------------------------------*/ + +.fc-agenda table { + border-collapse: separate; + } + +.fc-agenda-days th { + text-align: center; + } + +.fc-agenda .fc-agenda-axis { + width: 50px; + padding: 0 4px; + vertical-align: middle; + text-align: right; + white-space: nowrap; + font-weight: normal; + } + +.fc-agenda .fc-week-number { + font-weight: bold; + } + +.fc-agenda .fc-day-content { + padding: 2px 2px 1px; +} + +/* make axis border take precedence */ + +.fc-agenda-days .fc-agenda-axis { + border-right-width: 1px; + + } + +.fc-agenda-days .fc-col0 { + border-left-width: 0; + } + +/* all-day area */ + +.fc-agenda-allday th { + border-width: 0 1px; + } + +.fc-agenda-allday .fc-day-content { + min-height: 34px; /* TODO: doesnt work well in quirksmode */ + _height: 34px; + } + +/* divider (between all-day and slots) */ + +.fc-agenda-divider-inner { + height: 2px; + overflow: hidden; + } + +.fc-widget-header .fc-agenda-divider-inner { + background: #eee; + } + +/* slot rows */ + +.fc-agenda-slots th { + border-width: 1px 1px 0; + } + +.fc-agenda-slots td { + border-width: 1px 0 0; + background: none; + } + +.fc-agenda-slots td div { + height: 20px; + } + +.fc-agenda-slots tr.fc-slot0 th, +.fc-agenda-slots tr.fc-slot0 td { + border-top-width: 0; + } + +.fc-agenda-slots tr.fc-minor th, +.fc-agenda-slots tr.fc-minor td { + border-top-style: dotted; + } + +.fc-agenda-slots tr.fc-minor th.ui-widget-header { + *border-top-style: solid; /* doesn't work with background in IE6/7 */ + } + + + +/* Vertical Events +------------------------------------------------------------------------*/ + +.fc-event-vert { + border-width: 0 1px; + } + +.fc-event-vert.fc-event-start { + border-top-width: 1px; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + } + +.fc-event-vert.fc-event-end { + border-bottom-width: 1px; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + } + +.fc-event-vert .fc-event-time { + white-space: nowrap; + font-size: 10px; + } + +.fc-event-vert .fc-event-inner { + position: relative; + z-index: 2; + } + +.fc-event-vert .fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay */ + position: absolute; + z-index: 1; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #fff; + opacity: .25; + filter: alpha(opacity=25); + } + +.fc .ui-draggable-dragging .fc-event-bg, /* TODO: something nicer like .fc-opacity */ +.fc-select-helper .fc-event-bg { + display: none\9; /* for IE6/7/8. nested opacity filters while dragging don't work */ + } + +/* resizable */ + +.fc-event-vert .ui-resizable-s { + bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */ + width: 100% !important; + height: 8px !important; + overflow: hidden !important; + line-height: 8px !important; + font-size: 11px !important; + font-family: monospace; + text-align: center; + cursor: s-resize; + } + +.fc-agenda .ui-resizable-resizing { /* TODO: better selector */ + _overflow: hidden; + } + + diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/fullcalendar.print.css b/gridplatform/bootstrap/static/bootstrap/genius/css/fullcalendar.print.css new file mode 100755 index 0000000..8fea38d --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/fullcalendar.print.css @@ -0,0 +1,32 @@ +/*! + * FullCalendar v1.6.1 Print Stylesheet + * Docs & License: http://arshaw.com/fullcalendar/ + * (c) 2013 Adam Shaw + */ + +/* + * Include this stylesheet on your page to get a more printer-friendly calendar. + * When including this stylesheet, use the media='print' attribute of the tag. + * Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css. + */ + + + /* Events +-----------------------------------------------------*/ + +.fc-event { + background: #fff !important; + color: #000 !important; + } + +/* for vertical events */ + +.fc-event-bg { + display: none !important; + } + +.fc-event .ui-resizable-handle { + display: none !important; + } + + diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/glyphicons.css b/gridplatform/bootstrap/static/bootstrap/genius/css/glyphicons.css new file mode 100644 index 0000000..3ea2da9 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/glyphicons.css @@ -0,0 +1,2879 @@ +/*! + * + * Project: GLYPHICONS HALFLINGS + * Author: Jan Kovarik - www.glyphicons.com + * Twitter: @glyphicons + * + */ +@font-face { + font-family: 'Glyphicons Regular'; + src: url('../fonts/glyphicons-regular.eot'); + src: url('../fonts/glyphicons-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-regular.woff') format('woff'), url('../fonts/glyphicons-regular.ttf') format('truetype'), url('../fonts/glyphicons-regular.svg#glyphiconsregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.glyphicons { + display: inline-block; + position: relative; + padding-left: 48px; + color: #1d1d1b; + text-decoration: none; + *display: inline; + *zoom: 1; + vertical-align: middle; +} +.glyphicons:before { + position: absolute; + left: 0; + top: 0; + display: inline-block; + margin: 0 5px 0 0; + font: 24px/1em 'Glyphicons Regular'; + font-style: normal; + font-weight: normal; + color: #1d1d1b; + *display: inline; + *zoom: 1; + vertical-align: middle; + text-transform: none; + -webkit-font-smoothing: antialiased; +} +.glyphicons.white:before { + color: #fff; +} +.glyphicons.glass:before { + content: "\E001"; +} +.glyphicons.leaf:before { + content: "\E002"; +} +.glyphicons.dog:before { + content: "\1F415"; +} +.glyphicons.user:before { + content: "\E004"; +} +.glyphicons.girl:before { + content: "\1F467"; +} +.glyphicons.car:before { + content: "\E006"; +} +.glyphicons.user_add:before { + content: "\E007"; +} +.glyphicons.user_remove:before { + content: "\E008"; +} +.glyphicons.film:before { + content: "\E009"; +} +.glyphicons.magic:before { + content: "\E010"; +} +.glyphicons.envelope:before { + content: "\2709"; +} +.glyphicons.camera:before { + content: "\1F4F7"; +} +.glyphicons.heart:before { + content: "\E013"; +} +.glyphicons.beach_umbrella:before { + content: "\E014"; +} +.glyphicons.train:before { + content: "\1F686"; +} +.glyphicons.print:before { + content: "\E016"; +} +.glyphicons.bin:before { + content: "\E017"; +} +.glyphicons.music:before { + content: "\E018"; +} +.glyphicons.note:before { + content: "\E019"; +} +.glyphicons.heart_empty:before { + content: "\E020"; +} +.glyphicons.home:before { + content: "\E021"; +} +.glyphicons.snowflake:before { + content: "\2744"; +} +.glyphicons.fire:before { + content: "\1F525"; +} +.glyphicons.magnet:before { + content: "\E024"; +} +.glyphicons.parents:before { + content: "\E025"; +} +.glyphicons.binoculars:before { + content: "\E026"; +} +.glyphicons.road:before { + content: "\E027"; +} +.glyphicons.search:before { + content: "\E028"; +} +.glyphicons.cars:before { + content: "\E029"; +} +.glyphicons.notes_2:before { + content: "\E030"; +} +.glyphicons.pencil:before { + content: "\270F"; +} +.glyphicons.bus:before { + content: "\1F68C"; +} +.glyphicons.wifi_alt:before { + content: "\E033"; +} +.glyphicons.luggage:before { + content: "\E034"; +} +.glyphicons.old_man:before { + content: "\E035"; +} +.glyphicons.woman:before { + content: "\1F469"; +} +.glyphicons.file:before { + content: "\E037"; +} +.glyphicons.coins:before { + content: "\E038"; +} +.glyphicons.airplane:before { + content: "\2708"; +} +.glyphicons.notes:before { + content: "\E040"; +} +.glyphicons.stats:before { + content: "\E041"; +} +.glyphicons.charts:before { + content: "\E042"; +} +.glyphicons.pie_chart:before { + content: "\E043"; +} +.glyphicons.group:before { + content: "\E044"; +} +.glyphicons.keys:before { + content: "\E045"; +} +.glyphicons.calendar:before { + content: "\1F4C5"; +} +.glyphicons.router:before { + content: "\E047"; +} +.glyphicons.camera_small:before { + content: "\E048"; +} +.glyphicons.dislikes:before { + content: "\E049"; +} +.glyphicons.star:before { + content: "\E050"; +} +.glyphicons.link:before { + content: "\E051"; +} +.glyphicons.eye_open:before { + content: "\E052"; +} +.glyphicons.eye_close:before { + content: "\E053"; +} +.glyphicons.alarm:before { + content: "\E054"; +} +.glyphicons.clock:before { + content: "\E055"; +} +.glyphicons.stopwatch:before { + content: "\E056"; +} +.glyphicons.projector:before { + content: "\E057"; +} +.glyphicons.history:before { + content: "\E058"; +} +.glyphicons.truck:before { + content: "\E059"; +} +.glyphicons.cargo:before { + content: "\E060"; +} +.glyphicons.compass:before { + content: "\E061"; +} +.glyphicons.keynote:before { + content: "\E062"; +} +.glyphicons.paperclip:before { + content: "\1F4CE"; +} +.glyphicons.power:before { + content: "\E064"; +} +.glyphicons.lightbulb:before { + content: "\E065"; +} +.glyphicons.tag:before { + content: "\E066"; +} +.glyphicons.tags:before { + content: "\E067"; +} +.glyphicons.cleaning:before { + content: "\E068"; +} +.glyphicons.ruller:before { + content: "\E069"; +} +.glyphicons.gift:before { + content: "\E070"; +} +.glyphicons.umbrella:before { + content: "\2602"; +} +.glyphicons.book:before { + content: "\E072"; +} +.glyphicons.bookmark:before { + content: "\1F516"; +} +.glyphicons.wifi:before { + content: "\E074"; +} +.glyphicons.cup:before { + content: "\E075"; +} +.glyphicons.stroller:before { + content: "\E076"; +} +.glyphicons.headphones:before { + content: "\E077"; +} +.glyphicons.headset:before { + content: "\E078"; +} +.glyphicons.warning_sign:before { + content: "\E079"; +} +.glyphicons.signal:before { + content: "\E080"; +} +.glyphicons.retweet:before { + content: "\E081"; +} +.glyphicons.refresh:before { + content: "\E082"; +} +.glyphicons.roundabout:before { + content: "\E083"; +} +.glyphicons.random:before { + content: "\E084"; +} +.glyphicons.heat:before { + content: "\E085"; +} +.glyphicons.repeat:before { + content: "\E086"; +} +.glyphicons.display:before { + content: "\E087"; +} +.glyphicons.log_book:before { + content: "\E088"; +} +.glyphicons.address_book:before { + content: "\E089"; +} +.glyphicons.building:before { + content: "\E090"; +} +.glyphicons.eyedropper:before { + content: "\E091"; +} +.glyphicons.adjust:before { + content: "\E092"; +} +.glyphicons.tint:before { + content: "\E093"; +} +.glyphicons.crop:before { + content: "\E094"; +} +.glyphicons.vector_path_square:before { + content: "\E095"; +} +.glyphicons.vector_path_circle:before { + content: "\E096"; +} +.glyphicons.vector_path_polygon:before { + content: "\E097"; +} +.glyphicons.vector_path_line:before { + content: "\E098"; +} +.glyphicons.vector_path_curve:before { + content: "\E099"; +} +.glyphicons.vector_path_all:before { + content: "\E100"; +} +.glyphicons.font:before { + content: "\E101"; +} +.glyphicons.italic:before { + content: "\E102"; +} +.glyphicons.bold:before { + content: "\E103"; +} +.glyphicons.text_underline:before { + content: "\E104"; +} +.glyphicons.text_strike:before { + content: "\E105"; +} +.glyphicons.text_height:before { + content: "\E106"; +} +.glyphicons.text_width:before { + content: "\E107"; +} +.glyphicons.text_resize:before { + content: "\E108"; +} +.glyphicons.left_indent:before { + content: "\E109"; +} +.glyphicons.right_indent:before { + content: "\E110"; +} +.glyphicons.align_left:before { + content: "\E111"; +} +.glyphicons.align_center:before { + content: "\E112"; +} +.glyphicons.align_right:before { + content: "\E113"; +} +.glyphicons.justify:before { + content: "\E114"; +} +.glyphicons.list:before { + content: "\E115"; +} +.glyphicons.text_smaller:before { + content: "\E116"; +} +.glyphicons.text_bigger:before { + content: "\E117"; +} +.glyphicons.embed:before { + content: "\E118"; +} +.glyphicons.embed_close:before { + content: "\E119"; +} +.glyphicons.table:before { + content: "\E120"; +} +.glyphicons.message_full:before { + content: "\E121"; +} +.glyphicons.message_empty:before { + content: "\E122"; +} +.glyphicons.message_in:before { + content: "\E123"; +} +.glyphicons.message_out:before { + content: "\E124"; +} +.glyphicons.message_plus:before { + content: "\E125"; +} +.glyphicons.message_minus:before { + content: "\E126"; +} +.glyphicons.message_ban:before { + content: "\E127"; +} +.glyphicons.message_flag:before { + content: "\E128"; +} +.glyphicons.message_lock:before { + content: "\E129"; +} +.glyphicons.message_new:before { + content: "\E130"; +} +.glyphicons.inbox:before { + content: "\E131"; +} +.glyphicons.inbox_plus:before { + content: "\E132"; +} +.glyphicons.inbox_minus:before { + content: "\E133"; +} +.glyphicons.inbox_lock:before { + content: "\E134"; +} +.glyphicons.inbox_in:before { + content: "\E135"; +} +.glyphicons.inbox_out:before { + content: "\E136"; +} +.glyphicons.cogwheel:before { + content: "\E137"; +} +.glyphicons.cogwheels:before { + content: "\E138"; +} +.glyphicons.picture:before { + content: "\E139"; +} +.glyphicons.adjust_alt:before { + content: "\E140"; +} +.glyphicons.database_lock:before { + content: "\E141"; +} +.glyphicons.database_plus:before { + content: "\E142"; +} +.glyphicons.database_minus:before { + content: "\E143"; +} +.glyphicons.database_ban:before { + content: "\E144"; +} +.glyphicons.folder_open:before { + content: "\E145"; +} +.glyphicons.folder_plus:before { + content: "\E146"; +} +.glyphicons.folder_minus:before { + content: "\E147"; +} +.glyphicons.folder_lock:before { + content: "\E148"; +} +.glyphicons.folder_flag:before { + content: "\E149"; +} +.glyphicons.folder_new:before { + content: "\E150"; +} +.glyphicons.edit:before { + content: "\E151"; +} +.glyphicons.new_window:before { + content: "\E152"; +} +.glyphicons.check:before { + content: "\E153"; +} +.glyphicons.unchecked:before { + content: "\E154"; +} +.glyphicons.more_windows:before { + content: "\E155"; +} +.glyphicons.show_big_thumbnails:before { + content: "\E156"; +} +.glyphicons.show_thumbnails:before { + content: "\E157"; +} +.glyphicons.show_thumbnails_with_lines:before { + content: "\E158"; +} +.glyphicons.show_lines:before { + content: "\E159"; +} +.glyphicons.playlist:before { + content: "\E160"; +} +.glyphicons.imac:before { + content: "\E161"; +} +.glyphicons.macbook:before { + content: "\E162"; +} +.glyphicons.ipad:before { + content: "\E163"; +} +.glyphicons.iphone:before { + content: "\E164"; +} +.glyphicons.iphone_transfer:before { + content: "\E165"; +} +.glyphicons.iphone_exchange:before { + content: "\E166"; +} +.glyphicons.ipod:before { + content: "\E167"; +} +.glyphicons.ipod_shuffle:before { + content: "\E168"; +} +.glyphicons.ear_plugs:before { + content: "\E169"; +} +.glyphicons.record:before { + content: "\E170"; +} +.glyphicons.step_backward:before { + content: "\E171"; +} +.glyphicons.fast_backward:before { + content: "\E172"; +} +.glyphicons.rewind:before { + content: "\E173"; +} +.glyphicons.play:before { + content: "\E174"; +} +.glyphicons.pause:before { + content: "\E175"; +} +.glyphicons.stop:before { + content: "\E176"; +} +.glyphicons.forward:before { + content: "\E177"; +} +.glyphicons.fast_forward:before { + content: "\E178"; +} +.glyphicons.step_forward:before { + content: "\E179"; +} +.glyphicons.eject:before { + content: "\E180"; +} +.glyphicons.facetime_video:before { + content: "\E181"; +} +.glyphicons.download_alt:before { + content: "\E182"; +} +.glyphicons.mute:before { + content: "\E183"; +} +.glyphicons.volume_down:before { + content: "\E184"; +} +.glyphicons.volume_up:before { + content: "\E185"; +} +.glyphicons.screenshot:before { + content: "\E186"; +} +.glyphicons.move:before { + content: "\E187"; +} +.glyphicons.more:before { + content: "\E188"; +} +.glyphicons.brightness_reduce:before { + content: "\E189"; +} +.glyphicons.brightness_increase:before { + content: "\E190"; +} +.glyphicons.circle_plus:before { + content: "\E191"; +} +.glyphicons.circle_minus:before { + content: "\E192"; +} +.glyphicons.circle_remove:before { + content: "\E193"; +} +.glyphicons.circle_ok:before { + content: "\E194"; +} +.glyphicons.circle_question_mark:before { + content: "\E195"; +} +.glyphicons.circle_info:before { + content: "\E196"; +} +.glyphicons.circle_exclamation_mark:before { + content: "\E197"; +} +.glyphicons.remove:before { + content: "\E198"; +} +.glyphicons.ok:before { + content: "\E199"; +} +.glyphicons.ban:before { + content: "\E200"; +} +.glyphicons.download:before { + content: "\E201"; +} +.glyphicons.upload:before { + content: "\E202"; +} +.glyphicons.shopping_cart:before { + content: "\E203"; +} +.glyphicons.lock:before { + content: "\1F512"; +} +.glyphicons.unlock:before { + content: "\E205"; +} +.glyphicons.electricity:before { + content: "\E206"; +} +.glyphicons.ok_2:before { + content: "\E207"; +} +.glyphicons.remove_2:before { + content: "\E208"; +} +.glyphicons.cart_out:before { + content: "\E209"; +} +.glyphicons.cart_in:before { + content: "\E210"; +} +.glyphicons.left_arrow:before { + content: "\E211"; +} +.glyphicons.right_arrow:before { + content: "\E212"; +} +.glyphicons.down_arrow:before { + content: "\E213"; +} +.glyphicons.up_arrow:before { + content: "\E214"; +} +.glyphicons.resize_small:before { + content: "\E215"; +} +.glyphicons.resize_full:before { + content: "\E216"; +} +.glyphicons.circle_arrow_left:before { + content: "\E217"; +} +.glyphicons.circle_arrow_right:before { + content: "\E218"; +} +.glyphicons.circle_arrow_top:before { + content: "\E219"; +} +.glyphicons.circle_arrow_down:before { + content: "\E220"; +} +.glyphicons.play_button:before { + content: "\E221"; +} +.glyphicons.unshare:before { + content: "\E222"; +} +.glyphicons.share:before { + content: "\E223"; +} +.glyphicons.chevron-right:before { + content: "\E224"; +} +.glyphicons.chevron-left:before { + content: "\E225"; +} +.glyphicons.bluetooth:before { + content: "\E226"; +} +.glyphicons.euro:before { + content: "\20AC"; +} +.glyphicons.usd:before { + content: "\E228"; +} +.glyphicons.gbp:before { + content: "\E229"; +} +.glyphicons.retweet_2:before { + content: "\E230"; +} +.glyphicons.moon:before { + content: "\E231"; +} +.glyphicons.sun:before { + content: "\2609"; +} +.glyphicons.cloud:before { + content: "\2601"; +} +.glyphicons.direction:before { + content: "\E234"; +} +.glyphicons.brush:before { + content: "\E235"; +} +.glyphicons.pen:before { + content: "\E236"; +} +.glyphicons.zoom_in:before { + content: "\E237"; +} +.glyphicons.zoom_out:before { + content: "\E238"; +} +.glyphicons.pin:before { + content: "\E239"; +} +.glyphicons.albums:before { + content: "\E240"; +} +.glyphicons.rotation_lock:before { + content: "\E241"; +} +.glyphicons.flash:before { + content: "\E242"; +} +.glyphicons.google_maps:before { + content: "\E243"; +} +.glyphicons.anchor:before { + content: "\2693"; +} +.glyphicons.conversation:before { + content: "\E245"; +} +.glyphicons.chat:before { + content: "\E246"; +} +.glyphicons.male:before { + content: "\E247"; +} +.glyphicons.female:before { + content: "\E248"; +} +.glyphicons.asterisk:before { + content: "\002A"; +} +.glyphicons.divide:before { + content: "\00F7"; +} +.glyphicons.snorkel_diving:before { + content: "\E251"; +} +.glyphicons.scuba_diving:before { + content: "\E252"; +} +.glyphicons.oxygen_bottle:before { + content: "\E253"; +} +.glyphicons.fins:before { + content: "\E254"; +} +.glyphicons.fishes:before { + content: "\E255"; +} +.glyphicons.boat:before { + content: "\E256"; +} +.glyphicons.delete:before { + content: "\E257"; +} +.glyphicons.sheriffs_star:before { + content: "\E258"; +} +.glyphicons.qrcode:before { + content: "\E259"; +} +.glyphicons.barcode:before { + content: "\E260"; +} +.glyphicons.pool:before { + content: "\E261"; +} +.glyphicons.buoy:before { + content: "\E262"; +} +.glyphicons.spade:before { + content: "\E263"; +} +.glyphicons.bank:before { + content: "\1F3E6"; +} +.glyphicons.vcard:before { + content: "\E265"; +} +.glyphicons.electrical_plug:before { + content: "\E266"; +} +.glyphicons.flag:before { + content: "\E267"; +} +.glyphicons.credit_card:before { + content: "\E268"; +} +.glyphicons.keyboard-wireless:before { + content: "\E269"; +} +.glyphicons.keyboard-wired:before { + content: "\E270"; +} +.glyphicons.shield:before { + content: "\E271"; +} +.glyphicons.ring:before { + content: "\02DA"; +} +.glyphicons.cake:before { + content: "\E273"; +} +.glyphicons.drink:before { + content: "\E274"; +} +.glyphicons.beer:before { + content: "\E275"; +} +.glyphicons.fast_food:before { + content: "\E276"; +} +.glyphicons.cutlery:before { + content: "\E277"; +} +.glyphicons.pizza:before { + content: "\E278"; +} +.glyphicons.birthday_cake:before { + content: "\E279"; +} +.glyphicons.tablet:before { + content: "\E280"; +} +.glyphicons.settings:before { + content: "\E281"; +} +.glyphicons.bullets:before { + content: "\E282"; +} +.glyphicons.cardio:before { + content: "\E283"; +} +.glyphicons.t-shirt:before { + content: "\E284"; +} +.glyphicons.pants:before { + content: "\E285"; +} +.glyphicons.sweater:before { + content: "\E286"; +} +.glyphicons.fabric:before { + content: "\E287"; +} +.glyphicons.leather:before { + content: "\E288"; +} +.glyphicons.scissors:before { + content: "\E289"; +} +.glyphicons.bomb:before { + content: "\1F4A3"; +} +.glyphicons.skull:before { + content: "\1F480"; +} +.glyphicons.celebration:before { + content: "\E292"; +} +.glyphicons.tea_kettle:before { + content: "\E293"; +} +.glyphicons.french_press:before { + content: "\E294"; +} +.glyphicons.coffe_cup:before { + content: "\E295"; +} +.glyphicons.pot:before { + content: "\E296"; +} +.glyphicons.grater:before { + content: "\E297"; +} +.glyphicons.kettle:before { + content: "\E298"; +} +.glyphicons.hospital:before { + content: "\1F3E5"; +} +.glyphicons.hospital_h:before { + content: "\E300"; +} +.glyphicons.microphone:before { + content: "\1F3A4"; +} +.glyphicons.webcam:before { + content: "\E302"; +} +.glyphicons.temple_christianity_church:before { + content: "\E303"; +} +.glyphicons.temple_islam:before { + content: "\E304"; +} +.glyphicons.temple_hindu:before { + content: "\E305"; +} +.glyphicons.temple_buddhist:before { + content: "\E306"; +} +.glyphicons.bicycle:before { + content: "\1F6B2"; +} +.glyphicons.life_preserver:before { + content: "\E308"; +} +.glyphicons.share_alt:before { + content: "\E309"; +} +.glyphicons.comments:before { + content: "\E310"; +} +.glyphicons.flower:before { + content: "\2698"; +} +.glyphicons.baseball:before { + content: "\26BE"; +} +.glyphicons.rugby:before { + content: "\E313"; +} +.glyphicons.ax:before { + content: "\E314"; +} +.glyphicons.table_tennis:before { + content: "\E315"; +} +.glyphicons.bowling:before { + content: "\1F3B3"; +} +.glyphicons.tree_conifer:before { + content: "\E317"; +} +.glyphicons.tree_deciduous:before { + content: "\E318"; +} +.glyphicons.more_items:before { + content: "\E319"; +} +.glyphicons.sort:before { + content: "\E320"; +} +.glyphicons.filter:before { + content: "\E321"; +} +.glyphicons.gamepad:before { + content: "\E322"; +} +.glyphicons.playing_dices:before { + content: "\E323"; +} +.glyphicons.calculator:before { + content: "\E324"; +} +.glyphicons.tie:before { + content: "\E325"; +} +.glyphicons.wallet:before { + content: "\E326"; +} +.glyphicons.piano:before { + content: "\E327"; +} +.glyphicons.sampler:before { + content: "\E328"; +} +.glyphicons.podium:before { + content: "\E329"; +} +.glyphicons.soccer_ball:before { + content: "\E330"; +} +.glyphicons.blog:before { + content: "\E331"; +} +.glyphicons.dashboard:before { + content: "\E332"; +} +.glyphicons.certificate:before { + content: "\E333"; +} +.glyphicons.bell:before { + content: "\1F514"; +} +.glyphicons.candle:before { + content: "\E335"; +} +.glyphicons.pushpin:before { + content: "\1F4CC"; +} +.glyphicons.iphone_shake:before { + content: "\E337"; +} +.glyphicons.pin_flag:before { + content: "\E338"; +} +.glyphicons.turtle:before { + content: "\1F422"; +} +.glyphicons.rabbit:before { + content: "\1F407"; +} +.glyphicons.globe:before { + content: "\E341"; +} +.glyphicons.briefcase:before { + content: "\1F4BC"; +} +.glyphicons.hdd:before { + content: "\E343"; +} +.glyphicons.thumbs_up:before { + content: "\E344"; +} +.glyphicons.thumbs_down:before { + content: "\E345"; +} +.glyphicons.hand_right:before { + content: "\E346"; +} +.glyphicons.hand_left:before { + content: "\E347"; +} +.glyphicons.hand_up:before { + content: "\E348"; +} +.glyphicons.hand_down:before { + content: "\E349"; +} +.glyphicons.fullscreen:before { + content: "\E350"; +} +.glyphicons.shopping_bag:before { + content: "\E351"; +} +.glyphicons.book_open:before { + content: "\E352"; +} +.glyphicons.nameplate:before { + content: "\E353"; +} +.glyphicons.nameplate_alt:before { + content: "\E354"; +} +.glyphicons.vases:before { + content: "\E355"; +} +.glyphicons.bullhorn:before { + content: "\E356"; +} +.glyphicons.dumbbell:before { + content: "\E357"; +} +.glyphicons.suitcase:before { + content: "\E358"; +} +.glyphicons.file_import:before { + content: "\E359"; +} +.glyphicons.file_export:before { + content: "\E360"; +} +.glyphicons.bug:before { + content: "\1F41B"; +} +.glyphicons.crown:before { + content: "\1F451"; +} +.glyphicons.smoking:before { + content: "\E363"; +} +.glyphicons.cloud-upload:before { + content: "\E364"; +} +.glyphicons.cloud-download:before { + content: "\E365"; +} +.glyphicons.restart:before { + content: "\E366"; +} +.glyphicons.security_camera:before { + content: "\E367"; +} +.glyphicons.expand:before { + content: "\E368"; +} +.glyphicons.collapse:before { + content: "\E369"; +} +.glyphicons.collapse_top:before { + content: "\E370"; +} +.glyphicons.globe_af:before { + content: "\E371"; +} +.glyphicons.global:before { + content: "\E372"; +} +.glyphicons.spray:before { + content: "\E373"; +} +.glyphicons.nails:before { + content: "\E374"; +} +.glyphicons.claw_hammer:before { + content: "\E375"; +} +.glyphicons.classic_hammer:before { + content: "\E376"; +} +.glyphicons.hand_saw:before { + content: "\E377"; +} +.glyphicons.riflescope:before { + content: "\E378"; +} +.glyphicons.electrical_socket_eu:before { + content: "\E379"; +} +.glyphicons.electrical_socket_us:before { + content: "\E380"; +} +.glyphicons.message_forward:before { + content: "\E381"; +} +.glyphicons.coat_hanger:before { + content: "\E382"; +} +.glyphicons.dress:before { + content: "\1F457"; +} +.glyphicons.bathrobe:before { + content: "\E384"; +} +.glyphicons.shirt:before { + content: "\E385"; +} +.glyphicons.underwear:before { + content: "\E386"; +} +.glyphicons.log_in:before { + content: "\E387"; +} +.glyphicons.log_out:before { + content: "\E388"; +} +.glyphicons.exit:before { + content: "\E389"; +} +.glyphicons.new_window_alt:before { + content: "\E390"; +} +.glyphicons.video_sd:before { + content: "\E391"; +} +.glyphicons.video_hd:before { + content: "\E392"; +} +.glyphicons.subtitles:before { + content: "\E393"; +} +.glyphicons.sound_stereo:before { + content: "\E394"; +} +.glyphicons.sound_dolby:before { + content: "\E395"; +} +.glyphicons.sound_5_1:before { + content: "\E396"; +} +.glyphicons.sound_6_1:before { + content: "\E397"; +} +.glyphicons.sound_7_1:before { + content: "\E398"; +} +.glyphicons.copyright_mark:before { + content: "\E399"; +} +.glyphicons.registration_mark:before { + content: "\E400"; +} +.glyphicons.radar:before { + content: "\E401"; +} +.glyphicons.skateboard:before { + content: "\E402"; +} +.glyphicons.golf_course:before { + content: "\E403"; +} +.glyphicons.sorting:before { + content: "\E404"; +} +.glyphicons.sort-by-alphabet:before { + content: "\E405"; +} +.glyphicons.sort-by-alphabet-alt:before { + content: "\E406"; +} +.glyphicons.sort-by-order:before { + content: "\E407"; +} +.glyphicons.sort-by-order-alt:before { + content: "\E408"; +} +.glyphicons.sort-by-attributes:before { + content: "\E409"; +} +.glyphicons.sort-by-attributes-alt:before { + content: "\E410"; +} +.glyphicons.compressed:before { + content: "\E411"; +} +.glyphicons.package:before { + content: "\1F4E6"; +} +.glyphicons.cloud_plus:before { + content: "\E413"; +} +.glyphicons.cloud_minus:before { + content: "\E414"; +} +.glyphicons.disk_save:before { + content: "\E415"; +} +.glyphicons.disk_open:before { + content: "\E416"; +} +.glyphicons.disk_saved:before { + content: "\E417"; +} +.glyphicons.disk_remove:before { + content: "\E418"; +} +.glyphicons.disk_import:before { + content: "\E419"; +} +.glyphicons.disk_export:before { + content: "\E420"; +} +.glyphicons.tower:before { + content: "\E421"; +} +.glyphicons.send:before { + content: "\E422"; +} +.glyphicons.git_branch:before { + content: "\E423"; +} +.glyphicons.git_create:before { + content: "\E424"; +} +.glyphicons.git_private:before { + content: "\E425"; +} +.glyphicons.git_delete:before { + content: "\E426"; +} +.glyphicons.git_merge:before { + content: "\E427"; +} +.glyphicons.git_pull_request:before { + content: "\E428"; +} +.glyphicons.git_compare:before { + content: "\E429"; +} +.glyphicons.git_commit:before { + content: "\E430"; +} +.glyphicons.construction_cone:before { + content: "\E431"; +} +.glyphicons.shoe_steps:before { + content: "\E432"; +} +.glyphicons.plus:before { + content: "\002B"; +} +.glyphicons.minus:before { + content: "\2212"; +} +.glyphicons.redo:before { + content: "\E435"; +} +.glyphicons.undo:before { + content: "\E436"; +} +.glyphicons.golf:before { + content: "\E437"; +} +.glyphicons.hockey:before { + content: "\E438"; +} +.glyphicons.pipe:before { + content: "\E439"; +} +.glyphicons.wrench:before { + content: "\1F527"; +} +.glyphicons.folder_closed:before { + content: "\E441"; +} +.glyphicons.phone_alt:before { + content: "\E442"; +} +.glyphicons.earphone:before { + content: "\E443"; +} +.glyphicons.floppy_disk:before { + content: "\E444"; +} +.glyphicons.floppy_saved:before { + content: "\E445"; +} +.glyphicons.floppy_remove:before { + content: "\E446"; +} +.glyphicons.floppy_save:before { + content: "\E447"; +} +.glyphicons.floppy_open:before { + content: "\E448"; +} +.glyphicons.translate:before { + content: "\E449"; +} +.glyphicons.fax:before { + content: "\E450"; +} +.glyphicons.factory:before { + content: "\1F3ED"; +} +.glyphicons.shop_window:before { + content: "\E452"; +} +.glyphicons.shop:before { + content: "\E453"; +} +.glyphicons.kiosk:before { + content: "\E454"; +} +.glyphicons.kiosk_wheels:before { + content: "\E455"; +} +.glyphicons.kiosk_light:before { + content: "\E456"; +} +.glyphicons.kiosk_food:before { + content: "\E457"; +} +.glyphicons.transfer:before { + content: "\E458"; +} +.glyphicons.money:before { + content: "\E459"; +} +.glyphicons.header:before { + content: "\E460"; +} +.glyphicons.blacksmith:before { + content: "\E461"; +} +.glyphicons.saw_blade:before { + content: "\E462"; +} +.glyphicons.basketball:before { + content: "\E463"; +} +.glyphicons.server:before { + content: "\E464"; +} +.glyphicons.server_plus:before { + content: "\E465"; +} +.glyphicons.server_minus:before { + content: "\E466"; +} +.glyphicons.server_ban:before { + content: "\E467"; +} +.glyphicons.server_flag:before { + content: "\E468"; +} +.glyphicons.server_lock:before { + content: "\E469"; +} +.glyphicons.server_new:before { + content: "\E470"; +} +.glyphicons-icon { + display: inline-block; + width: 48px; + height: 48px; + margin: 0 8px 0 0; + line-height: 14px; + vertical-align: text-top; + background-position: 0 0; + background-repeat: no-repeat; + vertical-align: top; + *display: inline; + *zoom: 1; + *margin-right: .3em; +} +.glyphicons-icon _:-o-prefocus, +.glyphicons-icon.white _:-o-prefocus, +.glyphicons-icon.glass { + background-position: 4px 11px; +} +.glyphicons-icon.leaf { + background-position: -44px 11px; +} +.glyphicons-icon.dog { + background-position: -92px 11px; +} +.glyphicons-icon.user { + background-position: -140px 11px; +} +.glyphicons-icon.girl { + background-position: -188px 11px; +} +.glyphicons-icon.car { + background-position: -236px 11px; +} +.glyphicons-icon.user_add { + background-position: -284px 11px; +} +.glyphicons-icon.user_remove { + background-position: -332px 11px; +} +.glyphicons-icon.film { + background-position: -380px 11px; +} +.glyphicons-icon.magic { + background-position: -428px 11px; +} +.glyphicons-icon.envelope { + background-position: 4px -37px; +} +.glyphicons-icon.camera { + background-position: -44px -37px; +} +.glyphicons-icon.heart { + background-position: -92px -37px; +} +.glyphicons-icon.beach_umbrella { + background-position: -140px -37px; +} +.glyphicons-icon.train { + background-position: -188px -37px; +} +.glyphicons-icon.print { + background-position: -236px -37px; +} +.glyphicons-icon.bin { + background-position: -284px -37px; +} +.glyphicons-icon.music { + background-position: -332px -37px; +} +.glyphicons-icon.note { + background-position: -380px -37px; +} +.glyphicons-icon.heart_empty { + background-position: -428px -37px; +} +.glyphicons-icon.home { + background-position: 4px -85px; +} +.glyphicons-icon.snowflake { + background-position: -44px -85px; +} +.glyphicons-icon.fire { + background-position: -92px -85px; +} +.glyphicons-icon.magnet { + background-position: -140px -85px; +} +.glyphicons-icon.parents { + background-position: -188px -85px; +} +.glyphicons-icon.binoculars { + background-position: -236px -85px; +} +.glyphicons-icon.road { + background-position: -284px -85px; +} +.glyphicons-icon.search { + background-position: -332px -85px; +} +.glyphicons-icon.cars { + background-position: -380px -85px; +} +.glyphicons-icon.notes_2 { + background-position: -428px -85px; +} +.glyphicons-icon.pencil { + background-position: 4px -133px; +} +.glyphicons-icon.bus { + background-position: -44px -133px; +} +.glyphicons-icon.wifi_alt { + background-position: -92px -133px; +} +.glyphicons-icon.luggage { + background-position: -140px -133px; +} +.glyphicons-icon.old_man { + background-position: -188px -133px; +} +.glyphicons-icon.woman { + background-position: -236px -133px; +} +.glyphicons-icon.file { + background-position: -284px -133px; +} +.glyphicons-icon.coins { + background-position: -332px -133px; +} +.glyphicons-icon.airplane { + background-position: -380px -133px; +} +.glyphicons-icon.notes { + background-position: -428px -133px; +} +.glyphicons-icon.stats { + background-position: 4px -181px; +} +.glyphicons-icon.charts { + background-position: -44px -181px; +} +.glyphicons-icon.pie_chart { + background-position: -92px -181px; +} +.glyphicons-icon.group { + background-position: -140px -181px; +} +.glyphicons-icon.keys { + background-position: -188px -181px; +} +.glyphicons-icon.calendar { + background-position: -236px -181px; +} +.glyphicons-icon.router { + background-position: -284px -181px; +} +.glyphicons-icon.camera_small { + background-position: -332px -181px; +} +.glyphicons-icon.dislikes { + background-position: -380px -181px; +} +.glyphicons-icon.star { + background-position: -428px -181px; +} +.glyphicons-icon.link { + background-position: 4px -229px; +} +.glyphicons-icon.eye_open { + background-position: -44px -229px; +} +.glyphicons-icon.eye_close { + background-position: -92px -229px; +} +.glyphicons-icon.alarm { + background-position: -140px -229px; +} +.glyphicons-icon.clock { + background-position: -188px -229px; +} +.glyphicons-icon.stopwatch { + background-position: -236px -229px; +} +.glyphicons-icon.projector { + background-position: -284px -229px; +} +.glyphicons-icon.history { + background-position: -332px -229px; +} +.glyphicons-icon.truck { + background-position: -380px -229px; +} +.glyphicons-icon.cargo { + background-position: -428px -229px; +} +.glyphicons-icon.compass { + background-position: 4px -277px; +} +.glyphicons-icon.keynote { + background-position: -44px -277px; +} +.glyphicons-icon.paperclip { + background-position: -92px -277px; +} +.glyphicons-icon.power { + background-position: -140px -277px; +} +.glyphicons-icon.lightbulb { + background-position: -188px -277px; +} +.glyphicons-icon.tag { + background-position: -236px -277px; +} +.glyphicons-icon.tags { + background-position: -284px -277px; +} +.glyphicons-icon.cleaning { + background-position: -332px -277px; +} +.glyphicons-icon.ruller { + background-position: -380px -277px; +} +.glyphicons-icon.gift { + background-position: -428px -277px; +} +.glyphicons-icon.umbrella { + background-position: 4px -325px; +} +.glyphicons-icon.book { + background-position: -44px -325px; +} +.glyphicons-icon.bookmark { + background-position: -92px -325px; +} +.glyphicons-icon.wifi { + background-position: -140px -325px; +} +.glyphicons-icon.cup { + background-position: -188px -325px; +} +.glyphicons-icon.stroller { + background-position: -236px -325px; +} +.glyphicons-icon.headphones { + background-position: -284px -325px; +} +.glyphicons-icon.headset { + background-position: -332px -325px; +} +.glyphicons-icon.warning_sign { + background-position: -380px -325px; +} +.glyphicons-icon.signal { + background-position: -428px -325px; +} +.glyphicons-icon.retweet { + background-position: 4px -373px; +} +.glyphicons-icon.refresh { + background-position: -44px -373px; +} +.glyphicons-icon.roundabout { + background-position: -92px -373px; +} +.glyphicons-icon.random { + background-position: -140px -373px; +} +.glyphicons-icon.heat { + background-position: -188px -373px; +} +.glyphicons-icon.repeat { + background-position: -236px -373px; +} +.glyphicons-icon.display { + background-position: -284px -373px; +} +.glyphicons-icon.log_book { + background-position: -332px -373px; +} +.glyphicons-icon.address_book { + background-position: -380px -373px; +} +.glyphicons-icon.building { + background-position: -428px -373px; +} +.glyphicons-icon.eyedropper { + background-position: 4px -421px; +} +.glyphicons-icon.adjust { + background-position: -44px -421px; +} +.glyphicons-icon.tint { + background-position: -92px -421px; +} +.glyphicons-icon.crop { + background-position: -140px -421px; +} +.glyphicons-icon.vector_path_square { + background-position: -188px -421px; +} +.glyphicons-icon.vector_path_circle { + background-position: -236px -421px; +} +.glyphicons-icon.vector_path_polygon { + background-position: -284px -421px; +} +.glyphicons-icon.vector_path_line { + background-position: -332px -421px; +} +.glyphicons-icon.vector_path_curve { + background-position: -380px -421px; +} +.glyphicons-icon.vector_path_all { + background-position: -428px -421px; +} +.glyphicons-icon.font { + background-position: 4px -469px; +} +.glyphicons-icon.italic { + background-position: -44px -469px; +} +.glyphicons-icon.bold { + background-position: -92px -469px; +} +.glyphicons-icon.text_underline { + background-position: -140px -469px; +} +.glyphicons-icon.text_strike { + background-position: -188px -469px; +} +.glyphicons-icon.text_height { + background-position: -236px -469px; +} +.glyphicons-icon.text_width { + background-position: -284px -469px; +} +.glyphicons-icon.text_resize { + background-position: -332px -469px; +} +.glyphicons-icon.left_indent { + background-position: -380px -469px; +} +.glyphicons-icon.right_indent { + background-position: -428px -469px; +} +.glyphicons-icon.align_left { + background-position: 4px -517px; +} +.glyphicons-icon.align_center { + background-position: -44px -517px; +} +.glyphicons-icon.align_right { + background-position: -92px -517px; +} +.glyphicons-icon.justify { + background-position: -140px -517px; +} +.glyphicons-icon.list { + background-position: -188px -517px; +} +.glyphicons-icon.text_smaller { + background-position: -236px -517px; +} +.glyphicons-icon.text_bigger { + background-position: -284px -517px; +} +.glyphicons-icon.embed { + background-position: -332px -517px; +} +.glyphicons-icon.embed_close { + background-position: -380px -517px; +} +.glyphicons-icon.table { + background-position: -428px -517px; +} +.glyphicons-icon.message_full { + background-position: 4px -565px; +} +.glyphicons-icon.message_empty { + background-position: -44px -565px; +} +.glyphicons-icon.message_in { + background-position: -92px -565px; +} +.glyphicons-icon.message_out { + background-position: -140px -565px; +} +.glyphicons-icon.message_plus { + background-position: -188px -565px; +} +.glyphicons-icon.message_minus { + background-position: -236px -565px; +} +.glyphicons-icon.message_ban { + background-position: -284px -565px; +} +.glyphicons-icon.message_flag { + background-position: -332px -565px; +} +.glyphicons-icon.message_lock { + background-position: -380px -565px; +} +.glyphicons-icon.message_new { + background-position: -428px -565px; +} +.glyphicons-icon.inbox { + background-position: 4px -613px; +} +.glyphicons-icon.inbox_plus { + background-position: -44px -613px; +} +.glyphicons-icon.inbox_minus { + background-position: -92px -613px; +} +.glyphicons-icon.inbox_lock { + background-position: -140px -613px; +} +.glyphicons-icon.inbox_in { + background-position: -188px -613px; +} +.glyphicons-icon.inbox_out { + background-position: -236px -613px; +} +.glyphicons-icon.cogwheel { + background-position: -284px -613px; +} +.glyphicons-icon.cogwheels { + background-position: -332px -613px; +} +.glyphicons-icon.picture { + background-position: -380px -613px; +} +.glyphicons-icon.adjust_alt { + background-position: -428px -613px; +} +.glyphicons-icon.database_lock { + background-position: 4px -661px; +} +.glyphicons-icon.database_plus { + background-position: -44px -661px; +} +.glyphicons-icon.database_minus { + background-position: -92px -661px; +} +.glyphicons-icon.database_ban { + background-position: -140px -661px; +} +.glyphicons-icon.folder_open { + background-position: -188px -661px; +} +.glyphicons-icon.folder_plus { + background-position: -236px -661px; +} +.glyphicons-icon.folder_minus { + background-position: -284px -661px; +} +.glyphicons-icon.folder_lock { + background-position: -332px -661px; +} +.glyphicons-icon.folder_flag { + background-position: -380px -661px; +} +.glyphicons-icon.folder_new { + background-position: -428px -661px; +} +.glyphicons-icon.edit { + background-position: 4px -709px; +} +.glyphicons-icon.new_window { + background-position: -44px -709px; +} +.glyphicons-icon.check { + background-position: -92px -709px; +} +.glyphicons-icon.unchecked { + background-position: -140px -709px; +} +.glyphicons-icon.more_windows { + background-position: -188px -709px; +} +.glyphicons-icon.show_big_thumbnails { + background-position: -236px -709px; +} +.glyphicons-icon.show_thumbnails { + background-position: -284px -709px; +} +.glyphicons-icon.show_thumbnails_with_lines { + background-position: -332px -709px; +} +.glyphicons-icon.show_lines { + background-position: -380px -709px; +} +.glyphicons-icon.playlist { + background-position: -428px -709px; +} +.glyphicons-icon.imac { + background-position: 4px -757px; +} +.glyphicons-icon.macbook { + background-position: -44px -757px; +} +.glyphicons-icon.ipad { + background-position: -92px -757px; +} +.glyphicons-icon.iphone { + background-position: -140px -757px; +} +.glyphicons-icon.iphone_transfer { + background-position: -188px -757px; +} +.glyphicons-icon.iphone_exchange { + background-position: -236px -757px; +} +.glyphicons-icon.ipod { + background-position: -284px -757px; +} +.glyphicons-icon.ipod_shuffle { + background-position: -332px -757px; +} +.glyphicons-icon.ear_plugs { + background-position: -380px -757px; +} +.glyphicons-icon.record { + background-position: -428px -757px; +} +.glyphicons-icon.step_backward { + background-position: 4px -805px; +} +.glyphicons-icon.fast_backward { + background-position: -44px -805px; +} +.glyphicons-icon.rewind { + background-position: -92px -805px; +} +.glyphicons-icon.play { + background-position: -140px -805px; +} +.glyphicons-icon.pause { + background-position: -188px -805px; +} +.glyphicons-icon.stop { + background-position: -236px -805px; +} +.glyphicons-icon.forward { + background-position: -284px -805px; +} +.glyphicons-icon.fast_forward { + background-position: -332px -805px; +} +.glyphicons-icon.step_forward { + background-position: -380px -805px; +} +.glyphicons-icon.eject { + background-position: -428px -805px; +} +.glyphicons-icon.facetime_video { + background-position: 4px -853px; +} +.glyphicons-icon.download_alt { + background-position: -44px -853px; +} +.glyphicons-icon.mute { + background-position: -92px -853px; +} +.glyphicons-icon.volume_down { + background-position: -140px -853px; +} +.glyphicons-icon.volume_up { + background-position: -188px -853px; +} +.glyphicons-icon.screenshot { + background-position: -236px -853px; +} +.glyphicons-icon.move { + background-position: -284px -853px; +} +.glyphicons-icon.more { + background-position: -332px -853px; +} +.glyphicons-icon.brightness_reduce { + background-position: -380px -853px; +} +.glyphicons-icon.brightness_increase { + background-position: -428px -853px; +} +.glyphicons-icon.circle_plus { + background-position: 4px -901px; +} +.glyphicons-icon.circle_minus { + background-position: -44px -901px; +} +.glyphicons-icon.circle_remove { + background-position: -92px -901px; +} +.glyphicons-icon.circle_ok { + background-position: -140px -901px; +} +.glyphicons-icon.circle_question_mark { + background-position: -188px -901px; +} +.glyphicons-icon.circle_info { + background-position: -236px -901px; +} +.glyphicons-icon.circle_exclamation_mark { + background-position: -284px -901px; +} +.glyphicons-icon.remove { + background-position: -332px -901px; +} +.glyphicons-icon.ok { + background-position: -380px -901px; +} +.glyphicons-icon.ban { + background-position: -428px -901px; +} +.glyphicons-icon.download { + background-position: 4px -949px; +} +.glyphicons-icon.upload { + background-position: -44px -949px; +} +.glyphicons-icon.shopping_cart { + background-position: -92px -949px; +} +.glyphicons-icon.lock { + background-position: -140px -949px; +} +.glyphicons-icon.unlock { + background-position: -188px -949px; +} +.glyphicons-icon.electricity { + background-position: -236px -949px; +} +.glyphicons-icon.ok_2 { + background-position: -284px -949px; +} +.glyphicons-icon.remove_2 { + background-position: -332px -949px; +} +.glyphicons-icon.cart_out { + background-position: -380px -949px; +} +.glyphicons-icon.cart_in { + background-position: -428px -949px; +} +.glyphicons-icon.left_arrow { + background-position: 4px -997px; +} +.glyphicons-icon.right_arrow { + background-position: -44px -997px; +} +.glyphicons-icon.down_arrow { + background-position: -92px -997px; +} +.glyphicons-icon.up_arrow { + background-position: -140px -997px; +} +.glyphicons-icon.resize_small { + background-position: -188px -997px; +} +.glyphicons-icon.resize_full { + background-position: -236px -997px; +} +.glyphicons-icon.circle_arrow_left { + background-position: -284px -997px; +} +.glyphicons-icon.circle_arrow_right { + background-position: -332px -997px; +} +.glyphicons-icon.circle_arrow_top { + background-position: -380px -997px; +} +.glyphicons-icon.circle_arrow_down { + background-position: -428px -997px; +} +.glyphicons-icon.play_button { + background-position: 4px -1045px; +} +.glyphicons-icon.unshare { + background-position: -44px -1045px; +} +.glyphicons-icon.share { + background-position: -92px -1045px; +} +.glyphicons-icon.chevron-right { + background-position: -140px -1045px; +} +.glyphicons-icon.chevron-left { + background-position: -188px -1045px; +} +.glyphicons-icon.bluetooth { + background-position: -236px -1045px; +} +.glyphicons-icon.euro { + background-position: -284px -1045px; +} +.glyphicons-icon.usd { + background-position: -332px -1045px; +} +.glyphicons-icon.gbp { + background-position: -380px -1045px; +} +.glyphicons-icon.retweet_2 { + background-position: -428px -1045px; +} +.glyphicons-icon.moon { + background-position: 4px -1093px; +} +.glyphicons-icon.sun { + background-position: -44px -1093px; +} +.glyphicons-icon.cloud { + background-position: -92px -1093px; +} +.glyphicons-icon.direction { + background-position: -140px -1093px; +} +.glyphicons-icon.brush { + background-position: -188px -1093px; +} +.glyphicons-icon.pen { + background-position: -236px -1093px; +} +.glyphicons-icon.zoom_in { + background-position: -284px -1093px; +} +.glyphicons-icon.zoom_out { + background-position: -332px -1093px; +} +.glyphicons-icon.pin { + background-position: -380px -1093px; +} +.glyphicons-icon.albums { + background-position: -428px -1093px; +} +.glyphicons-icon.rotation_lock { + background-position: 4px -1141px; +} +.glyphicons-icon.flash { + background-position: -44px -1141px; +} +.glyphicons-icon.google_maps { + background-position: -92px -1141px; +} +.glyphicons-icon.anchor { + background-position: -140px -1141px; +} +.glyphicons-icon.conversation { + background-position: -188px -1141px; +} +.glyphicons-icon.chat { + background-position: -236px -1141px; +} +.glyphicons-icon.male { + background-position: -284px -1141px; +} +.glyphicons-icon.female { + background-position: -332px -1141px; +} +.glyphicons-icon.asterisk { + background-position: -380px -1141px; +} +.glyphicons-icon.divide { + background-position: -428px -1141px; +} +.glyphicons-icon.snorkel_diving { + background-position: 4px -1189px; +} +.glyphicons-icon.scuba_diving { + background-position: -44px -1189px; +} +.glyphicons-icon.oxygen_bottle { + background-position: -92px -1189px; +} +.glyphicons-icon.fins { + background-position: -140px -1189px; +} +.glyphicons-icon.fishes { + background-position: -188px -1189px; +} +.glyphicons-icon.boat { + background-position: -236px -1189px; +} +.glyphicons-icon.delete { + background-position: -284px -1189px; +} +.glyphicons-icon.sheriffs_star { + background-position: -332px -1189px; +} +.glyphicons-icon.qrcode { + background-position: -380px -1189px; +} +.glyphicons-icon.barcode { + background-position: -428px -1189px; +} +.glyphicons-icon.pool { + background-position: 4px -1237px; +} +.glyphicons-icon.buoy { + background-position: -44px -1237px; +} +.glyphicons-icon.spade { + background-position: -92px -1237px; +} +.glyphicons-icon.bank { + background-position: -140px -1237px; +} +.glyphicons-icon.vcard { + background-position: -188px -1237px; +} +.glyphicons-icon.electrical_plug { + background-position: -236px -1237px; +} +.glyphicons-icon.flag { + background-position: -284px -1237px; +} +.glyphicons-icon.credit_card { + background-position: -332px -1237px; +} +.glyphicons-icon.keyboard-wireless { + background-position: -380px -1237px; +} +.glyphicons-icon.keyboard-wired { + background-position: -428px -1237px; +} +.glyphicons-icon.shield { + background-position: 4px -1285px; +} +.glyphicons-icon.ring { + background-position: -44px -1285px; +} +.glyphicons-icon.cake { + background-position: -92px -1285px; +} +.glyphicons-icon.drink { + background-position: -140px -1285px; +} +.glyphicons-icon.beer { + background-position: -188px -1285px; +} +.glyphicons-icon.fast_food { + background-position: -236px -1285px; +} +.glyphicons-icon.cutlery { + background-position: -284px -1285px; +} +.glyphicons-icon.pizza { + background-position: -332px -1285px; +} +.glyphicons-icon.birthday_cake { + background-position: -380px -1285px; +} +.glyphicons-icon.tablet { + background-position: -428px -1285px; +} +.glyphicons-icon.settings { + background-position: 4px -1333px; +} +.glyphicons-icon.bullets { + background-position: -44px -1333px; +} +.glyphicons-icon.cardio { + background-position: -92px -1333px; +} +.glyphicons-icon.t-shirt { + background-position: -140px -1333px; +} +.glyphicons-icon.pants { + background-position: -188px -1333px; +} +.glyphicons-icon.sweater { + background-position: -236px -1333px; +} +.glyphicons-icon.fabric { + background-position: -284px -1333px; +} +.glyphicons-icon.leather { + background-position: -332px -1333px; +} +.glyphicons-icon.scissors { + background-position: -380px -1333px; +} +.glyphicons-icon.bomb { + background-position: -428px -1333px; +} +.glyphicons-icon.skull { + background-position: 4px -1381px; +} +.glyphicons-icon.celebration { + background-position: -44px -1381px; +} +.glyphicons-icon.tea_kettle { + background-position: -92px -1381px; +} +.glyphicons-icon.french_press { + background-position: -140px -1381px; +} +.glyphicons-icon.coffe_cup { + background-position: -188px -1381px; +} +.glyphicons-icon.pot { + background-position: -236px -1381px; +} +.glyphicons-icon.grater { + background-position: -284px -1381px; +} +.glyphicons-icon.kettle { + background-position: -332px -1381px; +} +.glyphicons-icon.hospital { + background-position: -380px -1381px; +} +.glyphicons-icon.hospital_h { + background-position: -428px -1381px; +} +.glyphicons-icon.microphone { + background-position: 4px -1429px; +} +.glyphicons-icon.webcam { + background-position: -44px -1429px; +} +.glyphicons-icon.temple_christianity_church { + background-position: -92px -1429px; +} +.glyphicons-icon.temple_islam { + background-position: -140px -1429px; +} +.glyphicons-icon.temple_hindu { + background-position: -188px -1429px; +} +.glyphicons-icon.temple_buddhist { + background-position: -236px -1429px; +} +.glyphicons-icon.bicycle { + background-position: -284px -1429px; +} +.glyphicons-icon.life_preserver { + background-position: -332px -1429px; +} +.glyphicons-icon.share_alt { + background-position: -380px -1429px; +} +.glyphicons-icon.comments { + background-position: -428px -1429px; +} +.glyphicons-icon.flower { + background-position: 4px -1477px; +} +.glyphicons-icon.baseball { + background-position: -44px -1477px; +} +.glyphicons-icon.rugby { + background-position: -92px -1477px; +} +.glyphicons-icon.ax { + background-position: -140px -1477px; +} +.glyphicons-icon.table_tennis { + background-position: -188px -1477px; +} +.glyphicons-icon.bowling { + background-position: -236px -1477px; +} +.glyphicons-icon.tree_conifer { + background-position: -284px -1477px; +} +.glyphicons-icon.tree_deciduous { + background-position: -332px -1477px; +} +.glyphicons-icon.more_items { + background-position: -380px -1477px; +} +.glyphicons-icon.sort { + background-position: -428px -1477px; +} +.glyphicons-icon.filter { + background-position: 4px -1525px; +} +.glyphicons-icon.gamepad { + background-position: -44px -1525px; +} +.glyphicons-icon.playing_dices { + background-position: -92px -1525px; +} +.glyphicons-icon.calculator { + background-position: -140px -1525px; +} +.glyphicons-icon.tie { + background-position: -188px -1525px; +} +.glyphicons-icon.wallet { + background-position: -236px -1525px; +} +.glyphicons-icon.piano { + background-position: -284px -1525px; +} +.glyphicons-icon.sampler { + background-position: -332px -1525px; +} +.glyphicons-icon.podium { + background-position: -380px -1525px; +} +.glyphicons-icon.soccer_ball { + background-position: -428px -1525px; +} +.glyphicons-icon.blog { + background-position: 4px -1573px; +} +.glyphicons-icon.dashboard { + background-position: -44px -1573px; +} +.glyphicons-icon.certificate { + background-position: -92px -1573px; +} +.glyphicons-icon.bell { + background-position: -140px -1573px; +} +.glyphicons-icon.candle { + background-position: -188px -1573px; +} +.glyphicons-icon.pushpin { + background-position: -236px -1573px; +} +.glyphicons-icon.iphone_shake { + background-position: -284px -1573px; +} +.glyphicons-icon.pin_flag { + background-position: -332px -1573px; +} +.glyphicons-icon.turtle { + background-position: -380px -1573px; +} +.glyphicons-icon.rabbit { + background-position: -428px -1573px; +} +.glyphicons-icon.globe { + background-position: 4px -1621px; +} +.glyphicons-icon.briefcase { + background-position: -44px -1621px; +} +.glyphicons-icon.hdd { + background-position: -92px -1621px; +} +.glyphicons-icon.thumbs_up { + background-position: -140px -1621px; +} +.glyphicons-icon.thumbs_down { + background-position: -188px -1621px; +} +.glyphicons-icon.hand_right { + background-position: -236px -1621px; +} +.glyphicons-icon.hand_left { + background-position: -284px -1621px; +} +.glyphicons-icon.hand_up { + background-position: -332px -1621px; +} +.glyphicons-icon.hand_down { + background-position: -380px -1621px; +} +.glyphicons-icon.fullscreen { + background-position: -428px -1621px; +} +.glyphicons-icon.shopping_bag { + background-position: 4px -1669px; +} +.glyphicons-icon.book_open { + background-position: -44px -1669px; +} +.glyphicons-icon.nameplate { + background-position: -92px -1669px; +} +.glyphicons-icon.nameplate_alt { + background-position: -140px -1669px; +} +.glyphicons-icon.vases { + background-position: -188px -1669px; +} +.glyphicons-icon.bullhorn { + background-position: -236px -1669px; +} +.glyphicons-icon.dumbbell { + background-position: -284px -1669px; +} +.glyphicons-icon.suitcase { + background-position: -332px -1669px; +} +.glyphicons-icon.file_import { + background-position: -380px -1669px; +} +.glyphicons-icon.file_export { + background-position: -428px -1669px; +} +.glyphicons-icon.bug { + background-position: 4px -1717px; +} +.glyphicons-icon.crown { + background-position: -44px -1717px; +} +.glyphicons-icon.smoking { + background-position: -92px -1717px; +} +.glyphicons-icon.cloud-upload { + background-position: -140px -1717px; +} +.glyphicons-icon.cloud-download { + background-position: -188px -1717px; +} +.glyphicons-icon.restart { + background-position: -236px -1717px; +} +.glyphicons-icon.security_camera { + background-position: -284px -1717px; +} +.glyphicons-icon.expand { + background-position: -332px -1717px; +} +.glyphicons-icon.collapse { + background-position: -380px -1717px; +} +.glyphicons-icon.collapse_top { + background-position: -428px -1717px; +} +.glyphicons-icon.globe_af { + background-position: 4px -1765px; +} +.glyphicons-icon.global { + background-position: -44px -1765px; +} +.glyphicons-icon.spray { + background-position: -92px -1765px; +} +.glyphicons-icon.nails { + background-position: -140px -1765px; +} +.glyphicons-icon.claw_hammer { + background-position: -188px -1765px; +} +.glyphicons-icon.classic_hammer { + background-position: -236px -1765px; +} +.glyphicons-icon.hand_saw { + background-position: -284px -1765px; +} +.glyphicons-icon.riflescope { + background-position: -332px -1765px; +} +.glyphicons-icon.electrical_socket_eu { + background-position: -380px -1765px; +} +.glyphicons-icon.electrical_socket_us { + background-position: -428px -1765px; +} +.glyphicons-icon.message_forward { + background-position: 4px -1813px; +} +.glyphicons-icon.coat_hanger { + background-position: -44px -1813px; +} +.glyphicons-icon.dress { + background-position: -92px -1813px; +} +.glyphicons-icon.bathrobe { + background-position: -140px -1813px; +} +.glyphicons-icon.shirt { + background-position: -188px -1813px; +} +.glyphicons-icon.underwear { + background-position: -236px -1813px; +} +.glyphicons-icon.log_in { + background-position: -284px -1813px; +} +.glyphicons-icon.log_out { + background-position: -332px -1813px; +} +.glyphicons-icon.exit { + background-position: -380px -1813px; +} +.glyphicons-icon.new_window_alt { + background-position: -428px -1813px; +} +.glyphicons-icon.video_sd { + background-position: 4px -1861px; +} +.glyphicons-icon.video_hd { + background-position: -44px -1861px; +} +.glyphicons-icon.subtitles { + background-position: -92px -1861px; +} +.glyphicons-icon.sound_stereo { + background-position: -140px -1861px; +} +.glyphicons-icon.sound_dolby { + background-position: -188px -1861px; +} +.glyphicons-icon.sound_5_1 { + background-position: -236px -1861px; +} +.glyphicons-icon.sound_6_1 { + background-position: -284px -1861px; +} +.glyphicons-icon.sound_7_1 { + background-position: -332px -1861px; +} +.glyphicons-icon.copyright_mark { + background-position: -380px -1861px; +} +.glyphicons-icon.registration_mark { + background-position: -428px -1861px; +} +.glyphicons-icon.radar { + background-position: 4px -1909px; +} +.glyphicons-icon.skateboard { + background-position: -44px -1909px; +} +.glyphicons-icon.golf_course { + background-position: -92px -1909px; +} +.glyphicons-icon.sorting { + background-position: -140px -1909px; +} +.glyphicons-icon.sort-by-alphabet { + background-position: -188px -1909px; +} +.glyphicons-icon.sort-by-alphabet-alt { + background-position: -236px -1909px; +} +.glyphicons-icon.sort-by-order { + background-position: -284px -1909px; +} +.glyphicons-icon.sort-by-order-alt { + background-position: -332px -1909px; +} +.glyphicons-icon.sort-by-attributes { + background-position: -380px -1909px; +} +.glyphicons-icon.sort-by-attributes-alt { + background-position: -428px -1909px; +} +.glyphicons-icon.compressed { + background-position: 4px -1957px; +} +.glyphicons-icon.package { + background-position: -44px -1957px; +} +.glyphicons-icon.cloud_plus { + background-position: -92px -1957px; +} +.glyphicons-icon.cloud_minus { + background-position: -140px -1957px; +} +.glyphicons-icon.disk_save { + background-position: -188px -1957px; +} +.glyphicons-icon.disk_open { + background-position: -236px -1957px; +} +.glyphicons-icon.disk_saved { + background-position: -284px -1957px; +} +.glyphicons-icon.disk_remove { + background-position: -332px -1957px; +} +.glyphicons-icon.disk_import { + background-position: -380px -1957px; +} +.glyphicons-icon.disk_export { + background-position: -428px -1957px; +} +.glyphicons-icon.tower { + background-position: 4px -2005px; +} +.glyphicons-icon.send { + background-position: -44px -2005px; +} +.glyphicons-icon.git_branch { + background-position: -92px -2005px; +} +.glyphicons-icon.git_create { + background-position: -140px -2005px; +} +.glyphicons-icon.git_private { + background-position: -188px -2005px; +} +.glyphicons-icon.git_delete { + background-position: -236px -2005px; +} +.glyphicons-icon.git_merge { + background-position: -284px -2005px; +} +.glyphicons-icon.git_pull_request { + background-position: -332px -2005px; +} +.glyphicons-icon.git_compare { + background-position: -380px -2005px; +} +.glyphicons-icon.git_commit { + background-position: -428px -2005px; +} +.glyphicons-icon.construction_cone { + background-position: 4px -2053px; +} +.glyphicons-icon.shoe_steps { + background-position: -44px -2053px; +} +.glyphicons-icon.plus { + background-position: -92px -2053px; +} +.glyphicons-icon.minus { + background-position: -140px -2053px; +} +.glyphicons-icon.redo { + background-position: -188px -2053px; +} +.glyphicons-icon.undo { + background-position: -236px -2053px; +} +.glyphicons-icon.golf { + background-position: -284px -2053px; +} +.glyphicons-icon.hockey { + background-position: -332px -2053px; +} +.glyphicons-icon.pipe { + background-position: -380px -2053px; +} +.glyphicons-icon.wrench { + background-position: -428px -2053px; +} +.glyphicons-icon.folder_closed { + background-position: 4px -2101px; +} +.glyphicons-icon.phone_alt { + background-position: -44px -2101px; +} +.glyphicons-icon.earphone { + background-position: -92px -2101px; +} +.glyphicons-icon.floppy_disk { + background-position: -140px -2101px; +} +.glyphicons-icon.floppy_saved { + background-position: -188px -2101px; +} +.glyphicons-icon.floppy_remove { + background-position: -236px -2101px; +} +.glyphicons-icon.floppy_save { + background-position: -284px -2101px; +} +.glyphicons-icon.floppy_open { + background-position: -332px -2101px; +} +.glyphicons-icon.translate { + background-position: -380px -2101px; +} +.glyphicons-icon.fax { + background-position: -428px -2101px; +} +.glyphicons-icon.factory { + background-position: 4px -2149px; +} +.glyphicons-icon.shop_window { + background-position: -44px -2149px; +} +.glyphicons-icon.shop { + background-position: -92px -2149px; +} +.glyphicons-icon.kiosk { + background-position: -140px -2149px; +} +.glyphicons-icon.kiosk_wheels { + background-position: -188px -2149px; +} +.glyphicons-icon.kiosk_light { + background-position: -236px -2149px; +} +.glyphicons-icon.kiosk_food { + background-position: -284px -2149px; +} +.glyphicons-icon.transfer { + background-position: -332px -2149px; +} +.glyphicons-icon.money { + background-position: -380px -2149px; +} +.glyphicons-icon.header { + background-position: -428px -2149px; +} +.glyphicons-icon.blacksmith { + background-position: 4px -2197px; +} +.glyphicons-icon.saw_blade { + background-position: -44px -2197px; +} +.glyphicons-icon.basketball { + background-position: -92px -2197px; +} +.glyphicons-icon.server { + background-position: -140px -2197px; +} +.glyphicons-icon.server_plus { + background-position: -188px -2197px; +} +.glyphicons-icon.server_minus { + background-position: -236px -2197px; +} +.glyphicons-icon.server_ban { + background-position: -284px -2197px; +} +.glyphicons-icon.server_flag { + background-position: -332px -2197px; +} +.glyphicons-icon.server_lock { + background-position: -380px -2197px; +} +.glyphicons-icon.server_new { + background-position: -428px -2197px; +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/halflings.css b/gridplatform/bootstrap/static/bootstrap/genius/css/halflings.css new file mode 100644 index 0000000..b413794 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/halflings.css @@ -0,0 +1,1259 @@ +/*! + * + * Project: GLYPHICONS HALFLINGS + * Author: Jan Kovarik - www.glyphicons.com + * Twitter: @glyphicons + * + */ +@font-face { + font-family: 'Glyphicons Halflings Regular'; + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), 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'); + font-weight: normal; + font-style: normal; +} +.halflings { + display: inline-block; + position: relative; + padding-left: 25px; + color: #1d1d1b; + text-decoration: none; + *display: inline; + *zoom: 1; + vertical-align: middle; +} +.halflings:before { + position: absolute; + left: 0; + top: 0; + display: inline-block; + margin: 0 5px 0 0; + font: 12px/1em 'Glyphicons Halflings Regular'; + font-style: normal; + font-weight: normal; + color: #1d1d1b; + *display: inline; + *zoom: 1; + vertical-align: middle; + text-transform: none; + -webkit-font-smoothing: antialiased; +} +.halflings.white:before { + color: #fff; +} +.halflings.glass:before { + content: "\E001"; +} +.halflings.music:before { + content: "\E002"; +} +.halflings.search:before { + content: "\E003"; +} +.halflings.envelope:before { + content: "\2709"; +} +.halflings.heart:before { + content: "\E005"; +} +.halflings.star:before { + content: "\E006"; +} +.halflings.star-empty:before { + content: "\E007"; +} +.halflings.user:before { + content: "\E008"; +} +.halflings.film:before { + content: "\E009"; +} +.halflings.th-large:before { + content: "\E010"; +} +.halflings.th:before { + content: "\E011"; +} +.halflings.th-list:before { + content: "\E012"; +} +.halflings.ok:before { + content: "\E013"; +} +.halflings.remove:before { + content: "\E014"; +} +.halflings.zoom-in:before { + content: "\E015"; +} +.halflings.zoom-out:before { + content: "\E016"; +} +.halflings.off:before { + content: "\E017"; +} +.halflings.signal:before { + content: "\E018"; +} +.halflings.cog:before { + content: "\E019"; +} +.halflings.trash:before { + content: "\E020"; +} +.halflings.home:before { + content: "\E021"; +} +.halflings.file:before { + content: "\E022"; +} +.halflings.time:before { + content: "\E023"; +} +.halflings.road:before { + content: "\E024"; +} +.halflings.download-alt:before { + content: "\E025"; +} +.halflings.download:before { + content: "\E026"; +} +.halflings.upload:before { + content: "\E027"; +} +.halflings.inbox:before { + content: "\E028"; +} +.halflings.play-circle:before { + content: "\E029"; +} +.halflings.repeat:before { + content: "\E030"; +} +.halflings.refresh:before { + content: "\E031"; +} +.halflings.list-alt:before { + content: "\E032"; +} +.halflings.lock:before { + content: "\1F512"; +} +.halflings.flag:before { + content: "\E034"; +} +.halflings.headphones:before { + content: "\E035"; +} +.halflings.volume-off:before { + content: "\E036"; +} +.halflings.volume-down:before { + content: "\E037"; +} +.halflings.volume-up:before { + content: "\E038"; +} +.halflings.qrcode:before { + content: "\E039"; +} +.halflings.barcode:before { + content: "\E040"; +} +.halflings.tag:before { + content: "\E041"; +} +.halflings.tags:before { + content: "\E042"; +} +.halflings.book:before { + content: "\E043"; +} +.halflings.bookmark:before { + content: "\1F516"; +} +.halflings.print:before { + content: "\E045"; +} +.halflings.camera:before { + content: "\1F4F7"; +} +.halflings.font:before { + content: "\E047"; +} +.halflings.bold:before { + content: "\E048"; +} +.halflings.italic:before { + content: "\E049"; +} +.halflings.text-height:before { + content: "\E050"; +} +.halflings.text-width:before { + content: "\E051"; +} +.halflings.align-left:before { + content: "\E052"; +} +.halflings.align-center:before { + content: "\E053"; +} +.halflings.align-right:before { + content: "\E054"; +} +.halflings.align-justify:before { + content: "\E055"; +} +.halflings.list:before { + content: "\E056"; +} +.halflings.indent-left:before { + content: "\E057"; +} +.halflings.indent-right:before { + content: "\E058"; +} +.halflings.facetime-video:before { + content: "\E059"; +} +.halflings.picture:before { + content: "\E060"; +} +.halflings.pencil:before { + content: "\270F"; +} +.halflings.map-marker:before { + content: "\E062"; +} +.halflings.adjust:before { + content: "\E063"; +} +.halflings.tint:before { + content: "\E064"; +} +.halflings.edit:before { + content: "\E065"; +} +.halflings.share:before { + content: "\E066"; +} +.halflings.check:before { + content: "\E067"; +} +.halflings.move:before { + content: "\E068"; +} +.halflings.step-backward:before { + content: "\E069"; +} +.halflings.fast-backward:before { + content: "\E070"; +} +.halflings.backward:before { + content: "\E071"; +} +.halflings.play:before { + content: "\E072"; +} +.halflings.pause:before { + content: "\E073"; +} +.halflings.stop:before { + content: "\E074"; +} +.halflings.forward:before { + content: "\E075"; +} +.halflings.fast-forward:before { + content: "\E076"; +} +.halflings.step-forward:before { + content: "\E077"; +} +.halflings.eject:before { + content: "\E078"; +} +.halflings.chevron-left:before { + content: "\E079"; +} +.halflings.chevron-right:before { + content: "\E080"; +} +.halflings.plus-sign:before { + content: "\E081"; +} +.halflings.minus-sign:before { + content: "\E082"; +} +.halflings.remove-sign:before { + content: "\E083"; +} +.halflings.ok-sign:before { + content: "\E084"; +} +.halflings.question-sign:before { + content: "\E085"; +} +.halflings.info-sign:before { + content: "\E086"; +} +.halflings.screenshot:before { + content: "\E087"; +} +.halflings.remove-circle:before { + content: "\E088"; +} +.halflings.ok-circle:before { + content: "\E089"; +} +.halflings.ban-circle:before { + content: "\E090"; +} +.halflings.arrow-left:before { + content: "\E091"; +} +.halflings.arrow-right:before { + content: "\E092"; +} +.halflings.arrow-up:before { + content: "\E093"; +} +.halflings.arrow-down:before { + content: "\E094"; +} +.halflings.share-alt:before { + content: "\E095"; +} +.halflings.resize-full:before { + content: "\E096"; +} +.halflings.resize-small:before { + content: "\E097"; +} +.halflings.plus:before { + content: "\002B"; +} +.halflings.minus:before { + content: "\2212"; +} +.halflings.asterisk:before { + content: "\002A"; +} +.halflings.exclamation-sign:before { + content: "\E101"; +} +.halflings.gift:before { + content: "\E102"; +} +.halflings.leaf:before { + content: "\E103"; +} +.halflings.fire:before { + content: "\1F525"; +} +.halflings.eye-open:before { + content: "\E105"; +} +.halflings.eye-close:before { + content: "\E106"; +} +.halflings.warning-sign:before { + content: "\E107"; +} +.halflings.plane:before { + content: "\E108"; +} +.halflings.calendar:before { + content: "\1F4C5"; +} +.halflings.random:before { + content: "\E110"; +} +.halflings.comments:before { + content: "\E111"; +} +.halflings.magnet:before { + content: "\E112"; +} +.halflings.chevron-up:before { + content: "\E113"; +} +.halflings.chevron-down:before { + content: "\E114"; +} +.halflings.retweet:before { + content: "\E115"; +} +.halflings.shopping-cart:before { + content: "\E116"; +} +.halflings.folder-close:before { + content: "\E117"; +} +.halflings.folder-open:before { + content: "\E118"; +} +.halflings.resize-vertical:before { + content: "\E119"; +} +.halflings.resize-horizontal:before { + content: "\E120"; +} +.halflings.hdd:before { + content: "\E121"; +} +.halflings.bullhorn:before { + content: "\E122"; +} +.halflings.bell:before { + content: "\1F514"; +} +.halflings.certificate:before { + content: "\E124"; +} +.halflings.thumbs-up:before { + content: "\E125"; +} +.halflings.thumbs-down:before { + content: "\E126"; +} +.halflings.hand-right:before { + content: "\E127"; +} +.halflings.hand-left:before { + content: "\E128"; +} +.halflings.hand-top:before { + content: "\E129"; +} +.halflings.hand-down:before { + content: "\E130"; +} +.halflings.circle-arrow-right:before { + content: "\E131"; +} +.halflings.circle-arrow-left:before { + content: "\E132"; +} +.halflings.circle-arrow-top:before { + content: "\E133"; +} +.halflings.circle-arrow-down:before { + content: "\E134"; +} +.halflings.globe:before { + content: "\E135"; +} +.halflings.wrench:before { + content: "\1F527"; +} +.halflings.tasks:before { + content: "\E137"; +} +.halflings.filter:before { + content: "\E138"; +} +.halflings.briefcase:before { + content: "\1F4BC"; +} +.halflings.fullscreen:before { + content: "\E140"; +} +.halflings.dashboard:before { + content: "\E141"; +} +.halflings.paperclip:before { + content: "\1F4CE"; +} +.halflings.heart-empty:before { + content: "\E143"; +} +.halflings.link:before { + content: "\E144"; +} +.halflings.phone:before { + content: "\E145"; +} +.halflings.pushpin:before { + content: "\1F4CC"; +} +.halflings.euro:before { + content: "\20AC"; +} +.halflings.usd:before { + content: "\E148"; +} +.halflings.gbp:before { + content: "\E149"; +} +.halflings.sort:before { + content: "\E150"; +} +.halflings.sort-by-alphabet:before { + content: "\E151"; +} +.halflings.sort-by-alphabet-alt:before { + content: "\E152"; +} +.halflings.sort-by-order:before { + content: "\E153"; +} +.halflings.sort-by-order-alt:before { + content: "\E154"; +} +.halflings.sort-by-attributes:before { + content: "\E155"; +} +.halflings.sort-by-attributes-alt:before { + content: "\E156"; +} +.halflings.unchecked:before { + content: "\E157"; +} +.halflings.expand:before { + content: "\E158"; +} +.halflings.collapse:before { + content: "\E159"; +} +.halflings.collapse-top:before { + content: "\E160"; +} +.halflings.log_in:before { + content: "\E161"; +} +.halflings.flash:before { + content: "\E162"; +} +.halflings.log_out:before { + content: "\E163"; +} +.halflings.new_window:before { + content: "\E164"; +} +.halflings.record:before { + content: "\E165"; +} +.halflings.save:before { + content: "\E166"; +} +.halflings.open:before { + content: "\E167"; +} +.halflings.saved:before { + content: "\E168"; +} +.halflings.import:before { + content: "\E169"; +} +.halflings.export:before { + content: "\E170"; +} +.halflings.send:before { + content: "\E171"; +} +.halflings.floppy_disk:before { + content: "\E172"; +} +.halflings.floppy_saved:before { + content: "\E173"; +} +.halflings.floppy_remove:before { + content: "\E174"; +} +.halflings.floppy_save:before { + content: "\E175"; +} +.halflings.floppy_open:before { + content: "\E176"; +} +.halflings.credit_card:before { + content: "\E177"; +} +.halflings.transfer:before { + content: "\E178"; +} +.halflings.cutlery:before { + content: "\E179"; +} +.halflings.header:before { + content: "\E180"; +} +.halflings.compressed:before { + content: "\E181"; +} +.halflings.earphone:before { + content: "\E182"; +} +.halflings.phone_alt:before { + content: "\E183"; +} +.halflings.tower:before { + content: "\E184"; +} +.halflings.stats:before { + content: "\E185"; +} +.halflings.sd_video:before { + content: "\E186"; +} +.halflings.hd_video:before { + content: "\E187"; +} +.halflings.subtitles:before { + content: "\E188"; +} +.halflings.sound_stereo:before { + content: "\E189"; +} +.halflings.sound_dolby:before { + content: "\E190"; +} +.halflings.sound_5_1:before { + content: "\E191"; +} +.halflings.sound_6_1:before { + content: "\E192"; +} +.halflings.sound_7_1:before { + content: "\E193"; +} +.halflings.copyright_mark:before { + content: "\E194"; +} +.halflings.registration_mark:before { + content: "\E195"; +} +.halflings.cloud:before { + content: "\2601"; +} +.halflings.cloud_download:before { + content: "\E197"; +} +.halflings.cloud_upload:before { + content: "\E198"; +} +.halflings.tree_conifer:before { + content: "\E199"; +} +.halflings.tree_deciduous:before { + content: "\E200"; +} +.halflings-icon { + display: inline-block; + width: 14px; + height: 14px; + margin: 0 8px 0 0; + line-height: 14px; + vertical-align: text-top; + background-position: 0 0; + background-repeat: no-repeat; + vertical-align: top; + *display: inline; + *zoom: 1; + *margin-right: .3em; +} +.halflings-icon _:-o-prefocus, +.halflings-icon.white _:-o-prefocus, +.halflings-icon.glass { + background-position: 0px 0px; +} +.halflings-icon.music { + background-position: -24px 0px; +} +.halflings-icon.search { + background-position: -48px 0px; +} +.halflings-icon.envelope { + background-position: -72px 0px; +} +.halflings-icon.heart { + background-position: -96px 0px; +} +.halflings-icon.star { + background-position: -120px 0px; +} +.halflings-icon.star-empty { + background-position: -144px 0px; +} +.halflings-icon.user { + background-position: -168px 0px; +} +.halflings-icon.film { + background-position: -192px 0px; +} +.halflings-icon.th-large { + background-position: -216px 0px; +} +.halflings-icon.th { + background-position: -240px 0px; +} +.halflings-icon.th-list { + background-position: -264px 0px; +} +.halflings-icon.ok { + background-position: -288px 0px; +} +.halflings-icon.remove { + background-position: -312px 0px; +} +.halflings-icon.zoom-in { + background-position: -336px 0px; +} +.halflings-icon.zoom-out { + background-position: -360px 0px; +} +.halflings-icon.off { + background-position: -384px 0px; +} +.halflings-icon.signal { + background-position: -408px 0px; +} +.halflings-icon.cog { + background-position: -432px 0px; +} +.halflings-icon.trash { + background-position: -456px 0px; +} +.halflings-icon.home { + background-position: 0px -24px; +} +.halflings-icon.file { + background-position: -24px -24px; +} +.halflings-icon.time { + background-position: -48px -24px; +} +.halflings-icon.road { + background-position: -71px -24px; +} +.halflings-icon.download-alt { + background-position: -96px -24px; +} +.halflings-icon.download { + background-position: -120px -24px; +} +.halflings-icon.upload { + background-position: -144px -24px; +} +.halflings-icon.inbox { + background-position: -168px -24px; +} +.halflings-icon.play-circle { + background-position: -192px -24px; +} +.halflings-icon.repeat { + background-position: -216px -24px; +} +.halflings-icon.refresh { + background-position: -240px -24px; +} +.halflings-icon.list-alt { + background-position: -264px -24px; +} +.halflings-icon.lock { + background-position: -288px -24px; +} +.halflings-icon.flag { + background-position: -312px -24px; +} +.halflings-icon.headphones { + background-position: -336px -24px; +} +.halflings-icon.volume-off { + background-position: -360px -24px; +} +.halflings-icon.volume-down { + background-position: -384px -24px; +} +.halflings-icon.volume-up { + background-position: -408px -24px; +} +.halflings-icon.qrcode { + background-position: -432px -24px; +} +.halflings-icon.barcode { + background-position: -456px -24px; +} +.halflings-icon.tag { + background-position: 0px -48px; +} +.halflings-icon.tags { + background-position: -24px -48px; +} +.halflings-icon.book { + background-position: -48px -48px; +} +.halflings-icon.bookmark { + background-position: -72px -48px; +} +.halflings-icon.print { + background-position: -96px -48px; +} +.halflings-icon.camera { + background-position: -120px -48px; +} +.halflings-icon.font { + background-position: -144px -48px; +} +.halflings-icon.bold { + background-position: -168px -48px; +} +.halflings-icon.italic { + background-position: -192px -48px; +} +.halflings-icon.text-height { + background-position: -216px -48px; +} +.halflings-icon.text-width { + background-position: -240px -48px; +} +.halflings-icon.align-left { + background-position: -264px -48px; +} +.halflings-icon.align-center { + background-position: -288px -48px; +} +.halflings-icon.align-right { + background-position: -312px -48px; +} +.halflings-icon.align-justify { + background-position: -336px -48px; +} +.halflings-icon.list { + background-position: -360px -48px; +} +.halflings-icon.indent-left { + background-position: -384px -48px; +} +.halflings-icon.indent-right { + background-position: -408px -48px; +} +.halflings-icon.facetime-video { + background-position: -432px -48px; +} +.halflings-icon.picture { + background-position: -456px -48px; +} +.halflings-icon.pencil { + background-position: 0px -72px; +} +.halflings-icon.map-marker { + background-position: -24px -72px; +} +.halflings-icon.adjust { + background-position: -48px -72px; +} +.halflings-icon.tint { + background-position: -72px -72px; +} +.halflings-icon.edit { + background-position: -96px -72px; +} +.halflings-icon.share { + background-position: -120px -72px; +} +.halflings-icon.check { + background-position: -144px -72px; +} +.halflings-icon.move { + background-position: -168px -72px; +} +.halflings-icon.step-backward { + background-position: -192px -72px; +} +.halflings-icon.fast-backward { + background-position: -216px -72px; +} +.halflings-icon.backward { + background-position: -240px -72px; +} +.halflings-icon.play { + background-position: -264px -72px; +} +.halflings-icon.pause { + background-position: -288px -72px; +} +.halflings-icon.stop { + background-position: -312px -72px; +} +.halflings-icon.forward { + background-position: -336px -72px; +} +.halflings-icon.fast-forward { + background-position: -360px -72px; +} +.halflings-icon.step-forward { + background-position: -384px -72px; +} +.halflings-icon.eject { + background-position: -408px -72px; +} +.halflings-icon.chevron-left { + background-position: -432px -72px; +} +.halflings-icon.chevron-right { + background-position: -456px -72px; +} +.halflings-icon.plus-sign { + background-position: 0px -96px; +} +.halflings-icon.minus-sign { + background-position: -24px -96px; +} +.halflings-icon.remove-sign { + background-position: -48px -96px; +} +.halflings-icon.ok-sign { + background-position: -72px -96px; +} +.halflings-icon.question-sign { + background-position: -96px -96px; +} +.halflings-icon.info-sign { + background-position: -120px -96px; +} +.halflings-icon.screenshot { + background-position: -144px -96px; +} +.halflings-icon.remove-circle { + background-position: -168px -96px; +} +.halflings-icon.ok-circle { + background-position: -192px -96px; +} +.halflings-icon.ban-circle { + background-position: -216px -96px; +} +.halflings-icon.arrow-left { + background-position: -240px -96px; +} +.halflings-icon.arrow-right { + background-position: -264px -96px; +} +.halflings-icon.arrow-up { + background-position: -288px -96px; +} +.halflings-icon.arrow-down { + background-position: -312px -96px; +} +.halflings-icon.share-alt { + background-position: -336px -96px; +} +.halflings-icon.resize-full { + background-position: -360px -96px; +} +.halflings-icon.resize-small { + background-position: -384px -96px; +} +.halflings-icon.plus { + background-position: -408px -96px; +} +.halflings-icon.minus { + background-position: -432px -96px; +} +.halflings-icon.asterisk { + background-position: -456px -96px; +} +.halflings-icon.exclamation-sign { + background-position: 0px -120px; +} +.halflings-icon.gift { + background-position: -24px -120px; +} +.halflings-icon.leaf { + background-position: -48px -120px; +} +.halflings-icon.fire { + background-position: -72px -120px; +} +.halflings-icon.eye-open { + background-position: -95px -120px; +} +.halflings-icon.eye-close { + background-position: -119px -120px; +} +.halflings-icon.warning-sign { + background-position: -144px -120px; +} +.halflings-icon.plane { + background-position: -168px -120px; +} +.halflings-icon.calendar { + background-position: -192px -120px; +} +.halflings-icon.random { + background-position: -216px -120px; +} +.halflings-icon.comments { + background-position: -240px -120px; +} +.halflings-icon.magnet { + background-position: -264px -120px; +} +.halflings-icon.chevron-up { + background-position: -288px -120px; +} +.halflings-icon.chevron-down { + background-position: -312px -120px; +} +.halflings-icon.retweet { + background-position: -336px -120px; +} +.halflings-icon.shopping-cart { + background-position: -360px -120px; +} +.halflings-icon.folder-close { + background-position: -384px -120px; +} +.halflings-icon.folder-open { + background-position: -408px -120px; +} +.halflings-icon.resize-vertical { + background-position: -432px -120px; +} +.halflings-icon.resize-horizontal { + background-position: -456px -120px; +} +.halflings-icon.hdd { + background-position: 0px -144px; +} +.halflings-icon.bullhorn { + background-position: -24px -144px; +} +.halflings-icon.bell { + background-position: -48px -144px; +} +.halflings-icon.certificate { + background-position: -72px -144px; +} +.halflings-icon.thumbs-up { + background-position: -96px -144px; +} +.halflings-icon.thumbs-down { + background-position: -120px -144px; +} +.halflings-icon.hand-right { + background-position: -145px -144px; +} +.halflings-icon.hand-left { + background-position: -167px -144px; +} +.halflings-icon.hand-top { + background-position: -192px -144px; +} +.halflings-icon.hand-down { + background-position: -216px -144px; +} +.halflings-icon.circle-arrow-right { + background-position: -240px -144px; +} +.halflings-icon.circle-arrow-left { + background-position: -264px -144px; +} +.halflings-icon.circle-arrow-top { + background-position: -288px -144px; +} +.halflings-icon.circle-arrow-down { + background-position: -312px -144px; +} +.halflings-icon.globe { + background-position: -336px -144px; +} +.halflings-icon.wrench { + background-position: -360px -144px; +} +.halflings-icon.tasks { + background-position: -384px -144px; +} +.halflings-icon.filter { + background-position: -408px -144px; +} +.halflings-icon.briefcase { + background-position: -432px -144px; +} +.halflings-icon.fullscreen { + background-position: -456px -144px; +} +.halflings-icon.dashboard { + background-position: 0px -168px; +} +.halflings-icon.paperclip { + background-position: -24px -168px; +} +.halflings-icon.heart-empty { + background-position: -48px -168px; +} +.halflings-icon.link { + background-position: -72px -168px; +} +.halflings-icon.phone { + background-position: -96px -168px; +} +.halflings-icon.pushpin { + background-position: -120px -168px; +} +.halflings-icon.euro { + background-position: -144px -168px; +} +.halflings-icon.usd { + background-position: -168px -168px; +} +.halflings-icon.gbp { + background-position: -192px -168px; +} +.halflings-icon.sort { + background-position: -216px -168px; +} +.halflings-icon.sort-by-alphabet { + background-position: -240px -168px; +} +.halflings-icon.sort-by-alphabet-alt { + background-position: -264px -168px; +} +.halflings-icon.sort-by-order { + background-position: -288px -168px; +} +.halflings-icon.sort-by-order-alt { + background-position: -312px -168px; +} +.halflings-icon.sort-by-attributes { + background-position: -336px -168px; +} +.halflings-icon.sort-by-attributes-alt { + background-position: -360px -168px; +} +.halflings-icon.unchecked { + background-position: -384px -168px; +} +.halflings-icon.expand { + background-position: -408px -168px; +} +.halflings-icon.collapse { + background-position: -432px -168px; +} +.halflings-icon.collapse-top { + background-position: -456px -168px; +} +.halflings-icon.log_in { + background-position: 0px -192px; +} +.halflings-icon.flash { + background-position: -24px -192px; +} +.halflings-icon.log_out { + background-position: -48px -192px; +} +.halflings-icon.new_window { + background-position: -72px -192px; +} +.halflings-icon.record { + background-position: -96px -192px; +} +.halflings-icon.save { + background-position: -120px -192px; +} +.halflings-icon.open { + background-position: -144px -192px; +} +.halflings-icon.saved { + background-position: -168px -192px; +} +.halflings-icon.import { + background-position: -192px -192px; +} +.halflings-icon.export { + background-position: -216px -192px; +} +.halflings-icon.send { + background-position: -240px -192px; +} +.halflings-icon.floppy_disk { + background-position: -264px -192px; +} +.halflings-icon.floppy_saved { + background-position: -288px -192px; +} +.halflings-icon.floppy_remove { + background-position: -312px -192px; +} +.halflings-icon.floppy_save { + background-position: -336px -192px; +} +.halflings-icon.floppy_open { + background-position: -360px -192px; +} +.halflings-icon.credit_card { + background-position: -384px -192px; +} +.halflings-icon.transfer { + background-position: -408px -192px; +} +.halflings-icon.cutlery { + background-position: -432px -192px; +} +.halflings-icon.header { + background-position: -456px -192px; +} +.halflings-icon.compressed { + background-position: 0px -216px; +} +.halflings-icon.earphone { + background-position: -24px -216px; +} +.halflings-icon.phone_alt { + background-position: -48px -216px; +} +.halflings-icon.tower { + background-position: -72px -216px; +} +.halflings-icon.stats { + background-position: -96px -216px; +} +.halflings-icon.sd_video { + background-position: -119px -216px; +} +.halflings-icon.hd_video { + background-position: -143px -216px; +} +.halflings-icon.subtitles { + background-position: -167px -216px; +} +.halflings-icon.sound_stereo { + background-position: -191px -216px; +} +.halflings-icon.sound_dolby { + background-position: -215px -216px; +} +.halflings-icon.sound_5_1 { + background-position: -239px -216px; +} +.halflings-icon.sound_6_1 { + background-position: -263px -216px; +} +.halflings-icon.sound_7_1 { + background-position: -287px -216px; +} +.halflings-icon.copyright_mark { + background-position: -312px -216px; +} +.halflings-icon.registration_mark { + background-position: -336px -216px; +} +.halflings-icon.cloud { + background-position: -360px -216px; +} +.halflings-icon.cloud_download { + background-position: -384px -216px; +} +.halflings-icon.cloud_upload { + background-position: -408px -216px; +} +.halflings-icon.tree_conifer { + background-position: -432px -216px; +} +.halflings-icon.tree_deciduous { + background-position: -456px -216px; +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/all.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/all.css new file mode 100755 index 0000000..6439b74 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/all.css @@ -0,0 +1,61 @@ +/* iCheck plugin skins +----------------------------------- */ +@import url("minimal/_all.css"); +/* +@import url("minimal/minimal.css"); +@import url("minimal/red.css"); +@import url("minimal/green.css"); +@import url("minimal/blue.css"); +@import url("minimal/aero.css"); +@import url("minimal/grey.css"); +@import url("minimal/orange.css"); +@import url("minimal/yellow.css"); +@import url("minimal/pink.css"); +@import url("minimal/purple.css"); +*/ + +@import url("square/_all.css"); +/* +@import url("square/square.css"); +@import url("square/red.css"); +@import url("square/green.css"); +@import url("square/blue.css"); +@import url("square/aero.css"); +@import url("square/grey.css"); +@import url("square/orange.css"); +@import url("square/yellow.css"); +@import url("square/pink.css"); +@import url("square/purple.css"); +*/ + +@import url("flat/_all.css"); +/* +@import url("flat/flat.css"); +@import url("flat/red.css"); +@import url("flat/green.css"); +@import url("flat/blue.css"); +@import url("flat/aero.css"); +@import url("flat/grey.css"); +@import url("flat/orange.css"); +@import url("flat/yellow.css"); +@import url("flat/pink.css"); +@import url("flat/purple.css"); +*/ + +@import url("line/_all.css"); +/* +@import url("line/line.css"); +@import url("line/red.css"); +@import url("line/green.css"); +@import url("line/blue.css"); +@import url("line/aero.css"); +@import url("line/grey.css"); +@import url("line/orange.css"); +@import url("line/yellow.css"); +@import url("line/pink.css"); +@import url("line/purple.css"); +*/ + +@import url("polaris/polaris.css"); + +@import url("futurico/futurico.css"); \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/_all.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/_all.css new file mode 100755 index 0000000..14b32b9 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/_all.css @@ -0,0 +1,540 @@ +/* iCheck plugin Flat skin +----------------------------------- */ +.icheckbox_flat, +.iradio_flat { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(flat.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat { + background-position: 0 0; +} + .icheckbox_flat.checked { + background-position: -22px 0; + } + .icheckbox_flat.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat { + background-position: -88px 0; +} + .iradio_flat.checked { + background-position: -110px 0; + } + .iradio_flat.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat, + .iradio_flat { + background-image: url(flat@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} + +/* red */ +.icheckbox_flat-red, +.iradio_flat-red { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(red.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-red { + background-position: 0 0; +} + .icheckbox_flat-red.checked { + background-position: -22px 0; + } + .icheckbox_flat-red.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-red.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-red { + background-position: -88px 0; +} + .iradio_flat-red.checked { + background-position: -110px 0; + } + .iradio_flat-red.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-red.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-red, + .iradio_flat-red { + background-image: url(red@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} + +/* green */ +.icheckbox_flat-green, +.iradio_flat-green { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(green.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-green { + background-position: 0 0; +} + .icheckbox_flat-green.checked { + background-position: -22px 0; + } + .icheckbox_flat-green.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-green.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-green { + background-position: -88px 0; +} + .iradio_flat-green.checked { + background-position: -110px 0; + } + .iradio_flat-green.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-green.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-green, + .iradio_flat-green { + background-image: url(green@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} + +/* blue */ +.icheckbox_flat-blue, +.iradio_flat-blue { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(blue.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-blue { + background-position: 0 0; +} + .icheckbox_flat-blue.checked { + background-position: -22px 0; + } + .icheckbox_flat-blue.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-blue.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-blue { + background-position: -88px 0; +} + .iradio_flat-blue.checked { + background-position: -110px 0; + } + .iradio_flat-blue.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-blue.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-blue, + .iradio_flat-blue { + background-image: url(blue@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} + +/* aero */ +.icheckbox_flat-aero, +.iradio_flat-aero { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(aero.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-aero { + background-position: 0 0; +} + .icheckbox_flat-aero.checked { + background-position: -22px 0; + } + .icheckbox_flat-aero.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-aero.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-aero { + background-position: -88px 0; +} + .iradio_flat-aero.checked { + background-position: -110px 0; + } + .iradio_flat-aero.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-aero.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-aero, + .iradio_flat-aero { + background-image: url(aero@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} + +/* grey */ +.icheckbox_flat-grey, +.iradio_flat-grey { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(grey.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-grey { + background-position: 0 0; +} + .icheckbox_flat-grey.checked { + background-position: -22px 0; + } + .icheckbox_flat-grey.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-grey.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-grey { + background-position: -88px 0; +} + .iradio_flat-grey.checked { + background-position: -110px 0; + } + .iradio_flat-grey.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-grey.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-grey, + .iradio_flat-grey { + background-image: url(grey@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} + +/* orange */ +.icheckbox_flat-orange, +.iradio_flat-orange { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(orange.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-orange { + background-position: 0 0; +} + .icheckbox_flat-orange.checked { + background-position: -22px 0; + } + .icheckbox_flat-orange.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-orange.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-orange { + background-position: -88px 0; +} + .iradio_flat-orange.checked { + background-position: -110px 0; + } + .iradio_flat-orange.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-orange.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-orange, + .iradio_flat-orange { + background-image: url(orange@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} + +/* yellow */ +.icheckbox_flat-yellow, +.iradio_flat-yellow { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(yellow.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-yellow { + background-position: 0 0; +} + .icheckbox_flat-yellow.checked { + background-position: -22px 0; + } + .icheckbox_flat-yellow.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-yellow.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-yellow { + background-position: -88px 0; +} + .iradio_flat-yellow.checked { + background-position: -110px 0; + } + .iradio_flat-yellow.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-yellow.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-yellow, + .iradio_flat-yellow { + background-image: url(yellow@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} + +/* pink */ +.icheckbox_flat-pink, +.iradio_flat-pink { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(pink.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-pink { + background-position: 0 0; +} + .icheckbox_flat-pink.checked { + background-position: -22px 0; + } + .icheckbox_flat-pink.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-pink.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-pink { + background-position: -88px 0; +} + .iradio_flat-pink.checked { + background-position: -110px 0; + } + .iradio_flat-pink.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-pink.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-pink, + .iradio_flat-pink { + background-image: url(pink@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} + +/* purple */ +.icheckbox_flat-purple, +.iradio_flat-purple { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(purple.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-purple { + background-position: 0 0; +} + .icheckbox_flat-purple.checked { + background-position: -22px 0; + } + .icheckbox_flat-purple.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-purple.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-purple { + background-position: -88px 0; +} + .iradio_flat-purple.checked { + background-position: -110px 0; + } + .iradio_flat-purple.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-purple.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-purple, + .iradio_flat-purple { + background-image: url(purple@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/aero.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/aero.css new file mode 100755 index 0000000..af6637a --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/aero.css @@ -0,0 +1,54 @@ +/* iCheck plugin Flat skin, aero +----------------------------------- */ +.icheckbox_flat-aero, +.iradio_flat-aero { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(aero.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-aero { + background-position: 0 0; +} + .icheckbox_flat-aero.checked { + background-position: -22px 0; + } + .icheckbox_flat-aero.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-aero.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-aero { + background-position: -88px 0; +} + .iradio_flat-aero.checked { + background-position: -110px 0; + } + .iradio_flat-aero.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-aero.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-aero, + .iradio_flat-aero { + background-image: url(aero@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/aero.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/aero.png new file mode 100755 index 0000000..3327d00 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/aero.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/aero@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/aero@2x.png new file mode 100755 index 0000000..76c2895 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/aero@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/blue.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/blue.css new file mode 100755 index 0000000..040c128 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/blue.css @@ -0,0 +1,54 @@ +/* iCheck plugin Flat skin, blue +----------------------------------- */ +.icheckbox_flat-blue, +.iradio_flat-blue { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(blue.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-blue { + background-position: 0 0; +} + .icheckbox_flat-blue.checked { + background-position: -22px 0; + } + .icheckbox_flat-blue.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-blue.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-blue { + background-position: -88px 0; +} + .iradio_flat-blue.checked { + background-position: -110px 0; + } + .iradio_flat-blue.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-blue.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-blue, + .iradio_flat-blue { + background-image: url(blue@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/blue.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/blue.png new file mode 100755 index 0000000..cd0c73a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/blue.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/blue@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/blue@2x.png new file mode 100755 index 0000000..9f1ceb3 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/blue@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/flat.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/flat.css new file mode 100755 index 0000000..8160d6b --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/flat.css @@ -0,0 +1,54 @@ +/* iCheck plugin flat skin, black +----------------------------------- */ +.icheckbox_flat, +.iradio_flat { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(flat.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat { + background-position: 0 0; +} + .icheckbox_flat.checked { + background-position: -22px 0; + } + .icheckbox_flat.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat { + background-position: -88px 0; +} + .iradio_flat.checked { + background-position: -110px 0; + } + .iradio_flat.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat, + .iradio_flat { + background-image: url(flat@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/flat.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/flat.png new file mode 100755 index 0000000..51c6682 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/flat.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/flat@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/flat@2x.png new file mode 100755 index 0000000..91efd44 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/flat@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/green.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/green.css new file mode 100755 index 0000000..2cf242c --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/green.css @@ -0,0 +1,54 @@ +/* iCheck plugin Flat skin, green +----------------------------------- */ +.icheckbox_flat-green, +.iradio_flat-green { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(green.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-green { + background-position: 0 0; +} + .icheckbox_flat-green.checked { + background-position: -22px 0; + } + .icheckbox_flat-green.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-green.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-green { + background-position: -88px 0; +} + .iradio_flat-green.checked { + background-position: -110px 0; + } + .iradio_flat-green.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-green.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-green, + .iradio_flat-green { + background-image: url(green@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/green.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/green.png new file mode 100755 index 0000000..8d7fa78 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/green.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/green@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/green@2x.png new file mode 100755 index 0000000..d9c36d9 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/green@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/grey.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/grey.css new file mode 100755 index 0000000..99fa706 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/grey.css @@ -0,0 +1,54 @@ +/* iCheck plugin Flat skin, grey +----------------------------------- */ +.icheckbox_flat-grey, +.iradio_flat-grey { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(grey.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-grey { + background-position: 0 0; +} + .icheckbox_flat-grey.checked { + background-position: -22px 0; + } + .icheckbox_flat-grey.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-grey.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-grey { + background-position: -88px 0; +} + .iradio_flat-grey.checked { + background-position: -110px 0; + } + .iradio_flat-grey.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-grey.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-grey, + .iradio_flat-grey { + background-image: url(grey@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/grey.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/grey.png new file mode 100755 index 0000000..0f4cce8 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/grey.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/grey@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/grey@2x.png new file mode 100755 index 0000000..5b791fa Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/grey@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/orange.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/orange.css new file mode 100755 index 0000000..72579b1 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/orange.css @@ -0,0 +1,54 @@ +/* iCheck plugin Flat skin, orange +----------------------------------- */ +.icheckbox_flat-orange, +.iradio_flat-orange { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(orange.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-orange { + background-position: 0 0; +} + .icheckbox_flat-orange.checked { + background-position: -22px 0; + } + .icheckbox_flat-orange.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-orange.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-orange { + background-position: -88px 0; +} + .iradio_flat-orange.checked { + background-position: -110px 0; + } + .iradio_flat-orange.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-orange.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-orange, + .iradio_flat-orange { + background-image: url(orange@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/orange.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/orange.png new file mode 100755 index 0000000..89e6a16 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/orange.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/orange@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/orange@2x.png new file mode 100755 index 0000000..df44ef5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/orange@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/pink.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/pink.css new file mode 100755 index 0000000..1edfaad --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/pink.css @@ -0,0 +1,54 @@ +/* iCheck plugin Flat skin, pink +----------------------------------- */ +.icheckbox_flat-pink, +.iradio_flat-pink { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(pink.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-pink { + background-position: 0 0; +} + .icheckbox_flat-pink.checked { + background-position: -22px 0; + } + .icheckbox_flat-pink.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-pink.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-pink { + background-position: -88px 0; +} + .iradio_flat-pink.checked { + background-position: -110px 0; + } + .iradio_flat-pink.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-pink.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-pink, + .iradio_flat-pink { + background-image: url(pink@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/pink.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/pink.png new file mode 100755 index 0000000..ec42b9e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/pink.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/pink@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/pink@2x.png new file mode 100755 index 0000000..98cc36c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/pink@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/purple.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/purple.css new file mode 100755 index 0000000..ab8c3aa --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/purple.css @@ -0,0 +1,54 @@ +/* iCheck plugin Flat skin, purple +----------------------------------- */ +.icheckbox_flat-purple, +.iradio_flat-purple { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(purple.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-purple { + background-position: 0 0; +} + .icheckbox_flat-purple.checked { + background-position: -22px 0; + } + .icheckbox_flat-purple.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-purple.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-purple { + background-position: -88px 0; +} + .iradio_flat-purple.checked { + background-position: -110px 0; + } + .iradio_flat-purple.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-purple.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-purple, + .iradio_flat-purple { + background-image: url(purple@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/purple.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/purple.png new file mode 100755 index 0000000..fcb34bb Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/purple.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/purple@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/purple@2x.png new file mode 100755 index 0000000..dea6e44 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/purple@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/red.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/red.css new file mode 100755 index 0000000..25364e3 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/red.css @@ -0,0 +1,54 @@ +/* iCheck plugin Flat skin, red +----------------------------------- */ +.icheckbox_flat-red, +.iradio_flat-red { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(red.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-red { + background-position: 0 0; +} + .icheckbox_flat-red.checked { + background-position: -22px 0; + } + .icheckbox_flat-red.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-red.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-red { + background-position: -88px 0; +} + .iradio_flat-red.checked { + background-position: -110px 0; + } + .iradio_flat-red.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-red.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-red, + .iradio_flat-red { + background-image: url(red@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/red.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/red.png new file mode 100755 index 0000000..bb065ba Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/red.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/red@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/red@2x.png new file mode 100755 index 0000000..6f53c5b Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/red@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/yellow.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/yellow.css new file mode 100755 index 0000000..1be1627 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/yellow.css @@ -0,0 +1,54 @@ +/* iCheck plugin Flat skin, yellow +----------------------------------- */ +.icheckbox_flat-yellow, +.iradio_flat-yellow { + display: block; + margin: 0; + padding: 0; + width: 20px; + height: 20px; + background: url(yellow.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_flat-yellow { + background-position: 0 0; +} + .icheckbox_flat-yellow.checked { + background-position: -22px 0; + } + .icheckbox_flat-yellow.disabled { + background-position: -44px 0; + cursor: default; + } + .icheckbox_flat-yellow.checked.disabled { + background-position: -66px 0; + } + +.iradio_flat-yellow { + background-position: -88px 0; +} + .iradio_flat-yellow.checked { + background-position: -110px 0; + } + .iradio_flat-yellow.disabled { + background-position: -132px 0; + cursor: default; + } + .iradio_flat-yellow.checked.disabled { + background-position: -154px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_flat-yellow, + .iradio_flat-yellow { + background-image: url(yellow@2x.png); + -webkit-background-size: 176px 22px; + background-size: 176px 22px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/yellow.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/yellow.png new file mode 100755 index 0000000..b122fcd Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/yellow.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/yellow@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/yellow@2x.png new file mode 100755 index 0000000..8363e23 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/flat/yellow@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/futurico/futurico.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/futurico/futurico.css new file mode 100755 index 0000000..bd40bc5 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/futurico/futurico.css @@ -0,0 +1,54 @@ +/* iCheck plugin Futurico skin +----------------------------------- */ +.icheckbox_futurico, +.iradio_futurico { + display: block; + margin: 0; + padding: 0; + width: 16px; + height: 17px; + background: url(futurico.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_futurico { + background-position: 0 0; +} + .icheckbox_futurico.checked { + background-position: -18px 0; + } + .icheckbox_futurico.disabled { + background-position: -36px 0; + cursor: default; + } + .icheckbox_futurico.checked.disabled { + background-position: -54px 0; + } + +.iradio_futurico { + background-position: -72px 0; +} + .iradio_futurico.checked { + background-position: -90px 0; + } + .iradio_futurico.disabled { + background-position: -108px 0; + cursor: default; + } + .iradio_futurico.checked.disabled { + background-position: -126px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_futurico, + .iradio_futurico { + background-image: url(futurico@2x.png); + -webkit-background-size: 144px 19px; + background-size: 144px 19px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/futurico/futurico.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/futurico/futurico.png new file mode 100755 index 0000000..50d62b5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/futurico/futurico.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/futurico/futurico@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/futurico/futurico@2x.png new file mode 100755 index 0000000..f7eb45a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/futurico/futurico@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/_all.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/_all.css new file mode 100755 index 0000000..a18d0d9 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/_all.css @@ -0,0 +1,740 @@ +/* iCheck plugin Line skin +----------------------------------- */ +.icheckbox_line, +.iradio_line { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #000; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line .icheck_line-icon, + .iradio_line .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line.hover, + .icheckbox_line.checked.hover, + .iradio_line.hover { + background: #444; + } + .icheckbox_line.checked, + .iradio_line.checked { + background: #000; + } + .icheckbox_line.checked .icheck_line-icon, + .iradio_line.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line.disabled, + .iradio_line.disabled { + background: #ccc; + cursor: default; + } + .icheckbox_line.disabled .icheck_line-icon, + .iradio_line.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line.checked.disabled, + .iradio_line.checked.disabled { + background: #ccc; + } + .icheckbox_line.checked.disabled .icheck_line-icon, + .iradio_line.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line .icheck_line-icon, + .iradio_line .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} + +/* red */ +.icheckbox_line-red, +.iradio_line-red { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #e56c69; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-red .icheck_line-icon, + .iradio_line-red .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-red.hover, + .icheckbox_line-red.checked.hover, + .iradio_line-red.hover { + background: #E98582; + } + .icheckbox_line-red.checked, + .iradio_line-red.checked { + background: #e56c69; + } + .icheckbox_line-red.checked .icheck_line-icon, + .iradio_line-red.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-red.disabled, + .iradio_line-red.disabled { + background: #F7D3D2; + cursor: default; + } + .icheckbox_line-red.disabled .icheck_line-icon, + .iradio_line-red.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-red.checked.disabled, + .iradio_line-red.checked.disabled { + background: #F7D3D2; + } + .icheckbox_line-red.checked.disabled .icheck_line-icon, + .iradio_line-red.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-red .icheck_line-icon, + .iradio_line-red .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} + +/* green */ +.icheckbox_line-green, +.iradio_line-green { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #1b7e5a; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-green .icheck_line-icon, + .iradio_line-green .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-green.hover, + .icheckbox_line-green.checked.hover, + .iradio_line-green.hover { + background: #24AA7A; + } + .icheckbox_line-green.checked, + .iradio_line-green.checked { + background: #1b7e5a; + } + .icheckbox_line-green.checked .icheck_line-icon, + .iradio_line-green.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-green.disabled, + .iradio_line-green.disabled { + background: #89E6C4; + cursor: default; + } + .icheckbox_line-green.disabled .icheck_line-icon, + .iradio_line-green.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-green.checked.disabled, + .iradio_line-green.checked.disabled { + background: #89E6C4; + } + .icheckbox_line-green.checked.disabled .icheck_line-icon, + .iradio_line-green.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-green .icheck_line-icon, + .iradio_line-green .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} + +/* blue */ +.icheckbox_line-blue, +.iradio_line-blue { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #2489c5; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-blue .icheck_line-icon, + .iradio_line-blue .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-blue.hover, + .icheckbox_line-blue.checked.hover, + .iradio_line-blue.hover { + background: #3DA0DB; + } + .icheckbox_line-blue.checked, + .iradio_line-blue.checked { + background: #2489c5; + } + .icheckbox_line-blue.checked .icheck_line-icon, + .iradio_line-blue.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-blue.disabled, + .iradio_line-blue.disabled { + background: #ADD7F0; + cursor: default; + } + .icheckbox_line-blue.disabled .icheck_line-icon, + .iradio_line-blue.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-blue.checked.disabled, + .iradio_line-blue.checked.disabled { + background: #ADD7F0; + } + .icheckbox_line-blue.checked.disabled .icheck_line-icon, + .iradio_line-blue.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-blue .icheck_line-icon, + .iradio_line-blue .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} + +/* aero */ +.icheckbox_line-aero, +.iradio_line-aero { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #9cc2cb; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-aero .icheck_line-icon, + .iradio_line-aero .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-aero.hover, + .icheckbox_line-aero.checked.hover, + .iradio_line-aero.hover { + background: #B5D1D8; + } + .icheckbox_line-aero.checked, + .iradio_line-aero.checked { + background: #9cc2cb; + } + .icheckbox_line-aero.checked .icheck_line-icon, + .iradio_line-aero.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-aero.disabled, + .iradio_line-aero.disabled { + background: #D2E4E8; + cursor: default; + } + .icheckbox_line-aero.disabled .icheck_line-icon, + .iradio_line-aero.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-aero.checked.disabled, + .iradio_line-aero.checked.disabled { + background: #D2E4E8; + } + .icheckbox_line-aero.checked.disabled .icheck_line-icon, + .iradio_line-aero.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-aero .icheck_line-icon, + .iradio_line-aero .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} + +/* grey */ +.icheckbox_line-grey, +.iradio_line-grey { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #73716e; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-grey .icheck_line-icon, + .iradio_line-grey .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-grey.hover, + .icheckbox_line-grey.checked.hover, + .iradio_line-grey.hover { + background: #8B8986; + } + .icheckbox_line-grey.checked, + .iradio_line-grey.checked { + background: #73716e; + } + .icheckbox_line-grey.checked .icheck_line-icon, + .iradio_line-grey.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-grey.disabled, + .iradio_line-grey.disabled { + background: #D5D4D3; + cursor: default; + } + .icheckbox_line-grey.disabled .icheck_line-icon, + .iradio_line-grey.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-grey.checked.disabled, + .iradio_line-grey.checked.disabled { + background: #D5D4D3; + } + .icheckbox_line-grey.checked.disabled .icheck_line-icon, + .iradio_line-grey.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-grey .icheck_line-icon, + .iradio_line-grey .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} + +/* orange */ +.icheckbox_line-orange, +.iradio_line-orange { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #f70; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-orange .icheck_line-icon, + .iradio_line-orange .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-orange.hover, + .icheckbox_line-orange.checked.hover, + .iradio_line-orange.hover { + background: #FF9233; + } + .icheckbox_line-orange.checked, + .iradio_line-orange.checked { + background: #f70; + } + .icheckbox_line-orange.checked .icheck_line-icon, + .iradio_line-orange.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-orange.disabled, + .iradio_line-orange.disabled { + background: #FFD6B3; + cursor: default; + } + .icheckbox_line-orange.disabled .icheck_line-icon, + .iradio_line-orange.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-orange.checked.disabled, + .iradio_line-orange.checked.disabled { + background: #FFD6B3; + } + .icheckbox_line-orange.checked.disabled .icheck_line-icon, + .iradio_line-orange.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-orange .icheck_line-icon, + .iradio_line-orange .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} + +/* yellow */ +.icheckbox_line-yellow, +.iradio_line-yellow { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #FFC414; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-yellow .icheck_line-icon, + .iradio_line-yellow .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-yellow.hover, + .icheckbox_line-yellow.checked.hover, + .iradio_line-yellow.hover { + background: #FFD34F; + } + .icheckbox_line-yellow.checked, + .iradio_line-yellow.checked { + background: #FFC414; + } + .icheckbox_line-yellow.checked .icheck_line-icon, + .iradio_line-yellow.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-yellow.disabled, + .iradio_line-yellow.disabled { + background: #FFE495; + cursor: default; + } + .icheckbox_line-yellow.disabled .icheck_line-icon, + .iradio_line-yellow.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-yellow.checked.disabled, + .iradio_line-yellow.checked.disabled { + background: #FFE495; + } + .icheckbox_line-yellow.checked.disabled .icheck_line-icon, + .iradio_line-yellow.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-yellow .icheck_line-icon, + .iradio_line-yellow .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} + +/* pink */ +.icheckbox_line-pink, +.iradio_line-pink { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #a77a94; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-pink .icheck_line-icon, + .iradio_line-pink .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-pink.hover, + .icheckbox_line-pink.checked.hover, + .iradio_line-pink.hover { + background: #B995A9; + } + .icheckbox_line-pink.checked, + .iradio_line-pink.checked { + background: #a77a94; + } + .icheckbox_line-pink.checked .icheck_line-icon, + .iradio_line-pink.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-pink.disabled, + .iradio_line-pink.disabled { + background: #E0D0DA; + cursor: default; + } + .icheckbox_line-pink.disabled .icheck_line-icon, + .iradio_line-pink.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-pink.checked.disabled, + .iradio_line-pink.checked.disabled { + background: #E0D0DA; + } + .icheckbox_line-pink.checked.disabled .icheck_line-icon, + .iradio_line-pink.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-pink .icheck_line-icon, + .iradio_line-pink .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} + +/* purple */ +.icheckbox_line-purple, +.iradio_line-purple { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #6a5a8c; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-purple .icheck_line-icon, + .iradio_line-purple .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-purple.hover, + .icheckbox_line-purple.checked.hover, + .iradio_line-purple.hover { + background: #8677A7; + } + .icheckbox_line-purple.checked, + .iradio_line-purple.checked { + background: #6a5a8c; + } + .icheckbox_line-purple.checked .icheck_line-icon, + .iradio_line-purple.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-purple.disabled, + .iradio_line-purple.disabled { + background: #D2CCDE; + cursor: default; + } + .icheckbox_line-purple.disabled .icheck_line-icon, + .iradio_line-purple.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-purple.checked.disabled, + .iradio_line-purple.checked.disabled { + background: #D2CCDE; + } + .icheckbox_line-purple.checked.disabled .icheck_line-icon, + .iradio_line-purple.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-purple .icheck_line-icon, + .iradio_line-purple .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/aero.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/aero.css new file mode 100755 index 0000000..44989a4 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/aero.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, aero +----------------------------------- */ +.icheckbox_line-aero, +.iradio_line-aero { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #9cc2cb; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-aero .icheck_line-icon, + .iradio_line-aero .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-aero.hover, + .icheckbox_line-aero.checked.hover, + .iradio_line-aero.hover { + background: #B5D1D8; + } + .icheckbox_line-aero.checked, + .iradio_line-aero.checked { + background: #9cc2cb; + } + .icheckbox_line-aero.checked .icheck_line-icon, + .iradio_line-aero.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-aero.disabled, + .iradio_line-aero.disabled { + background: #D2E4E8; + cursor: default; + } + .icheckbox_line-aero.disabled .icheck_line-icon, + .iradio_line-aero.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-aero.checked.disabled, + .iradio_line-aero.checked.disabled { + background: #D2E4E8; + } + .icheckbox_line-aero.checked.disabled .icheck_line-icon, + .iradio_line-aero.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-aero .icheck_line-icon, + .iradio_line-aero .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/blue.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/blue.css new file mode 100755 index 0000000..5c9c0a7 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/blue.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, blue +----------------------------------- */ +.icheckbox_line-blue, +.iradio_line-blue { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #2489c5; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-blue .icheck_line-icon, + .iradio_line-blue .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-blue.hover, + .icheckbox_line-blue.checked.hover, + .iradio_line-blue.hover { + background: #3DA0DB; + } + .icheckbox_line-blue.checked, + .iradio_line-blue.checked { + background: #2489c5; + } + .icheckbox_line-blue.checked .icheck_line-icon, + .iradio_line-blue.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-blue.disabled, + .iradio_line-blue.disabled { + background: #ADD7F0; + cursor: default; + } + .icheckbox_line-blue.disabled .icheck_line-icon, + .iradio_line-blue.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-blue.checked.disabled, + .iradio_line-blue.checked.disabled { + background: #ADD7F0; + } + .icheckbox_line-blue.checked.disabled .icheck_line-icon, + .iradio_line-blue.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-blue .icheck_line-icon, + .iradio_line-blue .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/green.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/green.css new file mode 100755 index 0000000..8bbe514 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/green.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, green +----------------------------------- */ +.icheckbox_line-green, +.iradio_line-green { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #1b7e5a; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-green .icheck_line-icon, + .iradio_line-green .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-green.hover, + .icheckbox_line-green.checked.hover, + .iradio_line-green.hover { + background: #24AA7A; + } + .icheckbox_line-green.checked, + .iradio_line-green.checked { + background: #1b7e5a; + } + .icheckbox_line-green.checked .icheck_line-icon, + .iradio_line-green.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-green.disabled, + .iradio_line-green.disabled { + background: #89E6C4; + cursor: default; + } + .icheckbox_line-green.disabled .icheck_line-icon, + .iradio_line-green.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-green.checked.disabled, + .iradio_line-green.checked.disabled { + background: #89E6C4; + } + .icheckbox_line-green.checked.disabled .icheck_line-icon, + .iradio_line-green.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-green .icheck_line-icon, + .iradio_line-green .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/grey.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/grey.css new file mode 100755 index 0000000..fc16a80 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/grey.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, grey +----------------------------------- */ +.icheckbox_line-grey, +.iradio_line-grey { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #73716e; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-grey .icheck_line-icon, + .iradio_line-grey .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-grey.hover, + .icheckbox_line-grey.checked.hover, + .iradio_line-grey.hover { + background: #8B8986; + } + .icheckbox_line-grey.checked, + .iradio_line-grey.checked { + background: #73716e; + } + .icheckbox_line-grey.checked .icheck_line-icon, + .iradio_line-grey.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-grey.disabled, + .iradio_line-grey.disabled { + background: #D5D4D3; + cursor: default; + } + .icheckbox_line-grey.disabled .icheck_line-icon, + .iradio_line-grey.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-grey.checked.disabled, + .iradio_line-grey.checked.disabled { + background: #D5D4D3; + } + .icheckbox_line-grey.checked.disabled .icheck_line-icon, + .iradio_line-grey.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-grey .icheck_line-icon, + .iradio_line-grey .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/line.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/line.css new file mode 100755 index 0000000..dbde8d4 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/line.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, black +----------------------------------- */ +.icheckbox_line, +.iradio_line { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #000; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line .icheck_line-icon, + .iradio_line .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line.hover, + .icheckbox_line.checked.hover, + .iradio_line.hover { + background: #444; + } + .icheckbox_line.checked, + .iradio_line.checked { + background: #000; + } + .icheckbox_line.checked .icheck_line-icon, + .iradio_line.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line.disabled, + .iradio_line.disabled { + background: #ccc; + cursor: default; + } + .icheckbox_line.disabled .icheck_line-icon, + .iradio_line.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line.checked.disabled, + .iradio_line.checked.disabled { + background: #ccc; + } + .icheckbox_line.checked.disabled .icheck_line-icon, + .iradio_line.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line .icheck_line-icon, + .iradio_line .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/line.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/line.png new file mode 100755 index 0000000..d21d7a7 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/line.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/line@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/line@2x.png new file mode 100755 index 0000000..62900a2 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/line@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/orange.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/orange.css new file mode 100755 index 0000000..210f334 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/orange.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, orange +----------------------------------- */ +.icheckbox_line-orange, +.iradio_line-orange { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #f70; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-orange .icheck_line-icon, + .iradio_line-orange .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-orange.hover, + .icheckbox_line-orange.checked.hover, + .iradio_line-orange.hover { + background: #FF9233; + } + .icheckbox_line-orange.checked, + .iradio_line-orange.checked { + background: #f70; + } + .icheckbox_line-orange.checked .icheck_line-icon, + .iradio_line-orange.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-orange.disabled, + .iradio_line-orange.disabled { + background: #FFD6B3; + cursor: default; + } + .icheckbox_line-orange.disabled .icheck_line-icon, + .iradio_line-orange.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-orange.checked.disabled, + .iradio_line-orange.checked.disabled { + background: #FFD6B3; + } + .icheckbox_line-orange.checked.disabled .icheck_line-icon, + .iradio_line-orange.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-orange .icheck_line-icon, + .iradio_line-orange .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/pink.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/pink.css new file mode 100755 index 0000000..44c9cea --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/pink.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, pink +----------------------------------- */ +.icheckbox_line-pink, +.iradio_line-pink { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #a77a94; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-pink .icheck_line-icon, + .iradio_line-pink .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-pink.hover, + .icheckbox_line-pink.checked.hover, + .iradio_line-pink.hover { + background: #B995A9; + } + .icheckbox_line-pink.checked, + .iradio_line-pink.checked { + background: #a77a94; + } + .icheckbox_line-pink.checked .icheck_line-icon, + .iradio_line-pink.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-pink.disabled, + .iradio_line-pink.disabled { + background: #E0D0DA; + cursor: default; + } + .icheckbox_line-pink.disabled .icheck_line-icon, + .iradio_line-pink.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-pink.checked.disabled, + .iradio_line-pink.checked.disabled { + background: #E0D0DA; + } + .icheckbox_line-pink.checked.disabled .icheck_line-icon, + .iradio_line-pink.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-pink .icheck_line-icon, + .iradio_line-pink .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/purple.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/purple.css new file mode 100755 index 0000000..be4c4e2 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/purple.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, purple +----------------------------------- */ +.icheckbox_line-purple, +.iradio_line-purple { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #6a5a8c; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-purple .icheck_line-icon, + .iradio_line-purple .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-purple.hover, + .icheckbox_line-purple.checked.hover, + .iradio_line-purple.hover { + background: #8677A7; + } + .icheckbox_line-purple.checked, + .iradio_line-purple.checked { + background: #6a5a8c; + } + .icheckbox_line-purple.checked .icheck_line-icon, + .iradio_line-purple.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-purple.disabled, + .iradio_line-purple.disabled { + background: #D2CCDE; + cursor: default; + } + .icheckbox_line-purple.disabled .icheck_line-icon, + .iradio_line-purple.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-purple.checked.disabled, + .iradio_line-purple.checked.disabled { + background: #D2CCDE; + } + .icheckbox_line-purple.checked.disabled .icheck_line-icon, + .iradio_line-purple.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-purple .icheck_line-icon, + .iradio_line-purple .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/red.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/red.css new file mode 100755 index 0000000..ebcd8be --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/red.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, red +----------------------------------- */ +.icheckbox_line-red, +.iradio_line-red { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #e56c69; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-red .icheck_line-icon, + .iradio_line-red .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-red.hover, + .icheckbox_line-red.checked.hover, + .iradio_line-red.hover { + background: #E98582; + } + .icheckbox_line-red.checked, + .iradio_line-red.checked { + background: #e56c69; + } + .icheckbox_line-red.checked .icheck_line-icon, + .iradio_line-red.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-red.disabled, + .iradio_line-red.disabled { + background: #F7D3D2; + cursor: default; + } + .icheckbox_line-red.disabled .icheck_line-icon, + .iradio_line-red.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-red.checked.disabled, + .iradio_line-red.checked.disabled { + background: #F7D3D2; + } + .icheckbox_line-red.checked.disabled .icheck_line-icon, + .iradio_line-red.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-red .icheck_line-icon, + .iradio_line-red .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/yellow.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/yellow.css new file mode 100755 index 0000000..8e08871 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/line/yellow.css @@ -0,0 +1,74 @@ +/* iCheck plugin Line skin, yellow +----------------------------------- */ +.icheckbox_line-yellow, +.iradio_line-yellow { + position: relative; + display: block; + margin: 0; + padding: 5px 15px 5px 38px; + font-size: 13px; + line-height: 17px; + color: #fff; + background: #FFC414; + border: none; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} + .icheckbox_line-yellow .icheck_line-icon, + .iradio_line-yellow .icheck_line-icon { + position: absolute; + top: 50%; + left: 13px; + width: 13px; + height: 11px; + margin: -5px 0 0 0; + padding: 0; + overflow: hidden; + background: url(line.png) no-repeat; + border: none; + } + .icheckbox_line-yellow.hover, + .icheckbox_line-yellow.checked.hover, + .iradio_line-yellow.hover { + background: #FFD34F; + } + .icheckbox_line-yellow.checked, + .iradio_line-yellow.checked { + background: #FFC414; + } + .icheckbox_line-yellow.checked .icheck_line-icon, + .iradio_line-yellow.checked .icheck_line-icon { + background-position: -15px 0; + } + .icheckbox_line-yellow.disabled, + .iradio_line-yellow.disabled { + background: #FFE495; + cursor: default; + } + .icheckbox_line-yellow.disabled .icheck_line-icon, + .iradio_line-yellow.disabled .icheck_line-icon { + background-position: -30px 0; + } + .icheckbox_line-yellow.checked.disabled, + .iradio_line-yellow.checked.disabled { + background: #FFE495; + } + .icheckbox_line-yellow.checked.disabled .icheck_line-icon, + .iradio_line-yellow.checked.disabled .icheck_line-icon { + background-position: -45px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_line-yellow .icheck_line-icon, + .iradio_line-yellow .icheck_line-icon { + background-image: url(line@2x.png); + -webkit-background-size: 60px 13px; + background-size: 60px 13px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/_all.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/_all.css new file mode 100755 index 0000000..8d54966 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/_all.css @@ -0,0 +1,600 @@ +/* iCheck plugin Minimal skin +----------------------------------- */ +.icheckbox_minimal, +.iradio_minimal { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(minimal.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal { + background-position: 0 0; +} + .icheckbox_minimal.hover { + background-position: -20px 0; + } + .icheckbox_minimal.checked { + background-position: -40px 0; + } + .icheckbox_minimal.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal { + background-position: -100px 0; +} + .iradio_minimal.hover { + background-position: -120px 0; + } + .iradio_minimal.checked { + background-position: -140px 0; + } + .iradio_minimal.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal, + .iradio_minimal { + background-image: url(minimal@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} + +/* red */ +.icheckbox_minimal-red, +.iradio_minimal-red { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(red.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-red { + background-position: 0 0; +} + .icheckbox_minimal-red.hover { + background-position: -20px 0; + } + .icheckbox_minimal-red.checked { + background-position: -40px 0; + } + .icheckbox_minimal-red.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-red.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-red { + background-position: -100px 0; +} + .iradio_minimal-red.hover { + background-position: -120px 0; + } + .iradio_minimal-red.checked { + background-position: -140px 0; + } + .iradio_minimal-red.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-red.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-red, + .iradio_minimal-red { + background-image: url(red@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} + +/* green */ +.icheckbox_minimal-green, +.iradio_minimal-green { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(green.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-green { + background-position: 0 0; +} + .icheckbox_minimal-green.hover { + background-position: -20px 0; + } + .icheckbox_minimal-green.checked { + background-position: -40px 0; + } + .icheckbox_minimal-green.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-green.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-green { + background-position: -100px 0; +} + .iradio_minimal-green.hover { + background-position: -120px 0; + } + .iradio_minimal-green.checked { + background-position: -140px 0; + } + .iradio_minimal-green.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-green.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-green, + .iradio_minimal-green { + background-image: url(green@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} + +/* blue */ +.icheckbox_minimal-blue, +.iradio_minimal-blue { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(blue.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-blue { + background-position: 0 0; +} + .icheckbox_minimal-blue.hover { + background-position: -20px 0; + } + .icheckbox_minimal-blue.checked { + background-position: -40px 0; + } + .icheckbox_minimal-blue.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-blue.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-blue { + background-position: -100px 0; +} + .iradio_minimal-blue.hover { + background-position: -120px 0; + } + .iradio_minimal-blue.checked { + background-position: -140px 0; + } + .iradio_minimal-blue.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-blue.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-blue, + .iradio_minimal-blue { + background-image: url(blue@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} + +/* aero */ +.icheckbox_minimal-aero, +.iradio_minimal-aero { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(aero.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-aero { + background-position: 0 0; +} + .icheckbox_minimal-aero.hover { + background-position: -20px 0; + } + .icheckbox_minimal-aero.checked { + background-position: -40px 0; + } + .icheckbox_minimal-aero.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-aero.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-aero { + background-position: -100px 0; +} + .iradio_minimal-aero.hover { + background-position: -120px 0; + } + .iradio_minimal-aero.checked { + background-position: -140px 0; + } + .iradio_minimal-aero.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-aero.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-aero, + .iradio_minimal-aero { + background-image: url(aero@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} + +/* grey */ +.icheckbox_minimal-grey, +.iradio_minimal-grey { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(grey.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-grey { + background-position: 0 0; +} + .icheckbox_minimal-grey.hover { + background-position: -20px 0; + } + .icheckbox_minimal-grey.checked { + background-position: -40px 0; + } + .icheckbox_minimal-grey.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-grey.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-grey { + background-position: -100px 0; +} + .iradio_minimal-grey.hover { + background-position: -120px 0; + } + .iradio_minimal-grey.checked { + background-position: -140px 0; + } + .iradio_minimal-grey.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-grey.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-grey, + .iradio_minimal-grey { + background-image: url(grey@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} + +/* orange */ +.icheckbox_minimal-orange, +.iradio_minimal-orange { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(orange.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-orange { + background-position: 0 0; +} + .icheckbox_minimal-orange.hover { + background-position: -20px 0; + } + .icheckbox_minimal-orange.checked { + background-position: -40px 0; + } + .icheckbox_minimal-orange.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-orange.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-orange { + background-position: -100px 0; +} + .iradio_minimal-orange.hover { + background-position: -120px 0; + } + .iradio_minimal-orange.checked { + background-position: -140px 0; + } + .iradio_minimal-orange.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-orange.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-orange, + .iradio_minimal-orange { + background-image: url(orange@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} + +/* yellow */ +.icheckbox_minimal-yellow, +.iradio_minimal-yellow { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(yellow.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-yellow { + background-position: 0 0; +} + .icheckbox_minimal-yellow.hover { + background-position: -20px 0; + } + .icheckbox_minimal-yellow.checked { + background-position: -40px 0; + } + .icheckbox_minimal-yellow.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-yellow.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-yellow { + background-position: -100px 0; +} + .iradio_minimal-yellow.hover { + background-position: -120px 0; + } + .iradio_minimal-yellow.checked { + background-position: -140px 0; + } + .iradio_minimal-yellow.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-yellow.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-yellow, + .iradio_minimal-yellow { + background-image: url(yellow@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} + +/* pink */ +.icheckbox_minimal-pink, +.iradio_minimal-pink { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(pink.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-pink { + background-position: 0 0; +} + .icheckbox_minimal-pink.hover { + background-position: -20px 0; + } + .icheckbox_minimal-pink.checked { + background-position: -40px 0; + } + .icheckbox_minimal-pink.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-pink.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-pink { + background-position: -100px 0; +} + .iradio_minimal-pink.hover { + background-position: -120px 0; + } + .iradio_minimal-pink.checked { + background-position: -140px 0; + } + .iradio_minimal-pink.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-pink.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-pink, + .iradio_minimal-pink { + background-image: url(pink@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} + +/* purple */ +.icheckbox_minimal-purple, +.iradio_minimal-purple { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(purple.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-purple { + background-position: 0 0; +} + .icheckbox_minimal-purple.hover { + background-position: -20px 0; + } + .icheckbox_minimal-purple.checked { + background-position: -40px 0; + } + .icheckbox_minimal-purple.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-purple.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-purple { + background-position: -100px 0; +} + .iradio_minimal-purple.hover { + background-position: -120px 0; + } + .iradio_minimal-purple.checked { + background-position: -140px 0; + } + .iradio_minimal-purple.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-purple.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-purple, + .iradio_minimal-purple { + background-image: url(purple@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/aero.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/aero.css new file mode 100755 index 0000000..bfc8bdd --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/aero.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, aero +----------------------------------- */ +.icheckbox_minimal-aero, +.iradio_minimal-aero { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(aero.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-aero { + background-position: 0 0; +} + .icheckbox_minimal-aero.hover { + background-position: -20px 0; + } + .icheckbox_minimal-aero.checked { + background-position: -40px 0; + } + .icheckbox_minimal-aero.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-aero.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-aero { + background-position: -100px 0; +} + .iradio_minimal-aero.hover { + background-position: -120px 0; + } + .iradio_minimal-aero.checked { + background-position: -140px 0; + } + .iradio_minimal-aero.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-aero.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-aero, + .iradio_minimal-aero { + background-image: url(aero@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/aero.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/aero.png new file mode 100755 index 0000000..dccf774 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/aero.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/aero@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/aero@2x.png new file mode 100755 index 0000000..5537ee3 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/aero@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/blue.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/blue.css new file mode 100755 index 0000000..1325bb6 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/blue.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, blue +----------------------------------- */ +.icheckbox_minimal-blue, +.iradio_minimal-blue { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(blue.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-blue { + background-position: 0 0; +} + .icheckbox_minimal-blue.hover { + background-position: -20px 0; + } + .icheckbox_minimal-blue.checked { + background-position: -40px 0; + } + .icheckbox_minimal-blue.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-blue.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-blue { + background-position: -100px 0; +} + .iradio_minimal-blue.hover { + background-position: -120px 0; + } + .iradio_minimal-blue.checked { + background-position: -140px 0; + } + .iradio_minimal-blue.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-blue.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-blue, + .iradio_minimal-blue { + background-image: url(blue@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/blue.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/blue.png new file mode 100755 index 0000000..af04cee Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/blue.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/blue@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/blue@2x.png new file mode 100755 index 0000000..f19210a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/blue@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/green.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/green.css new file mode 100755 index 0000000..5a38cd0 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/green.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, green +----------------------------------- */ +.icheckbox_minimal-green, +.iradio_minimal-green { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(green.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-green { + background-position: 0 0; +} + .icheckbox_minimal-green.hover { + background-position: -20px 0; + } + .icheckbox_minimal-green.checked { + background-position: -40px 0; + } + .icheckbox_minimal-green.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-green.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-green { + background-position: -100px 0; +} + .iradio_minimal-green.hover { + background-position: -120px 0; + } + .iradio_minimal-green.checked { + background-position: -140px 0; + } + .iradio_minimal-green.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-green.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-green, + .iradio_minimal-green { + background-image: url(green@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/green.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/green.png new file mode 100755 index 0000000..9171ebc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/green.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/green@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/green@2x.png new file mode 100755 index 0000000..7f18f96 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/green@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/grey.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/grey.css new file mode 100755 index 0000000..de3ec6b --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/grey.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, grey +----------------------------------- */ +.icheckbox_minimal-grey, +.iradio_minimal-grey { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(grey.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-grey { + background-position: 0 0; +} + .icheckbox_minimal-grey.hover { + background-position: -20px 0; + } + .icheckbox_minimal-grey.checked { + background-position: -40px 0; + } + .icheckbox_minimal-grey.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-grey.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-grey { + background-position: -100px 0; +} + .iradio_minimal-grey.hover { + background-position: -120px 0; + } + .iradio_minimal-grey.checked { + background-position: -140px 0; + } + .iradio_minimal-grey.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-grey.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-grey, + .iradio_minimal-grey { + background-image: url(grey@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/grey.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/grey.png new file mode 100755 index 0000000..22dcdbc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/grey.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/grey@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/grey@2x.png new file mode 100755 index 0000000..85e82dd Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/grey@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/minimal.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/minimal.css new file mode 100755 index 0000000..269adb8 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/minimal.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, black +----------------------------------- */ +.icheckbox_minimal, +.iradio_minimal { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(minimal.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal { + background-position: 0 0; +} + .icheckbox_minimal.hover { + background-position: -20px 0; + } + .icheckbox_minimal.checked { + background-position: -40px 0; + } + .icheckbox_minimal.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal { + background-position: -100px 0; +} + .iradio_minimal.hover { + background-position: -120px 0; + } + .iradio_minimal.checked { + background-position: -140px 0; + } + .iradio_minimal.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal, + .iradio_minimal { + background-image: url(minimal@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/minimal.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/minimal.png new file mode 100755 index 0000000..943be16 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/minimal.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/minimal@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/minimal@2x.png new file mode 100755 index 0000000..d62291d Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/minimal@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/orange.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/orange.css new file mode 100755 index 0000000..fc43938 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/orange.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, orange +----------------------------------- */ +.icheckbox_minimal-orange, +.iradio_minimal-orange { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(orange.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-orange { + background-position: 0 0; +} + .icheckbox_minimal-orange.hover { + background-position: -20px 0; + } + .icheckbox_minimal-orange.checked { + background-position: -40px 0; + } + .icheckbox_minimal-orange.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-orange.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-orange { + background-position: -100px 0; +} + .iradio_minimal-orange.hover { + background-position: -120px 0; + } + .iradio_minimal-orange.checked { + background-position: -140px 0; + } + .iradio_minimal-orange.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-orange.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-orange, + .iradio_minimal-orange { + background-image: url(orange@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/orange.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/orange.png new file mode 100755 index 0000000..f2a3149 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/orange.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/orange@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/orange@2x.png new file mode 100755 index 0000000..68c8359 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/orange@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/pink.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/pink.css new file mode 100755 index 0000000..4832e2e --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/pink.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, pink +----------------------------------- */ +.icheckbox_minimal-pink, +.iradio_minimal-pink { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(pink.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-pink { + background-position: 0 0; +} + .icheckbox_minimal-pink.hover { + background-position: -20px 0; + } + .icheckbox_minimal-pink.checked { + background-position: -40px 0; + } + .icheckbox_minimal-pink.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-pink.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-pink { + background-position: -100px 0; +} + .iradio_minimal-pink.hover { + background-position: -120px 0; + } + .iradio_minimal-pink.checked { + background-position: -140px 0; + } + .iradio_minimal-pink.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-pink.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-pink, + .iradio_minimal-pink { + background-image: url(pink@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/pink.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/pink.png new file mode 100755 index 0000000..660553c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/pink.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/pink@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/pink@2x.png new file mode 100755 index 0000000..7d7b385 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/pink@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/purple.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/purple.css new file mode 100755 index 0000000..3cdfea0 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/purple.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, purple +----------------------------------- */ +.icheckbox_minimal-purple, +.iradio_minimal-purple { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(purple.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-purple { + background-position: 0 0; +} + .icheckbox_minimal-purple.hover { + background-position: -20px 0; + } + .icheckbox_minimal-purple.checked { + background-position: -40px 0; + } + .icheckbox_minimal-purple.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-purple.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-purple { + background-position: -100px 0; +} + .iradio_minimal-purple.hover { + background-position: -120px 0; + } + .iradio_minimal-purple.checked { + background-position: -140px 0; + } + .iradio_minimal-purple.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-purple.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-purple, + .iradio_minimal-purple { + background-image: url(purple@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/purple.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/purple.png new file mode 100755 index 0000000..48dec79 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/purple.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/purple@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/purple@2x.png new file mode 100755 index 0000000..3bb7041 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/purple@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/red.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/red.css new file mode 100755 index 0000000..3b16ae0 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/red.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, red +----------------------------------- */ +.icheckbox_minimal-red, +.iradio_minimal-red { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(red.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-red { + background-position: 0 0; +} + .icheckbox_minimal-red.hover { + background-position: -20px 0; + } + .icheckbox_minimal-red.checked { + background-position: -40px 0; + } + .icheckbox_minimal-red.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-red.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-red { + background-position: -100px 0; +} + .iradio_minimal-red.hover { + background-position: -120px 0; + } + .iradio_minimal-red.checked { + background-position: -140px 0; + } + .iradio_minimal-red.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-red.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-red, + .iradio_minimal-red { + background-image: url(red@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/red.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/red.png new file mode 100755 index 0000000..4443f80 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/red.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/red@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/red@2x.png new file mode 100755 index 0000000..2eb55a6 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/red@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/yellow.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/yellow.css new file mode 100755 index 0000000..5a84dbf --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/yellow.css @@ -0,0 +1,60 @@ +/* iCheck plugin Minimal skin, yellow +----------------------------------- */ +.icheckbox_minimal-yellow, +.iradio_minimal-yellow { + display: block; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(yellow.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_minimal-yellow { + background-position: 0 0; +} + .icheckbox_minimal-yellow.hover { + background-position: -20px 0; + } + .icheckbox_minimal-yellow.checked { + background-position: -40px 0; + } + .icheckbox_minimal-yellow.disabled { + background-position: -60px 0; + cursor: default; + } + .icheckbox_minimal-yellow.checked.disabled { + background-position: -80px 0; + } + +.iradio_minimal-yellow { + background-position: -100px 0; +} + .iradio_minimal-yellow.hover { + background-position: -120px 0; + } + .iradio_minimal-yellow.checked { + background-position: -140px 0; + } + .iradio_minimal-yellow.disabled { + background-position: -160px 0; + cursor: default; + } + .iradio_minimal-yellow.checked.disabled { + background-position: -180px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 1.5), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal-yellow, + .iradio_minimal-yellow { + background-image: url(yellow@2x.png); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/yellow.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/yellow.png new file mode 100755 index 0000000..0999b7e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/yellow.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/yellow@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/yellow@2x.png new file mode 100755 index 0000000..c16f2b7 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/minimal/yellow@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/polaris/polaris.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/polaris/polaris.css new file mode 100755 index 0000000..a43b80d --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/polaris/polaris.css @@ -0,0 +1,60 @@ +/* iCheck plugin Polaris skin +----------------------------------- */ +.icheckbox_polaris, +.iradio_polaris { + display: block; + margin: 0; + padding: 0; + width: 29px; + height: 29px; + background: url(polaris.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_polaris { + background-position: 0 0; +} + .icheckbox_polaris.hover { + background-position: -31px 0; + } + .icheckbox_polaris.checked { + background-position: -62px 0; + } + .icheckbox_polaris.disabled { + background-position: -93px 0; + cursor: default; + } + .icheckbox_polaris.checked.disabled { + background-position: -124px 0; + } + +.iradio_polaris { + background-position: -155px 0; +} + .iradio_polaris.hover { + background-position: -186px 0; + } + .iradio_polaris.checked { + background-position: -217px 0; + } + .iradio_polaris.disabled { + background-position: -248px 0; + cursor: default; + } + .iradio_polaris.checked.disabled { + background-position: -279px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_polaris, + .iradio_polaris { + background-image: url(polaris@2x.png); + -webkit-background-size: 310px 31px; + background-size: 310px 31px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/polaris/polaris.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/polaris/polaris.png new file mode 100755 index 0000000..60c14e6 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/polaris/polaris.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/polaris/polaris@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/polaris/polaris@2x.png new file mode 100755 index 0000000..c75b826 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/polaris/polaris@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/_all.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/_all.css new file mode 100755 index 0000000..3c836c3 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/_all.css @@ -0,0 +1,600 @@ +/* iCheck plugin Square skin +----------------------------------- */ +.icheckbox_square, +.iradio_square { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(square.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square { + background-position: 0 0; +} + .icheckbox_square.hover { + background-position: -24px 0; + } + .icheckbox_square.checked { + background-position: -48px 0; + } + .icheckbox_square.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square.checked.disabled { + background-position: -96px 0; + } + +.iradio_square { + background-position: -120px 0; +} + .iradio_square.hover { + background-position: -144px 0; + } + .iradio_square.checked { + background-position: -168px 0; + } + .iradio_square.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square, + .iradio_square { + background-image: url(square@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} + +/* red */ +.icheckbox_square-red, +.iradio_square-red { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(red.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-red { + background-position: 0 0; +} + .icheckbox_square-red.hover { + background-position: -24px 0; + } + .icheckbox_square-red.checked { + background-position: -48px 0; + } + .icheckbox_square-red.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-red.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-red { + background-position: -120px 0; +} + .iradio_square-red.hover { + background-position: -144px 0; + } + .iradio_square-red.checked { + background-position: -168px 0; + } + .iradio_square-red.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-red.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-red, + .iradio_square-red { + background-image: url(red@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} + +/* green */ +.icheckbox_square-green, +.iradio_square-green { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(green.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-green { + background-position: 0 0; +} + .icheckbox_square-green.hover { + background-position: -24px 0; + } + .icheckbox_square-green.checked { + background-position: -48px 0; + } + .icheckbox_square-green.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-green.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-green { + background-position: -120px 0; +} + .iradio_square-green.hover { + background-position: -144px 0; + } + .iradio_square-green.checked { + background-position: -168px 0; + } + .iradio_square-green.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-green.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-green, + .iradio_square-green { + background-image: url(green@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} + +/* blue */ +.icheckbox_square-blue, +.iradio_square-blue { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(blue.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-blue { + background-position: 0 0; +} + .icheckbox_square-blue.hover { + background-position: -24px 0; + } + .icheckbox_square-blue.checked { + background-position: -48px 0; + } + .icheckbox_square-blue.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-blue.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-blue { + background-position: -120px 0; +} + .iradio_square-blue.hover { + background-position: -144px 0; + } + .iradio_square-blue.checked { + background-position: -168px 0; + } + .iradio_square-blue.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-blue.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-blue, + .iradio_square-blue { + background-image: url(blue@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} + +/* aero */ +.icheckbox_square-aero, +.iradio_square-aero { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(aero.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-aero { + background-position: 0 0; +} + .icheckbox_square-aero.hover { + background-position: -24px 0; + } + .icheckbox_square-aero.checked { + background-position: -48px 0; + } + .icheckbox_square-aero.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-aero.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-aero { + background-position: -120px 0; +} + .iradio_square-aero.hover { + background-position: -144px 0; + } + .iradio_square-aero.checked { + background-position: -168px 0; + } + .iradio_square-aero.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-aero.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-aero, + .iradio_square-aero { + background-image: url(aero@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} + +/* grey */ +.icheckbox_square-grey, +.iradio_square-grey { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(grey.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-grey { + background-position: 0 0; +} + .icheckbox_square-grey.hover { + background-position: -24px 0; + } + .icheckbox_square-grey.checked { + background-position: -48px 0; + } + .icheckbox_square-grey.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-grey.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-grey { + background-position: -120px 0; +} + .iradio_square-grey.hover { + background-position: -144px 0; + } + .iradio_square-grey.checked { + background-position: -168px 0; + } + .iradio_square-grey.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-grey.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-grey, + .iradio_square-grey { + background-image: url(grey@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} + +/* orange */ +.icheckbox_square-orange, +.iradio_square-orange { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(orange.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-orange { + background-position: 0 0; +} + .icheckbox_square-orange.hover { + background-position: -24px 0; + } + .icheckbox_square-orange.checked { + background-position: -48px 0; + } + .icheckbox_square-orange.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-orange.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-orange { + background-position: -120px 0; +} + .iradio_square-orange.hover { + background-position: -144px 0; + } + .iradio_square-orange.checked { + background-position: -168px 0; + } + .iradio_square-orange.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-orange.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-orange, + .iradio_square-orange { + background-image: url(orange@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} + +/* yellow */ +.icheckbox_square-yellow, +.iradio_square-yellow { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(yellow.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-yellow { + background-position: 0 0; +} + .icheckbox_square-yellow.hover { + background-position: -24px 0; + } + .icheckbox_square-yellow.checked { + background-position: -48px 0; + } + .icheckbox_square-yellow.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-yellow.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-yellow { + background-position: -120px 0; +} + .iradio_square-yellow.hover { + background-position: -144px 0; + } + .iradio_square-yellow.checked { + background-position: -168px 0; + } + .iradio_square-yellow.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-yellow.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-yellow, + .iradio_square-yellow { + background-image: url(yellow@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} + +/* pink */ +.icheckbox_square-pink, +.iradio_square-pink { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(pink.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-pink { + background-position: 0 0; +} + .icheckbox_square-pink.hover { + background-position: -24px 0; + } + .icheckbox_square-pink.checked { + background-position: -48px 0; + } + .icheckbox_square-pink.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-pink.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-pink { + background-position: -120px 0; +} + .iradio_square-pink.hover { + background-position: -144px 0; + } + .iradio_square-pink.checked { + background-position: -168px 0; + } + .iradio_square-pink.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-pink.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-pink, + .iradio_square-pink { + background-image: url(pink@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} + +/* purple */ +.icheckbox_square-purple, +.iradio_square-purple { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(purple.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-purple { + background-position: 0 0; +} + .icheckbox_square-purple.hover { + background-position: -24px 0; + } + .icheckbox_square-purple.checked { + background-position: -48px 0; + } + .icheckbox_square-purple.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-purple.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-purple { + background-position: -120px 0; +} + .iradio_square-purple.hover { + background-position: -144px 0; + } + .iradio_square-purple.checked { + background-position: -168px 0; + } + .iradio_square-purple.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-purple.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-purple, + .iradio_square-purple { + background-image: url(purple@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/aero.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/aero.css new file mode 100755 index 0000000..029ca25 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/aero.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, aero +----------------------------------- */ +.icheckbox_square-aero, +.iradio_square-aero { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(aero.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-aero { + background-position: 0 0; +} + .icheckbox_square-aero.hover { + background-position: -24px 0; + } + .icheckbox_square-aero.checked { + background-position: -48px 0; + } + .icheckbox_square-aero.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-aero.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-aero { + background-position: -120px 0; +} + .iradio_square-aero.hover { + background-position: -144px 0; + } + .iradio_square-aero.checked { + background-position: -168px 0; + } + .iradio_square-aero.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-aero.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-aero, + .iradio_square-aero { + background-image: url(aero@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/aero.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/aero.png new file mode 100755 index 0000000..1a332e6 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/aero.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/aero@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/aero@2x.png new file mode 100755 index 0000000..07c5a02 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/aero@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/blue.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/blue.css new file mode 100755 index 0000000..7e6b816 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/blue.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, blue +----------------------------------- */ +.icheckbox_square-blue, +.iradio_square-blue { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(blue.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-blue { + background-position: 0 0; +} + .icheckbox_square-blue.hover { + background-position: -24px 0; + } + .icheckbox_square-blue.checked { + background-position: -48px 0; + } + .icheckbox_square-blue.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-blue.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-blue { + background-position: -120px 0; +} + .iradio_square-blue.hover { + background-position: -144px 0; + } + .iradio_square-blue.checked { + background-position: -168px 0; + } + .iradio_square-blue.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-blue.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-blue, + .iradio_square-blue { + background-image: url(blue@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/blue.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/blue.png new file mode 100755 index 0000000..a3e040f Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/blue.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/blue@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/blue@2x.png new file mode 100755 index 0000000..8fdea12 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/blue@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/green.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/green.css new file mode 100755 index 0000000..791ef57 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/green.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, green +----------------------------------- */ +.icheckbox_square-green, +.iradio_square-green { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(green.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-green { + background-position: 0 0; +} + .icheckbox_square-green.hover { + background-position: -24px 0; + } + .icheckbox_square-green.checked { + background-position: -48px 0; + } + .icheckbox_square-green.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-green.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-green { + background-position: -120px 0; +} + .iradio_square-green.hover { + background-position: -144px 0; + } + .iradio_square-green.checked { + background-position: -168px 0; + } + .iradio_square-green.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-green.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-green, + .iradio_square-green { + background-image: url(green@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/green.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/green.png new file mode 100755 index 0000000..465824e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/green.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/green@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/green@2x.png new file mode 100755 index 0000000..784e874 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/green@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/grey.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/grey.css new file mode 100755 index 0000000..741d46b --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/grey.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, grey +----------------------------------- */ +.icheckbox_square-grey, +.iradio_square-grey { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(grey.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-grey { + background-position: 0 0; +} + .icheckbox_square-grey.hover { + background-position: -24px 0; + } + .icheckbox_square-grey.checked { + background-position: -48px 0; + } + .icheckbox_square-grey.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-grey.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-grey { + background-position: -120px 0; +} + .iradio_square-grey.hover { + background-position: -144px 0; + } + .iradio_square-grey.checked { + background-position: -168px 0; + } + .iradio_square-grey.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-grey.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-grey, + .iradio_square-grey { + background-image: url(grey@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/grey.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/grey.png new file mode 100755 index 0000000..f693758 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/grey.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/grey@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/grey@2x.png new file mode 100755 index 0000000..5d6341c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/grey@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/orange.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/orange.css new file mode 100755 index 0000000..4e0a14e --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/orange.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, orange +----------------------------------- */ +.icheckbox_square-orange, +.iradio_square-orange { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(orange.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-orange { + background-position: 0 0; +} + .icheckbox_square-orange.hover { + background-position: -24px 0; + } + .icheckbox_square-orange.checked { + background-position: -48px 0; + } + .icheckbox_square-orange.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-orange.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-orange { + background-position: -120px 0; +} + .iradio_square-orange.hover { + background-position: -144px 0; + } + .iradio_square-orange.checked { + background-position: -168px 0; + } + .iradio_square-orange.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-orange.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-orange, + .iradio_square-orange { + background-image: url(orange@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/orange.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/orange.png new file mode 100755 index 0000000..8460850 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/orange.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/orange@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/orange@2x.png new file mode 100755 index 0000000..b1f2319 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/orange@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/pink.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/pink.css new file mode 100755 index 0000000..888c229 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/pink.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, pink +----------------------------------- */ +.icheckbox_square-pink, +.iradio_square-pink { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(pink.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-pink { + background-position: 0 0; +} + .icheckbox_square-pink.hover { + background-position: -24px 0; + } + .icheckbox_square-pink.checked { + background-position: -48px 0; + } + .icheckbox_square-pink.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-pink.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-pink { + background-position: -120px 0; +} + .iradio_square-pink.hover { + background-position: -144px 0; + } + .iradio_square-pink.checked { + background-position: -168px 0; + } + .iradio_square-pink.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-pink.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-pink, + .iradio_square-pink { + background-image: url(pink@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/pink.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/pink.png new file mode 100755 index 0000000..9c8b4e2 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/pink.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/pink@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/pink@2x.png new file mode 100755 index 0000000..b1f3a6e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/pink@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/purple.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/purple.css new file mode 100755 index 0000000..6650f7b --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/purple.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, purple +----------------------------------- */ +.icheckbox_square-purple, +.iradio_square-purple { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(purple.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-purple { + background-position: 0 0; +} + .icheckbox_square-purple.hover { + background-position: -24px 0; + } + .icheckbox_square-purple.checked { + background-position: -48px 0; + } + .icheckbox_square-purple.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-purple.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-purple { + background-position: -120px 0; +} + .iradio_square-purple.hover { + background-position: -144px 0; + } + .iradio_square-purple.checked { + background-position: -168px 0; + } + .iradio_square-purple.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-purple.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-purple, + .iradio_square-purple { + background-image: url(purple@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/purple.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/purple.png new file mode 100755 index 0000000..6bfc16a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/purple.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/purple@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/purple@2x.png new file mode 100755 index 0000000..6d3c8b1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/purple@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/red.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/red.css new file mode 100755 index 0000000..08a65f5 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/red.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, red +----------------------------------- */ +.icheckbox_square-red, +.iradio_square-red { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(red.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-red { + background-position: 0 0; +} + .icheckbox_square-red.hover { + background-position: -24px 0; + } + .icheckbox_square-red.checked { + background-position: -48px 0; + } + .icheckbox_square-red.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-red.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-red { + background-position: -120px 0; +} + .iradio_square-red.hover { + background-position: -144px 0; + } + .iradio_square-red.checked { + background-position: -168px 0; + } + .iradio_square-red.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-red.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-red, + .iradio_square-red { + background-image: url(red@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/red.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/red.png new file mode 100755 index 0000000..749675a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/red.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/red@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/red@2x.png new file mode 100755 index 0000000..c05700a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/red@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/square.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/square.css new file mode 100755 index 0000000..c42b2f1 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/square.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, black +----------------------------------- */ +.icheckbox_square, +.iradio_square { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(square.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square { + background-position: 0 0; +} + .icheckbox_square.hover { + background-position: -24px 0; + } + .icheckbox_square.checked { + background-position: -48px 0; + } + .icheckbox_square.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square.checked.disabled { + background-position: -96px 0; + } + +.iradio_square { + background-position: -120px 0; +} + .iradio_square.hover { + background-position: -144px 0; + } + .iradio_square.checked { + background-position: -168px 0; + } + .iradio_square.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square, + .iradio_square { + background-image: url(square@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/square.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/square.png new file mode 100755 index 0000000..2a3c881 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/square.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/square@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/square@2x.png new file mode 100755 index 0000000..9b56c44 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/square@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/yellow.css b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/yellow.css new file mode 100755 index 0000000..8fb2965 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/yellow.css @@ -0,0 +1,60 @@ +/* iCheck plugin Square skin, yellow +----------------------------------- */ +.icheckbox_square-yellow, +.iradio_square-yellow { + display: block; + margin: 0; + padding: 0; + width: 22px; + height: 22px; + background: url(yellow.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox_square-yellow { + background-position: 0 0; +} + .icheckbox_square-yellow.hover { + background-position: -24px 0; + } + .icheckbox_square-yellow.checked { + background-position: -48px 0; + } + .icheckbox_square-yellow.disabled { + background-position: -72px 0; + cursor: default; + } + .icheckbox_square-yellow.checked.disabled { + background-position: -96px 0; + } + +.iradio_square-yellow { + background-position: -120px 0; +} + .iradio_square-yellow.hover { + background-position: -144px 0; + } + .iradio_square-yellow.checked { + background-position: -168px 0; + } + .iradio_square-yellow.disabled { + background-position: -192px 0; + cursor: default; + } + .iradio_square-yellow.checked.disabled { + background-position: -216px 0; + } + +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (-moz-min-device-pixel-ratio: 1.5), + only screen and (-o-min-device-pixel-ratio: 3/2), + only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_square-yellow, + .iradio_square-yellow { + background-image: url(yellow@2x.png); + -webkit-background-size: 240px 24px; + background-size: 240px 24px; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/yellow.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/yellow.png new file mode 100755 index 0000000..b6c0330 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/yellow.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/yellow@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/yellow@2x.png new file mode 100755 index 0000000..6b8e328 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/css/icheck/square/yellow@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/ie6-8.css b/gridplatform/bootstrap/static/bootstrap/genius/css/ie6-8.css new file mode 100644 index 0000000..fd976a4 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/ie6-8.css @@ -0,0 +1,3 @@ +.hideInIE8 { + display: none !important; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/jquery-ui-1.10.3.custom.css b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery-ui-1.10.3.custom.css new file mode 100755 index 0000000..e63c981 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery-ui-1.10.3.custom.css @@ -0,0 +1,1177 @@ +/*! jQuery UI - v1.10.3 - 2013-05-29 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Helvetica%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=2px&bgColorHeader=dddddd&bgTextureHeader=highlight_soft&bgImgOpacityHeader=50&borderColorHeader=dddddd&fcHeader=444444&iconColorHeader=0073ea&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=dddddd&fcContent=444444&iconColorContent=ff0084&bgColorDefault=f6f6f6&bgTextureDefault=highlight_soft&bgImgOpacityDefault=100&borderColorDefault=dddddd&fcDefault=0073ea&iconColorDefault=666666&bgColorHover=0073ea&bgTextureHover=highlight_soft&bgImgOpacityHover=25&borderColorHover=0073ea&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=dddddd&fcActive=ff0084&iconColorActive=454545&bgColorHighlight=ffffff&bgTextureHighlight=flat&bgImgOpacityHighlight=55&borderColorHighlight=cccccc&fcHighlight=444444&iconColorHighlight=0073ea&bgColorError=ffffff&bgTextureError=flat&bgImgOpacityError=55&borderColorError=ff0084&fcError=222222&iconColorError=ff0084&bgColorOverlay=eeeeee&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=80&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=60&thicknessShadow=4px&offsetTopShadow=-4px&offsetLeftShadow=-4px&cornerRadiusShadow=0px +* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { + display: none; +} +.ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.ui-helper-clearfix:before, +.ui-helper-clearfix:after { + content: ""; + display: table; + border-collapse: collapse; +} +.ui-helper-clearfix:after { + clear: both; +} +.ui-helper-clearfix { + min-height: 0; /* support: IE7 */ +} +.ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter:Alpha(Opacity=0); +} + +.ui-front { + z-index: 100; +} + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { + cursor: default !important; +} + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.ui-resizable { + position: relative; +} +.ui-resizable-handle { + position: absolute; + font-size: 0.1px; + display: block; +} +.ui-resizable-disabled .ui-resizable-handle, +.ui-resizable-autohide .ui-resizable-handle { + display: none; +} +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0; +} +.ui-resizable-s { + cursor: s-resize; + height: 7px; + width: 100%; + bottom: -5px; + left: 0; +} +.ui-resizable-e { + cursor: e-resize; + width: 7px; + right: -5px; + top: 0; + height: 100%; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0; + height: 100%; +} +.ui-resizable-se { + cursor: se-resize; + width: 12px; + height: 12px; + right: 1px; + bottom: 1px; +} +.ui-resizable-sw { + cursor: sw-resize; + width: 9px; + height: 9px; + left: -5px; + bottom: -5px; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: -5px; + top: -5px; +} +.ui-resizable-ne { + cursor: ne-resize; + width: 9px; + height: 9px; + right: -5px; + top: -5px; +} +.ui-selectable-helper { + position: absolute; + z-index: 100; + border: 1px dotted black; +} +.ui-accordion .ui-accordion-header { + display: block; + cursor: pointer; + position: relative; + margin-top: 2px; + padding: .5em .5em .5em .7em; + min-height: 0; /* support: IE7 */ +} +.ui-accordion .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-noicons { + padding-left: .7em; +} +.ui-accordion .ui-accordion-icons .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-header .ui-accordion-header-icon { + position: absolute; + left: .5em; + top: 50%; + margin-top: -8px; +} +.ui-accordion .ui-accordion-content { + padding: 1em 2.2em; + border-top: 0; + overflow: auto; +} +.ui-autocomplete { + position: absolute; + top: 0; + left: 0; + cursor: default; +} +.ui-button { + display: inline-block; + position: relative; + padding: 0; + line-height: normal; + margin-right: .1em; + cursor: pointer; + vertical-align: middle; + text-align: center; + overflow: visible; /* removes extra width in IE */ +} +.ui-button, +.ui-button:link, +.ui-button:visited, +.ui-button:hover, +.ui-button:active { + text-decoration: none; +} +/* to make room for the icon, a width needs to be set here */ +.ui-button-icon-only { + width: 2.2em; +} +/* button elements seem to need a little more width */ +button.ui-button-icon-only { + width: 2.4em; +} +.ui-button-icons-only { + width: 3.4em; +} +button.ui-button-icons-only { + width: 3.7em; +} + +/* button text element */ +.ui-button .ui-button-text { + display: block; + line-height: normal; +} +.ui-button-text-only .ui-button-text { + padding: .4em 1em; +} +.ui-button-icon-only .ui-button-text, +.ui-button-icons-only .ui-button-text { + padding: .4em; + text-indent: -9999999px; +} +.ui-button-text-icon-primary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 1em .4em 2.1em; +} +.ui-button-text-icon-secondary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 2.1em .4em 1em; +} +.ui-button-text-icons .ui-button-text { + padding-left: 2.1em; + padding-right: 2.1em; +} +/* no icon support for input elements, provide padding by default */ +input.ui-button { + padding: .4em 1em; +} + +/* button icon element(s) */ +.ui-button-icon-only .ui-icon, +.ui-button-text-icon-primary .ui-icon, +.ui-button-text-icon-secondary .ui-icon, +.ui-button-text-icons .ui-icon, +.ui-button-icons-only .ui-icon { + position: absolute; + top: 50%; + margin-top: -8px; +} +.ui-button-icon-only .ui-icon { + left: 50%; + margin-left: -8px; +} +.ui-button-text-icon-primary .ui-button-icon-primary, +.ui-button-text-icons .ui-button-icon-primary, +.ui-button-icons-only .ui-button-icon-primary { + left: .5em; +} +.ui-button-text-icon-secondary .ui-button-icon-secondary, +.ui-button-text-icons .ui-button-icon-secondary, +.ui-button-icons-only .ui-button-icon-secondary { + right: .5em; +} + +/* button sets */ +.ui-buttonset { + margin-right: 7px; +} +.ui-buttonset .ui-button { + margin-left: 0; + margin-right: -.3em; +} + +/* workarounds */ +/* reset extra padding in Firefox, see h5bp.com/l */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; +} +.ui-datepicker { + width: 17em; + padding: .2em .2em 0; + display: none; +} +.ui-datepicker .ui-datepicker-header { + position: relative; + padding: .2em 0; +} +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-next { + position: absolute; + top: 2px; + width: 1.8em; + height: 1.8em; +} +.ui-datepicker .ui-datepicker-prev-hover, +.ui-datepicker .ui-datepicker-next-hover { + top: 1px; +} +.ui-datepicker .ui-datepicker-prev { + left: 2px; +} +.ui-datepicker .ui-datepicker-next { + right: 2px; +} +.ui-datepicker .ui-datepicker-prev-hover { + left: 1px; +} +.ui-datepicker .ui-datepicker-next-hover { + right: 1px; +} +.ui-datepicker .ui-datepicker-prev span, +.ui-datepicker .ui-datepicker-next span { + display: block; + position: absolute; + left: 50%; + margin-left: -8px; + top: 50%; + margin-top: -8px; +} +.ui-datepicker .ui-datepicker-title { + margin: 0 2.3em; + line-height: 1.8em; + text-align: center; +} +.ui-datepicker .ui-datepicker-title select { + font-size: 1em; + margin: 1px 0; +} +.ui-datepicker select.ui-datepicker-month-year { + width: 100%; +} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { + width: 49%; +} +.ui-datepicker table { + width: 100%; + font-size: .9em; + border-collapse: collapse; + margin: 0 0 .4em; +} +.ui-datepicker th { + padding: .7em .3em; + text-align: center; + font-weight: bold; + border: 0; +} +.ui-datepicker td { + border: 0; + padding: 1px; +} +.ui-datepicker td span, +.ui-datepicker td a { + display: block; + padding: .2em; + text-align: right; + text-decoration: none; +} +.ui-datepicker .ui-datepicker-buttonpane { + background-image: none; + margin: .7em 0 0 0; + padding: 0 .2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} +.ui-datepicker .ui-datepicker-buttonpane button { + float: right; + margin: .5em .2em .4em; + cursor: pointer; + padding: .2em .6em .3em .6em; + width: auto; + overflow: visible; +} +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { + float: left; +} + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { + width: auto; +} +.ui-datepicker-multi .ui-datepicker-group { + float: left; +} +.ui-datepicker-multi .ui-datepicker-group table { + width: 95%; + margin: 0 auto .4em; +} +.ui-datepicker-multi-2 .ui-datepicker-group { + width: 50%; +} +.ui-datepicker-multi-3 .ui-datepicker-group { + width: 33.3%; +} +.ui-datepicker-multi-4 .ui-datepicker-group { + width: 25%; +} +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { + border-left-width: 0; +} +.ui-datepicker-multi .ui-datepicker-buttonpane { + clear: left; +} +.ui-datepicker-row-break { + clear: both; + width: 100%; + font-size: 0; +} + +/* RTL support */ +.ui-datepicker-rtl { + direction: rtl; +} +.ui-datepicker-rtl .ui-datepicker-prev { + right: 2px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next { + left: 2px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-prev:hover { + right: 1px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next:hover { + left: 1px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane { + clear: right; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button { + float: left; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, +.ui-datepicker-rtl .ui-datepicker-group { + float: right; +} +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { + border-right-width: 0; + border-left-width: 1px; +} +.ui-dialog { + position: absolute; + top: 0; + left: 0; + padding: .2em; + outline: 0; +} +.ui-dialog .ui-dialog-titlebar { + padding: .4em 1em; + position: relative; +} +.ui-dialog .ui-dialog-title { + float: left; + margin: .1em 0; + white-space: nowrap; + width: 90%; + overflow: hidden; + text-overflow: ellipsis; +} +.ui-dialog .ui-dialog-titlebar-close { + position: absolute; + right: .3em; + top: 50%; + width: 21px; + margin: -10px 0 0 0; + padding: 1px; + height: 20px; +} +.ui-dialog .ui-dialog-content { + position: relative; + border: 0; + padding: .5em 1em; + background: none; + overflow: auto; +} +.ui-dialog .ui-dialog-buttonpane { + text-align: left; + border-width: 1px 0 0 0; + background-image: none; + margin-top: .5em; + padding: .3em 1em .5em .4em; +} +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: right; +} +.ui-dialog .ui-dialog-buttonpane button { + margin: .5em .4em .5em 0; + cursor: pointer; +} +.ui-dialog .ui-resizable-se { + width: 12px; + height: 12px; + right: -5px; + bottom: -5px; + background-position: 16px 16px; +} +.ui-draggable .ui-dialog-titlebar { + cursor: move; +} +.ui-menu { + list-style: none; + padding: 2px; + margin: 0; + display: block; + outline: none; +} +.ui-menu .ui-menu { + margin-top: -3px; + position: absolute; +} +.ui-menu .ui-menu-item { + margin: 0; + padding: 0; + width: 100%; + /* support: IE10, see #8844 */ + list-style-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); +} +.ui-menu .ui-menu-divider { + margin: 5px -2px 5px -2px; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.ui-menu .ui-menu-item a { + text-decoration: none; + display: block; + padding: 2px .4em; + line-height: 1.5; + min-height: 0; /* support: IE7 */ + font-weight: normal; +} +.ui-menu .ui-menu-item a.ui-state-focus, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} + +.ui-menu .ui-state-disabled { + font-weight: normal; + margin: .4em 0 .2em; + line-height: 1.5; +} +.ui-menu .ui-state-disabled a { + cursor: default; +} + +/* icon support */ +.ui-menu-icons { + position: relative; +} +.ui-menu-icons .ui-menu-item a { + position: relative; + padding-left: 2em; +} + +/* left-aligned */ +.ui-menu .ui-icon { + position: absolute; + top: .2em; + left: .2em; +} + +/* right-aligned */ +.ui-menu .ui-menu-icon { + position: static; + float: right; +} +.ui-progressbar { + height: 2em; + text-align: left; + overflow: hidden; +} +.ui-progressbar .ui-progressbar-value { + margin: -1px; + height: 100%; +} +.ui-progressbar .ui-progressbar-overlay { + background: url("../img/animated-overlay.gif"); + height: 100%; + filter: alpha(opacity=25); + opacity: 0.25; +} +.ui-progressbar-indeterminate .ui-progressbar-value { + background-image: none; +} +.ui-slider { + position: relative; + text-align: left; +} +.ui-slider .ui-slider-handle { + position: absolute; + z-index: 2; + width: 1.2em; + height: 1.2em; + cursor: default; +} +.ui-slider .ui-slider-range { + position: absolute; + z-index: 1; + font-size: .7em; + display: block; + border: 0; + background-position: 0 0; +} + +/* For IE8 - See #6727 */ +.ui-slider.ui-state-disabled .ui-slider-handle, +.ui-slider.ui-state-disabled .ui-slider-range { + filter: inherit; +} + +.ui-slider-horizontal { + height: .8em; +} +.ui-slider-horizontal .ui-slider-handle { + top: -.3em; + margin-left: -.6em; +} +.ui-slider-horizontal .ui-slider-range { + top: 0; + height: 100%; +} +.ui-slider-horizontal .ui-slider-range-min { + left: 0; +} +.ui-slider-horizontal .ui-slider-range-max { + right: 0; +} + +.ui-slider-vertical { + width: .8em; + height: 100px; +} +.ui-slider-vertical .ui-slider-handle { + left: -.3em; + margin-left: 0; + margin-bottom: -.6em; +} +.ui-slider-vertical .ui-slider-range { + left: 0; + width: 100%; +} +.ui-slider-vertical .ui-slider-range-min { + bottom: 0; +} +.ui-slider-vertical .ui-slider-range-max { + top: 0; +} +.ui-spinner { + position: relative; + display: inline-block; + overflow: hidden; + padding: 0; + vertical-align: middle; +} +.ui-spinner-input { + border: none; + background: none; + color: inherit; + padding: 0; + margin: .2em 0; + vertical-align: middle; + margin-left: .4em; + margin-right: 22px; +} +.ui-spinner-button { + width: 16px; + height: 50%; + font-size: .5em; + padding: 0; + margin: 0; + text-align: center; + position: absolute; + cursor: default; + display: block; + overflow: hidden; + right: 0; +} +/* more specificity required here to overide default borders */ +.ui-spinner a.ui-spinner-button { + border-top: none; + border-bottom: none; + border-right: none; +} +/* vertical centre icon */ +.ui-spinner .ui-icon { + position: absolute; + margin-top: -8px; + top: 50%; + left: 0; +} +.ui-spinner-up { + top: 0; +} +.ui-spinner-down { + bottom: 0; +} + +/* TR overrides */ +.ui-spinner .ui-icon-triangle-1-s { + /* need to fix icons sprite */ + background-position: -65px -16px; +} +.ui-tabs { + position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ + padding: .2em; +} +.ui-tabs .ui-tabs-nav { + margin: 0; + padding: .2em .2em 0; +} +.ui-tabs .ui-tabs-nav li { + list-style: none; + float: left; + position: relative; + top: 0; + margin: 1px .2em 0 0; + border-bottom-width: 0; + padding: 0; + white-space: nowrap; +} +.ui-tabs .ui-tabs-nav li a { + float: left; + padding: .5em 1em; + text-decoration: none; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active { + margin-bottom: -1px; + padding-bottom: 1px; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active a, +.ui-tabs .ui-tabs-nav li.ui-state-disabled a, +.ui-tabs .ui-tabs-nav li.ui-tabs-loading a { + cursor: text; +} +.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { + cursor: pointer; +} +.ui-tabs .ui-tabs-panel { + display: block; + border-width: 0; + padding: 1em 1.4em; + background: none; +} +.ui-tooltip { + padding: 8px; + position: absolute; + z-index: 9999; + max-width: 300px; + -webkit-box-shadow: 0 0 5px #aaa; + box-shadow: 0 0 5px #aaa; +} +body .ui-tooltip { + border-width: 2px; +} + +/* Component containers +----------------------------------*/ +.ui-widget { + font-family: Helvetica,Arial,sans-serif; + font-size: 1.1em; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + font-family: Helvetica,Arial,sans-serif; + font-size: 1em; +} +.ui-widget-content { + border: 1px solid #dddddd; + background: #ffffff url(../img/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; + color: #444444; +} +.ui-widget-content a { + color: #444444; +} +.ui-widget-header { + border: 1px solid #dddddd; + background: #dddddd url(../img/ui-bg_highlight-soft_50_dddddd_1x100.png) 50% 50% repeat-x; + color: #444444; + font-weight: bold; +} +.ui-widget-header a { + color: #444444; +} + +/* Interaction states +----------------------------------*/ +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + border: 1px solid #dddddd; + background: #f6f6f6 url(../img/ui-bg_highlight-soft_100_f6f6f6_1x100.png) 50% 50% repeat-x; + font-weight: bold; + color: #0073ea; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited { + color: #0073ea; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + border: 1px solid #0073ea; + background: #0073ea url(../img/ui-bg_highlight-soft_25_0073ea_1x100.png) 50% 50% repeat-x; + font-weight: bold; + color: #ffffff; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited { + color: #ffffff; + text-decoration: none; +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active { + border: 1px solid #dddddd; + background: #ffffff url(../img/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; + font-weight: bold; + color: #ff0084; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #ff0084; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #cccccc; + background: #ffffff url(../img/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x; + color: #444444; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #444444; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #ff0084; + background: #ffffff url(../img/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x; + color: #222222; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #222222; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #222222; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); + background-image: none; +} +.ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + width: 16px; + height: 16px; +} +.ui-icon, +.ui-widget-content .ui-icon { + background-image: url(../img/ui-icons_ff0084_256x240.png); +} +.ui-widget-header .ui-icon { + background-image: url(../img/ui-icons_0073ea_256x240.png); +} +.ui-state-default .ui-icon { + background-image: url(../img/ui-icons_666666_256x240.png); +} +.ui-state-hover .ui-icon, +.ui-state-focus .ui-icon { + background-image: url(../img/ui-icons_ffffff_256x240.png); +} +.ui-state-active .ui-icon { + background-image: url(../img/ui-icons_454545_256x240.png); +} +.ui-state-highlight .ui-icon { + background-image: url(../img/ui-icons_0073ea_256x240.png); +} +.ui-state-error .ui-icon, +.ui-state-error-text .ui-icon { + background-image: url(../img/ui-icons_ff0084_256x240.png); +} + +/* positioning */ +.ui-icon-blank { background-position: 16px 16px; } +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-on { background-position: -96px -144px; } +.ui-icon-radio-off { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 2px; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 2px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 2px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 2px; +} + +/* Overlays */ +.ui-widget-overlay { + background: #eeeeee url(../img/ui-bg_flat_0_eeeeee_40x100.png) 50% 50% repeat-x; + opacity: .8; + filter: Alpha(Opacity=80); +} +.ui-widget-shadow { + margin: -4px 0 0 -4px; + padding: 4px; + background: #aaaaaa url(../img/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; + opacity: .6; + filter: Alpha(Opacity=60); + border-radius: 0px; +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/jquery-ui-1.10.3.custom.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery-ui-1.10.3.custom.min.css new file mode 100755 index 0000000..3939f4e --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery-ui-1.10.3.custom.min.css @@ -0,0 +1,5 @@ +/*! jQuery UI - v1.10.3 - 2013-05-29 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Helvetica%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=2px&bgColorHeader=dddddd&bgTextureHeader=highlight_soft&bgImgOpacityHeader=50&borderColorHeader=dddddd&fcHeader=444444&iconColorHeader=0073ea&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=dddddd&fcContent=444444&iconColorContent=ff0084&bgColorDefault=f6f6f6&bgTextureDefault=highlight_soft&bgImgOpacityDefault=100&borderColorDefault=dddddd&fcDefault=0073ea&iconColorDefault=666666&bgColorHover=0073ea&bgTextureHover=highlight_soft&bgImgOpacityHover=25&borderColorHover=0073ea&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=dddddd&fcActive=ff0084&iconColorActive=454545&bgColorHighlight=ffffff&bgTextureHighlight=flat&bgImgOpacityHighlight=55&borderColorHighlight=cccccc&fcHighlight=444444&iconColorHighlight=0073ea&bgColorError=ffffff&bgTextureError=flat&bgImgOpacityError=55&borderColorError=ff0084&fcError=222222&iconColorError=ff0084&bgColorOverlay=eeeeee&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=80&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=60&thicknessShadow=4px&offsetTopShadow=-4px&offsetLeftShadow=-4px&cornerRadiusShadow=0px +* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted #000}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:700;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:21px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:0;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:0}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:400}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:400;margin:-1px}.ui-menu .ui-state-disabled{font-weight:400;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url(../img/animated-overlay.gif);height:100%;filter:alpha(opacity=25);opacity:.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:0;background:0;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:0;border-bottom:0;border-right:0}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:0}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Helvetica,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Helvetica,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#fff url(../img/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#444}.ui-widget-content a{color:#444}.ui-widget-header{border:1px solid #ddd;background:#ddd url(../img/ui-bg_highlight-soft_50_dddddd_1x100.png) 50% 50% repeat-x;color:#444;font-weight:bold}.ui-widget-header a{color:#444}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ddd;background:#f6f6f6 url(../img/ui-bg_highlight-soft_100_f6f6f6_1x100.png) 50% 50% repeat-x;font-weight:bold;color:#0073ea}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#0073ea;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #0073ea;background:#0073ea url(../img/ui-bg_highlight-soft_25_0073ea_1x100.png) 50% 50% repeat-x;font-weight:bold;color:#fff}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#fff;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #ddd;background:#fff url(../img/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#ff0084}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#ff0084;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #ccc;background:#fff url(../img/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x;color:#444}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#444}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #ff0084;background:#fff url(../img/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#222}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#222}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url(../img/ui-icons_ff0084_256x240.png)}.ui-widget-header .ui-icon{background-image:url(../img/ui-icons_0073ea_256x240.png)}.ui-state-default .ui-icon{background-image:url(../img/ui-icons_666666_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(../img/ui-icons_ffffff_256x240.png)}.ui-state-active .ui-icon{background-image:url(../img/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(../img/ui-icons_0073ea_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(../img/ui-icons_ff0084_256x240.png)}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:2px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:2px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:2px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:2px}.ui-widget-overlay{background:#eee url(../img/ui-bg_flat_0_eeeeee_40x100.png) 50% 50% repeat-x;opacity:.8;filter:Alpha(Opacity=80)}.ui-widget-shadow{margin:-4px 0 0 -4px;padding:4px;background:#aaa url(../img/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.6;filter:Alpha(Opacity=60);border-radius:0} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.cleditor.css b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.cleditor.css new file mode 100755 index 0000000..ec1c50a --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.cleditor.css @@ -0,0 +1,24 @@ +.cleditorMain {border:1px solid #999; padding:0 1px 1px; background-color:white} +.cleditorMain iframe {border:none; margin:0; padding:0} +.cleditorMain textarea {border:none; margin:0; padding:0; overflow-y:scroll; font:10pt Arial,Verdana; resize:none; outline:none /* webkit grip focus */} +.cleditorToolbar {background: url('../img/toolbar.gif') repeat} +.cleditorGroup {float:left; height:26px} +.cleditorButton {float:left; width:24px; height:24px; margin:1px 0 1px 0; background: url('../img/buttons.gif')} +.cleditorDisabled {opacity:0.3; filter:alpha(opacity=30)} +.cleditorDivider {float:left; width:1px; height:23px; margin:1px 0 1px 0; background:#CCC} +.cleditorPopup {border:solid 1px #999; background-color:white; color:#333333; position:absolute; font:10pt Arial,Verdana; cursor:default; z-index:10000} +.cleditorList div {padding:2px 4px 2px 4px} +.cleditorList p, +.cleditorList h1, +.cleditorList h2, +.cleditorList h3, +.cleditorList h4, +.cleditorList h5, +.cleditorList h6, +.cleditorList font {padding:0; margin:0; background-color:Transparent} +.cleditorColor {width:150px; padding:1px 0 0 1px} +.cleditorColor div {float:left; width:14px; height:14px; margin:0 1px 1px 0} +.cleditorPrompt {background-color:#F6F7F9; padding:4px; font-size:8.5pt} +.cleditorPrompt input, +.cleditorPrompt textarea {font:8.5pt Arial,Verdana;} +.cleditorMsg {background-color:#FDFCEE; width:150px; padding:4px; font-size:8.5pt} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.easy-pie-chart.css b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.easy-pie-chart.css new file mode 100755 index 0000000..0b7be9e --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.easy-pie-chart.css @@ -0,0 +1,10 @@ +.easyPieChart { + position: relative; + text-align: center; +} + +.easyPieChart canvas { + position: absolute; + top: 0; + left: 0; +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.gritter.css b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.gritter.css new file mode 100755 index 0000000..f0fa3de --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.gritter.css @@ -0,0 +1,112 @@ +/* the norm */ +#gritter-notice-wrapper { + position:fixed; + top:20px; + right:20px; + width:301px; + z-index:9999; +} + +#gritter-notice-wrapper.top-left { + left: 20px; + right: auto; +} + +#gritter-notice-wrapper.bottom-right { + top: auto; + left: auto; + bottom: 20px; + right: 20px; +} + +#gritter-notice-wrapper.bottom-left { + top: auto; + right: auto; + bottom: 20px; + left: 20px; +} + +.gritter-item-wrapper { + position:relative; + margin:0 0 10px 0; +} + +.gritter-item { + background-color: rgba(0,0,0,0.8); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#cc000000', endColorstr='#cc000000',GradientType=0 ); /* IE6-8 */ + color:#fff; + padding:15px; + font-size: 11px; + -webkit-border-radius: 4px !important; + -moz-border-radius: 4px !important; + border-radius: 4px !important; + -webkit-box-shadow: 0px 1px 1px rgba(0,0,0,0.25); + -moz-box-shadow: 0px 1px 1px rgba(0,0,0,0.25); + box-shadow: 0px 1px 1px rgba(0,0,0,0.25); +} + +.hover .gritter-item {} + +.gritter-item p { + padding:0; + margin:0; + word-wrap:break-word; +} + +.gritter-close { + display:none; + position:absolute; + top:5px; + right:5px; + cursor:pointer; + width:12px; + height:12px; + background: url(../img/close-button-white.png); + opacity: .6; + +} + +.gritter-title { + font-size:14px; + font-weight:bold; + padding:0 0 7px 0; + display:block; + text-shadow:1px 1px 0 #000; /* Not supported by IE :( */ +} + +.gritter-image { + width:48px; + height:48px; + float:left; + margin: -5px 5px 5px -5px; +} + +.gritter-with-image, +.gritter-without-image { + padding:0; +} + +.gritter-with-image { + width:220px; + float:right; +} + +/* for the light (white) version of the gritter notice */ +.gritter-light .gritter-item { + background-color: rgba(255,255,255,0.8); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ccFFFFFF', endColorstr='#ccFFFFFF',GradientType=0 ); /* IE6-8 */ + color: #646464 !important; + -webkit-box-shadow: 0px 1px 1px rgba(0,0,0,0.25); + -moz-box-shadow: 0px 1px 1px rgba(0,0,0,0.25); + box-shadow: 0px 1px 1px rgba(0,0,0,0.25); +} + +.gritter-light .gritter-close { + background: url(../img/close-button.png); +} + + +.gritter-light .gritter-title { + color: #646464 !important; + text-shadow: none !important; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.noty.css b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.noty.css new file mode 100755 index 0000000..b589ebf --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/jquery.noty.css @@ -0,0 +1,105 @@ + +/* CORE STYLES */ + + /* noty bar */ + .noty_bar { + position: fixed; + display: none; + z-index: 9999999; + } + + /* noty_message */ + .noty_bar .noty_message { + text-align: center; + } + + /* noty close button */ + .noty_bar .noty_close { + cursor: pointer; + } + + /* noty modal */ + .noty_modal { + position: fixed; + width: 100%; + height: 100%; + background-color: #000; + z-index: 10000; + opacity: 0.6; + display: none; + left: 0; + top: 0; + } + + /* noty container for noty_layout_topLeft & noty_layout_topRight */ + ul.noty_cont { + position: fixed; + z-index: 10000000; + margin: 0px; + padding: 0px; + list-style: none; + width: 300px; + } + ul.noty_cont li { + position: relative; + float: left; + clear: both; + list-style: none; + padding: 0px; + margin: 10px 0 0 0; + width: 300px; /* Fix for: http://bugs.jquery.com/ticket/2278 */ + } + ul.noty_cont.noty_layout_topLeft {left:20px; top:20px;} + ul.noty_cont.noty_layout_topRight {right:40px; top:20px;} + ul.noty_cont.noty_layout_bottomLeft {left:20px; bottom:20px} + ul.noty_cont.noty_layout_bottomRight {right:40px; bottom:20px} + ul.noty_cont.noty_layout_topRight li {float:right} + +/* LAYOUTS */ + + /* noty_layout_top */ + .noty_bar.noty_layout_top { + top: 0; + left: 0; + width: 100%; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + } + + /* noty_layout_bottom */ + .noty_bar.noty_layout_bottom { + bottom: 0; + left: 0; + width: 100%; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + } + + /* noty_layout_center */ + .noty_bar.noty_layout_center { + top: 40%; + } + + /* noty_layout_topLeft & noty_layout_topRight */ + .noty_bar.noty_layout_topLeft, + .noty_bar.noty_layout_topRight, + .noty_bar.noty_layout_bottomLeft, + .noty_bar.noty_layout_bottomRight { + width: 100%; + clear: both; + position: relative; + } + + .noty_bar.noty_layout_topLeft .noty_message, + .noty_bar.noty_layout_topRight .noty_message, + .noty_bar.noty_layout_bottomLeft .noty_message, + .noty_bar.noty_layout_bottomRight .noty_message { + text-align: left; + } + + /* noty_layout_topCenter */ + .noty_bar.noty_layout_topCenter { + top: 20px; + } \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/buttons.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/buttons.less new file mode 100644 index 0000000..71dc102 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/buttons.less @@ -0,0 +1,200 @@ +/* Buttons +=================================================================== */ +.btn { + border: none; + .border-radius(2px); + text-shadow: none; + background: lighten(@grey,20%); + color: darken(@grey,20%); + + i { + margin-top: 2px; + } + +} + +.btn-primary { + color: #ffffff; + background: @blue; + + &:hover, + &.disabled, + &[disabled] { + background-color: darken(@blue,10%); + } + + &:active, + &.active { + background-color: darken(@blue,12%); + } +} + +.btn-warning { + color: #ffffff; + background: @lightOrange; + + &:hover, + &.disabled, + &[disabled] { + background-color: darken(@lightOrange,10%); + } + + &:active, + &.active { + background-color: darken(@lightOrange,12%); + } +} + +.btn-danger { + color: #ffffff; + background: @red; + + &:hover, + &.disabled, + &[disabled] { + background-color: darken(@red,10%); + } + + &:active, + &.active { + background-color: darken(@red,12%); + } +} + +.btn-success { + color: #ffffff; + background: @darkGreen; + + &:hover, + &.disabled, + &[disabled] { + background-color: darken(@darkGreen,10%); + } + + &:active, + &.active { + background-color: darken(@darkGreen,12%); + } +} + + +.btn-info { + color: #ffffff; + background: @lightBlue; + + &:hover, + &.disabled, + &[disabled] { + background-color: darken(@lightBlue,10%); + } + + &:active, + &.active { + background-color: darken(@lightBlue,12%); + } +} + +.btn-inverse { + color: #ffffff; + background: @inverse; + + &:hover, + &.disabled, + &[disabled] { + background-color: darken(@inverse,10%); + color: #ffffff; + } + + &:active, + &.active { + background-color: darken(@inverse,12%); + } +} + +.btn-facebook, +.btn-twitter, +.btn-linkedin { + color: white; + position:relative; + text-align: center; + height: 40px; + width: 100%; + font-family: 'FontAwesome'; + font-weight: bold; + padding: 10px 0; + + &:before { + position: absolute; + display: block; + height: 40px; + width: 40px; + top: 0; + left: 0; + .border-radius(2px); + font-size: 20px; + padding: 6px 0; + } + + span { + margin-left: 40px; + } + + &:hover { + color: white; + } +} + +.btn-facebook { + background: #3b5998; + + &:before { + content: "\f09a"; + background: darken(#3b5998, 5%); + } + + &:hover { + background: darken(#3b5998, 5%); + + &:before { + background: darken(#3b5998, 10%); + } + + } + +} + +.btn-twitter { + background: #00aced; + + &:before { + content: "\f099"; + background: darken(#00aced, 5%); + } + + &:hover { + background: darken(#00aced, 5%); + + &:before { + background: darken(#00aced, 10%); + } + + } +} + +.btn-linkedin { + background: #4875B4; + + &:before { + content: "\f0e1"; + background: darken(#4875B4, 5%); + } + + &:hover { + background: darken(#4875B4, 5%); + + &:before { + background: darken(#4875B4, 10%); + } + + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/calendar.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/calendar.less new file mode 100644 index 0000000..50b8336 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/calendar.less @@ -0,0 +1,143 @@ +/* Calendar Widget +=================================================================== */ +.calendar { + background: white; + + .calendar-details { + background: lighten(@grey, 15%); + color: white; + font-weight: 300px; + position: relative; + padding: 20px; + + .day { + font-size: 20px; + text-transform: uppercase; + float: left; + margin: 10px; + } + + .date { + font-size: 20px; + margin: 10px; + text-transform: uppercase; + } + + ul.events { + list-style: none; + margin: 0; + padding: 0; + li { + margin: 0px 10px; + } + } + + .add-event { + display: block; + bottom: 10px; + border-bottom: @grey; + padding: 13px 5px 0 5px; + + + input { + width: 100%; + color: white; + border: 0; + font-size: 12px; + margin: 0; + padding: 5px; + .box-shadow; + .border-radius(2px); + background: lighten(@grey, 10%); + z-index: 9; + + } + + } + } + + .fc td, + .fc th { + + } + + .fc { + padding: 20px; + .box-sizing(content-box); + } + + .fc-widget-header, + .fc-widget-content { + border-color: lighten(@grey,20%); + } + + .fc-state-default { + background: white; + border: none; + color: @grey; + text-shadow: none; + .box-shadow; + margin-top: -5px; + margin-left: -10px; + } + + .fc-state-hover, + .fc-state-down, + .fc-state-active, + .fc-state-disabled { + color: @darkGrey; + background: white; + } + + .fc-day { + //display: none; + } + + .fc-day-number { + margin: 0px 0 0 -30px; + padding: 5px !important; + text-align: left; + font-size: 10px; + font-weight: 300; + + } + + .fc-state-highlight { + background: transparent; + + .fc-day-number { + color: @mainColor; + font-weight: 700; + } + } + + .event { + background: @mainColor; + .border-radius(4px); + color: white; + + } + + .fc-grid .fc-day-number { + float: none; + padding: 0 2px; + text-align: center; + } + + .fc-grid .fc-other-month .fc-day-number { + opacity: 1; + filter: alpha(opacity=1); + color: @grey; + } + + .fc-event { + border: 0; + height: 1px; + background: @grey; + //display: none; + + .fc-event-inner { + display: none; + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/charts.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/charts.less new file mode 100644 index 0000000..72debe3 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/charts.less @@ -0,0 +1,155 @@ +/* Vertical Bar Chart +=================================================================== */ +.verticalChart { + + margin: 10px; + + .singleBar { + width: 6%; + display:block; + margin:0 2% 0% 2%; + float: left; + + .bar { + position: relative; + height: 120px; + background: #f9f9f9; + overflow: hidden; + .border-radius(2px); + + .value { + position: absolute; + bottom: 0; + width: 100%; + background: @green; + color: white; + .border-radius(2px); + + span { + position: absolute; + font-size: 12px; + bottom: 0; + width: 100%; + height: 20px; + color: white; + text-shadow: 0px -1px 0px @green, 0px 1px 0px @green, 1px 0px 0px @green, -1px 0px 0px @green, -1px -1px 0px @green,-1px 1px 0px @green, 1px 1px 0px @green, 1px -1px 0px @green; + display: none; + text-align: center; + } + } + } + + .title { + margin-top: 5px; + text-align: center; + color: @darkGrey; + } + } +} + +/* Browsers Stats +=================================================================== */ +.browserStat.big { + display:inline-block; + width: 49%; + text-align: center; + margin-bottom: 20px; + padding: 0px; +} + +.browserStat { + display:inline-block; + width: 32%; + text-align: center; + margin: 0px; + padding: 0px; + + span { + display:block; + text-align: center; + margin-top: 10px; + } +} + +/* Small Chart +=================================================================== */ +.smallchart { + background: white; + text-align: center; + + .title { + padding: 10px; + color: white; + background: lighten(@grey, 15%); + } + + .content { + padding: 40px 0px; + background: lighten(@grey, 15%); + + i { + font-size: 40px; + color: white; + } + + } + + .value { + color: @darkGrey; + padding: 10px; + } + + .backgroundColorTitle; + +} + +/* Sparkline stats +=================================================================== */ +.sparkLineStats { + position: relative; + margin-bottom: -4px; + + ul { + margin:0 0 0 -40px; + list-style: none; + + li { + margin-bottom: 0; + line-height: 32px; + padding-top:3px; + font-size: 12px; + + div { + float: left; + + &:first-child { + margin-right: 5px; + } + } + + .number { + font-size: 17px; + font-weight: 700; + padding:0px 0px 0px 2px; + color: @orange; + } + + h4 { + position: relative; + border-bottom: 1px solid #c4c4c4; + padding-bottom: 0px; + margin-bottom: 10px; + line-height: 37px; + .box-shadow(0 1px 0px rgba(255, 255, 255, 1)); + } + } + } +} + +/* Chart.JS responsive fix +=================================================================== */ +canvas.chartjs { + width: 100% !important; + max-width: 2000px; + height: auto !important; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/chat.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/chat.less new file mode 100644 index 0000000..a100394 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/chat.less @@ -0,0 +1,197 @@ +/* Chat Widget +=================================================================== */ +.chat { + position: relative; + background: white; + + .contacts { + position: absolute; + height: 100%; + float: left; + width:30%; + background: lighten(@grey,20%); + border-right: 1px solid lighten(@grey,15%); + + ul.list { + list-style: none; + margin: 0; + padding: 0; + + li { + position: relative; + padding: 5px 10px; + border-bottom: 1px solid lighten(@grey,15%); + cursor: pointer; + + &:hover{ + background: @grey; + } + + img.avatar { + .border-radius(2px); + width: 40px; + margin-right: 10px; + } + + .status { + display: block; + position: absolute; + top: 42%; + right: 20px; + width: 8px; + height: 8px; + .border-radius(2px); + + &.online { + background: @green; + } + + &.offline { + background: @grey; + } + + &.busy { + background: @orange; + } + } + + .important { + font-size: 11px; + display: inline-block; + position: absolute; + top: 1px; + left: 35px; + font-size: 10px; + + padding: 3px 7px; + color: white; + .border-radius(2px); + background: @red; + } + + } + + } + + } + + .conversation { + width:70%; + float: right; + + .actions { + background: @darkGrey; + width: 100%; + height: 50px; + + a { + display: block; + color: white; + padding: 16px; + font-size: 18px; + width: 18px; + float: left; + } + + img.avatar { + .border-radius(2px); + width: 30px; + margin: 10px 0px 10px 10px; + } + } + + ul { + height: 516px; + overflow-y: scroll; + list-style: none; + margin:0; + padding:0; + + li { + position: relative; + padding: 15px 10px 10px 60px; + border-bottom: 1px solid lighten(@grey,15%); + + img.avatar { + top: 10px; + left: 10px; + position: absolute; + .border-radius(2px); + width: 40px; + margin-right: 10px; + } + + .name { + font-weight: bold; + text-transform: uppercase; + } + + .time { + font-weight: bold; + right: 10px; + position: absolute; + color: @grey; + font-size: 11px; + } + + .message { + margin-top: 10px; + font-size: 12px; + } + } + } + + .form { + border-top: 2px solid lighten(@grey,15%); + height: 60px; + padding: 10px; + + input { + .border-radius(2px); + .box-shadow; + .box-sizing; + width: 100%; + height: 100%; + } + } + } + + &.alt { + + .contacts { + width: 60px; + + ul.list { + list-style: none; + margin: 0; + padding: 0; + + li { + text-align: center; + + img.avatar { + .border-radius(2px); + width: 40px; + margin: 0 auto; + } + + .name { + display: none; + } + + .status { + top: 70%; + right: 10px; + } + } + } + } + + .conversation { + width:auto; + margin-left: 60px; + } + + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/circle-stats.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/circle-stats.less new file mode 100644 index 0000000..ca19ca0 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/circle-stats.less @@ -0,0 +1,217 @@ +/* Circle stats +=================================================================== */ +.tempStats { + text-align: center !important; +} + +.tempStatBox { + width: 120px; + padding: 25px 0px; + .box-sizing(content-box); + margin: 0 auto; + + .tempStat { + position: relative; + font-size: 34px; + line-height: 100px; + .border-radius(50em); + border: 10px solid #FFF; + background: #f9f9f9; + height: 100px; + width: 100px; + text-align: center; + margin: 0 auto; + .box-sizing(content-box); + + &:before { + content:""; + top: -10px; + left: -10px; + height: 120px; + width: 120px; + position:absolute; + .border-radius(50em); + background: transparent; + .box-shadow-double(inset 0px 1px 1px rgba(0,0,0,.3), 0px 1px 0px #fff); + .box-sizing(content-box); + } + + &:after { + content:""; + top: 0px; + left: 0px; + height: 98px; + width: 98px; + position:absolute; + .border-radius(50em); + border: 1px solid #fff; + background: transparent; + .box-shadow(0px 0px 1px rgba(0,0,0,.4)); + .box-sizing(content-box); + } + } + + .tempStat.t0 { + border-color: @lightBlue; + } + + .tempStat.t20 { + border-color: @green; + } + + .tempStat.t40 { + border-color: @yellow; + } + + .tempStat.t60 { + border-color: @lightOrange; + } + + .tempStat.t80 { + border-color: @orange; + } + + .tempStat.t100 { + border-color: @red; + } + + span { + width: 100%; + text-align: center; + display: block; + margin-top: 10px; + text-shadow: 0px 1px 0px #fff; + } +} + +/* Circle stats +=================================================================== */ +.circleStats {text-align: center; position: relative;} +.circleStatsItem { + position: relative; + background: rgba(255,255,255,0.7); + .box-shadow-double(inset 0 0px 0 2px rgba(0,0,0,.2), 0 0px 0 4px rgba(0,0,0,.1)); + .border-radius(50em); + width:120px; + height: 120px; + margin: 10px auto; + + + i { + font-size: 30px; + position: absolute; + top:30%; + margin-top: 0px; + width: 100%; + text-align: center + } + + input { + cursor: default; + .box-shadow; + border:none; + height: auto; + position: absolute; + top:15px; + left: 120px; + padding: 5px 0px !important; + border-color: rgba(0, 0, 0, 0.8); + + &:focus { + outline: 0; + outline: thin dotted 0; + .box-shadow; + } + } + + .plus { + font-size: 16px; + position: absolute; + top:55%; + margin-left: 30px; + } + + .percent { + font-size: 14px; + position: absolute; + top:57%; + margin-left: 78px; + } +} + +.circleStatsItem.orange, .circleStatsItem.orange i {color:@orange; } +.circleStatsItem.lightorange, .circleStatsItem.lightorange i {color:@lightOrange; } +.circleStatsItem.blue, .circleStatsItem.blue i {color:@blue; } +.circleStatsItem.green, .circleStatsItem.green i {color:@green; } +.circleStatsItem.yellow, .circleStatsItem.yellow i {color:@yellow; } +.circleStatsItem.pink, .circleStatsItem.pink i {color:@pink; } + +.circleStatsItemBox { + position: relative; + background: @lightBlue; + width:100%; + min-width: 130px; + height: 160px; + margin: 10px auto; + padding-top: 40px; + .box-sizing(content-box); + + .header { + background: rgba(255,255,255,0.2); + color: rgba(255,255,255,0.9); + width: 100%; + height: 20px; + padding: 5px 0px; + position: absolute; + top: 0px; + .box-sizing(content-box); + } + + .footer { + background: rgba(0,0,0,0.1); + color: rgba(255,255,255,0.9); + width: 100%; + height: 20px; + padding: 5px 0px; + position: absolute; + bottom: 0px; + .box-sizing(content-box); + + .count{ + font-size: 10px; + } + + .value{ + font-weight: bold; + } + } + + .percent { + font-size: 12px; + position: absolute; + top:110px; + width: 100%; + left: 0px; + text-align: center; + color: rgba(255,255,255,0.9); + } + + input { + cursor: default; + .box-shadow; + border:none; + height: auto; + position: absolute; + top:30px; + padding: 5px 0px !important; + border-color: rgba(0, 0, 0, 0.8); + + &:focus { + outline: 0; + outline: thin dotted 0; + .box-shadow; + } + + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/collapse.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/collapse.less new file mode 100644 index 0000000..53d855a --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/collapse.less @@ -0,0 +1,15 @@ +/* Collapse +=================================================================== */ +.panel-group { + + .panel { + .border-radius; + .box-shadow; + border: 1px solid lighten(@grey, 15%); + + .panel-heading { + background: lighten(@grey, 25%); + } + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/colorpicker.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/colorpicker.less new file mode 100755 index 0000000..26b8105 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/colorpicker.less @@ -0,0 +1,135 @@ +/* + * Colorpicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ + +.colorpicker-saturation { + width: 100px; + height: 100px; + background-image: url(../img/saturation.png); + cursor: crosshair; + float: left; + i { + display: block; + height: 5px; + width: 5px; + border: 1px solid #000; + .border-radius(); + position: absolute; + top: 0; + left: 0; + margin: -4px 0 0 -4px; + b{ + display: block; + height: 5px; + width: 5px; + border: 1px solid #fff; + .border-radius(); + } + } +} +.colorpicker-hue, +.colorpicker-alpha { + width: 15px; + height: 100px; + float: left; + cursor: row-resize; + margin-left: 4px; + margin-bottom: 4px; + i { + display: block; + height: 1px; + background: #000; + border-top: 1px solid #fff; + position: absolute; + top: 0; + left: 0; + width: 100%; + margin-top: -1px; + } +} +.colorpicker-hue { + background-image: url(../img/hue.png); +} +.colorpicker-alpha { + background-image: url(../img/alpha.png); + display:none; +} +.colorpicker { + .clearfix(); + top: 0; + left: 0; + padding: 4px; + min-width: 120px; + margin-top: 1px; + .border-radius(4px); + &:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0,0,0,.2); + position: absolute; + top: -7px; + left: 6px; + } + &:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid white; + position: absolute; + top: -6px; + left: 7px; + } + div { + position: relative; + } + &.alpha { + min-width: 140px; + .colorpicker-alpha { + display: block; + } + } +} +.colorpicker-color { + height: 10px; + margin-top: 5px; + clear: both; + background-image: url(../img/alpha.png); + background-position: 0 100%; + div { + height: 10px; + } +} +.input-append, +.input-prepend { + &.color { + .add-on i { + display: block; + cursor: pointer; + width: 16px; + height: 16px; + } + } +} + +.input-group { + + &.color { + + .input-group-addon i { + display: block; + cursor: pointer; + width: 13px; + } + + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/colors.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/colors.less new file mode 100644 index 0000000..b4f7220 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/colors.less @@ -0,0 +1,85 @@ +/* Main Colors +=================================================================== */ +@blue: #36A9E1; +@lightBlue: #67c2ef; +@green: #bdea74; +@darkGreen: #78cd51; +@pink: #e84c8a; +@orange: #fa603d; +@lightOrange: #fabb3d; +@red: #ff5454; +@yellow: #eae874; +@inverse: #444; +@lightGrey: #f9f9f9; +@darkGrey: #34383c; +@grey: lighten(@darkGrey, 50%); +@borderGrey: #eee; + +@mainColor: @blue; +@bodyBackground: #f3f3f3; + +.blue { color: @blue; } +.lightBlue { color: @lightBlue; } +.green { color: @green; } +.darkGreen { color: @darkGreen; } +.pink { color: @pink; } +.orange { color: @orange; } +.lightOrange { color: @lightOrange; } +.red { color: @red; } +.yellow { color: @yellow; } +.white { color: white; } +.grey { color: @grey; } + +.backgroundColor { + + &.blue { background: @blue; } + &.lightBlue { background: @lightBlue; } + &.green { background: @green; } + &.darkGreen { background: @darkGreen; } + &.pink { background: @pink; } + &.orange { background: @orange; } + &.lightOrange { background: @lightOrange; } + &.red { background: @red; } + &.yellow { background: @yellow; } + &.white { background: white; } + &.grey { background: @grey; } + +} + +.backgroundColorTitle { + + &.blue { + .title { background: @blue; } + } + &.lightBlue { + .title { background: @lightBlue; } + } + &.green { + .title { background: @green; } + } + &.darkGreen { + .title { background: @darkGreen; } + } + &.pink { + .title { background: @pink; } + } + &.orange { + .title { background: @orange; } + } + &.lightOrange { + .title { background: @lightOrange; } + } + &.red { + .title { background: @red; } + } + &.yellow { + .title { background: @yellow; } + } + &.white { + .title { background: white; } + } + &.grey { + .title { background: @grey; } + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/comments-list.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/comments-list.less new file mode 100644 index 0000000..bafd25a --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/comments-list.less @@ -0,0 +1,55 @@ +/* Comments Lists ex. +=================================================================== */ +ul.comments-list { + padding: 0; + + a:hover { + text-decoration:none; + } + + li:last-child { + border-bottom: none; + } + + li:first-child { + border-top: none; + border-bottom: 1px solid lighten(@grey,20%); + } + + li { + padding: 5px 10px; + list-style:none; + border-bottom: 1px solid lighten(@grey,20%); + font-size: 12px; + + a { + + img.avatar { + height: 50px; + width: 50px; + float: left; + margin-top: 3px; + margin-right: 15px; + .border-radius(2px); + } + } + + div { + margin-left: 65px; + + &.date { + margin-top: 5px; + font-size: 10px; + font-weight: bold; + color: @grey; + } + } + } + + &.no-padding { + + li { + padding: 5px 0; + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/dashboard-list.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/dashboard-list.less new file mode 100644 index 0000000..1b3b445 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/dashboard-list.less @@ -0,0 +1,55 @@ +/* Dashboard Lists +=================================================================== */ +ul.dashboard-list { + padding: 0; + + a:hover { + text-decoration:none; + } + + li:last-child { + border-bottom: none; + } + + li:first-child { + border-top: none; + border-bottom: 1px solid lighten(@grey,20%); + } + + li { + padding: 5px 0; + list-style:none; + border-bottom: 1px solid lighten(@grey,20%); + font-size: 12px; + + a { + + span { + display: inline-block; + font-size: 18px; + font-weight: bold; + margin-right: 10px; + text-align: right; + width: 50px; + zoom: 1; + } + + img.avatar { + height: 50px; + width: 50px; + float: left; + margin-top: 3px; + margin-right: 15px; + .border-radius(2px); + } + } + + + i { + font-size: 18px; + opacity: .7; + filter: alpha(opacity=70); + -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/datatables.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/datatables.less new file mode 100644 index 0000000..5b098dd --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/datatables.less @@ -0,0 +1,211 @@ +div.dataTables_length label { + font-weight: normal; + float: left; + text-align: left; +} + +div.dataTables_length select { + width: 75px; +} + +div.dataTables_filter label { + font-weight: normal; + float: right; +} + +div.dataTables_info { + padding-top: 8px; +} + +div.dataTables_paginate { + float: right; + margin: 0; +} + +div.dataTables_paginate ul.pagination { + margin: 2px; +} + +table.table { + clear: both; + margin-top: 6px !important; + margin-bottom: 6px !important; + max-width: none !important; + + .btn { + margin: 1px 0; + } +} + +table.table thead .sorting, +table.table thead .sorting_asc, +table.table thead .sorting_desc, +table.table thead .sorting_asc_disabled, +table.table thead .sorting_desc_disabled { + cursor: pointer; +} + +table.table thead .sorting { background: url('../img/sort_both.png') no-repeat center right; } +table.table thead .sorting_asc { background: url('../img/sort_asc.png') no-repeat center right; } +table.table thead .sorting_desc { background: url('../img/sort_desc.png') no-repeat center right; } + +table.table thead .sorting_asc_disabled { background: url('../img/sort_asc_disabled.png') no-repeat center right; } +table.table thead .sorting_desc_disabled { background: url('../img/sort_desc_disabled.png') no-repeat center right; } + +table.dataTable th:active { + outline: none; +} + +/* Scrolling */ +div.dataTables_scrollHead table { + margin-bottom: 0 !important; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +div.dataTables_scrollHead table thead tr:last-child th:first-child, +div.dataTables_scrollHead table thead tr:last-child td:first-child { + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +div.dataTables_scrollBody table { + border-top: none; + margin-bottom: 0 !important; +} + +div.dataTables_scrollBody tbody tr:first-child th, +div.dataTables_scrollBody tbody tr:first-child td { + border-top: none; +} + +div.dataTables_scrollFoot table { + border-top: none; +} + + +/* + * TableTools styles + */ +.table tbody tr.active td, +.table tbody tr.active th { + background-color: #08C; + color: white; +} + +.table tbody tr.active:hover td, +.table tbody tr.active:hover th { + background-color: #0075b0 !important; +} + +.table-striped tbody tr.active:nth-child(odd) td, +.table-striped tbody tr.active:nth-child(odd) th { + background-color: #017ebc; +} + +table.DTTT_selectable tbody tr { + cursor: pointer; +} + +div.DTTT .btn { + color: #333 !important; + font-size: 12px; +} + +div.DTTT .btn:hover { + text-decoration: none !important; +} + +ul.DTTT_dropdown.dropdown-menu { + z-index: 2003; +} + +ul.DTTT_dropdown.dropdown-menu a { + color: #333 !important; /* needed only when demo_page.css is included */ +} + +ul.DTTT_dropdown.dropdown-menu li { + position: relative; +} + +ul.DTTT_dropdown.dropdown-menu li:hover a { + background-color: #0088cc; + color: white !important; +} + +/* TableTools information display */ +div.DTTT_print_info.modal { + height: 150px; + margin-top: -75px; + text-align: center; +} + +div.DTTT_print_info h6 { + font-weight: normal; + font-size: 28px; + line-height: 28px; + margin: 1em; +} + +div.DTTT_print_info p { + font-size: 14px; + line-height: 20px; +} + + + +/* + * FixedColumns styles + */ +div.DTFC_LeftHeadWrapper table, +div.DTFC_LeftFootWrapper table, +div.DTFC_RightHeadWrapper table, +div.DTFC_RightFootWrapper table, +table.DTFC_Cloned tr.even { + background-color: white; +} + +div.DTFC_RightHeadWrapper table , +div.DTFC_LeftHeadWrapper table { + margin-bottom: 0 !important; + border-top-right-radius: 0 !important; + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child, +div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child, +div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child, +div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child { + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +div.DTFC_RightBodyWrapper table, +div.DTFC_LeftBodyWrapper table { + border-top: none; + margin-bottom: 0 !important; +} + +div.DTFC_RightBodyWrapper tbody tr:first-child th, +div.DTFC_RightBodyWrapper tbody tr:first-child td, +div.DTFC_LeftBodyWrapper tbody tr:first-child th, +div.DTFC_LeftBodyWrapper tbody tr:first-child td { + border-top: none; +} + +div.DTFC_RightFootWrapper table, +div.DTFC_LeftFootWrapper table { + border-top: none; +} + +/* Retina Display Hack +=================================================================== */ +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { + table.table thead .sorting { background: url('../img/sort_both@2x.png') no-repeat center right; background-size: 19px 19px;} + table.table thead .sorting_asc { background: url('../img/sort_asc@2x.png') no-repeat center right; background-size: 19px 19px;} + table.table thead .sorting_desc { background: url('../img/sort_desc@2x.png') no-repeat center right; background-size: 19px 19px;} + + table.table thead .sorting_asc_disabled { background: url('../img/sort_asc_disabled@2x.png') no-repeat center right; background-size: 19px 19px;} + table.table thead .sorting_desc_disabled { background: url('../img/sort_desc_disabled@2x.png') no-repeat center right; background-size: 19px 19px;} +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/datepicker.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/datepicker.less new file mode 100755 index 0000000..90942c2 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/datepicker.less @@ -0,0 +1,256 @@ +/* + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ + +.datepicker { + padding: 4px; + .border-radius(4px); + &-inline { + width: 220px; + } + direction: ltr; + &&-rtl { + direction: rtl; + table tr td span { + float: right; + } + } + &-dropdown { + top: 0; + left: 0; + &:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-top: 0; + border-bottom-color: rgba(0,0,0,.2); + position: absolute; + } + &:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid white; + border-top: 0; + position: absolute; + } + &.datepicker-orient-left:before { left: 6px; } + &.datepicker-orient-left:after { left: 7px; } + &.datepicker-orient-right:before { right: 6px; } + &.datepicker-orient-right:after { right: 7px; } + &.datepicker-orient-top:before { top: -7px; } + &.datepicker-orient-top:after { top: -6px; } + &.datepicker-orient-bottom:before { + bottom: -7px; + border-bottom: 0; + border-top: 7px solid #999; + } + &.datepicker-orient-bottom:after { + bottom: -6px; + border-bottom: 0; + border-top: 6px solid white; + } + } + >div { + display: none; + } + &.days div.datepicker-days { + display: block; + } + &.months div.datepicker-months { + display: block; + } + &.years div.datepicker-years { + display: block; + } + table{ + margin: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + td, + th{ + text-align: center; + width: 20px; + height: 20px; + .border-radius(4px); + + border: none; + } + // Inline display inside a table presents some problems with + // border and background colors. + .table-striped & table tr { + td, th { + background-color:transparent; + } + } + table tr td { + &.day:hover { + background: #eee; + cursor: pointer; + } + &.old, + &.new { + color: @darkGrey; + } + &.disabled, + &.disabled:hover { + background: none; + color: @lightGrey; + cursor: default; + } + &.today, + &.today:hover, + &.today.disabled, + &.today.disabled:hover { + background: @blue; + color: #000; + } + &.today:hover:hover { // Thank bootstrap 2.0 for this selector... + // TODO: Bump min BS to 2.1, use @textColor in buttonBackground above + color: #000; + } + &.today.active:hover { + color: #fff; + } + &.range, + &.range:hover, + &.range.disabled, + &.range.disabled:hover { + background:#eee; + .border-radius(0); + } + &.range.today, + &.range.today:hover, + &.range.today.disabled, + &.range.today.disabled:hover { + background: #f3c17a; + .border-radius(0); + } + &.selected, + &.selected:hover, + &.selected.disabled, + &.selected.disabled:hover { + background: @lightGrey; + color: #fff; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + } + &.active, + &.active:hover, + &.active.disabled, + &.active.disabled:hover { + background: @blue; + color: #fff; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + } + span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + .border-radius(4px); + &:hover { + background: #eee; + } + &.disabled, + &.disabled:hover { + background:none; + color: @lightGrey; + cursor: default; + } + &.active, + &.active:hover, + &.active.disabled, + &.active.disabled:hover { + background: @blue; + color: #fff; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + } + &.old, + &.new { + color: @lightGrey; + } + } + } + + th.datepicker-switch { + width: 145px; + } + + thead tr:first-child th, + tfoot tr th { + cursor: pointer; + &:hover{ + background: #eee; + } + } + /*.dow { + border-top: 1px solid #ddd !important; + }*/ + + // Basic styling for calendar-week cells + .cw { + font-size: 10px; + width: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; + } + thead tr:first-child th.cw { + cursor: default; + background-color: transparent; + } +} +.input-append, +.input-prepend { + &.date { + .add-on i { + display: block; + cursor: pointer; + width: 16px; + height: 16px; + } + } +} +.input-daterange { + input { + text-align:center; + } + input:first-child { + .border-radius(3px 0 0 3px); + } + input:last-child { + .border-radius(0 3px 3px 0); + } + .add-on { + display: inline-block; + width: auto; + min-width: 16px; + height: 18px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + text-align: center; + text-shadow: 0 1px 0 white; + vertical-align: middle; + background-color: #eee; + border: 1px solid #ccc; + margin-left:-5px; + margin-right:-5px; + } +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/daterangepicker.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/daterangepicker.less new file mode 100644 index 0000000..320cd88 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/daterangepicker.less @@ -0,0 +1,245 @@ +/* + * Stylesheet for the Date Range Picker, for use with Bootstrap 3.x + * + * Copyright 2013 Dan Grossman ( http://www.dangrossman.info ) + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Built for http://www.improvely.com + */ + + .daterangepicker.dropdown-menu { + max-width: none; + z-index: 3000; +} + +.daterangepicker.opensleft .ranges, .daterangepicker.opensleft .calendar { + float: left; + margin: 4px; +} + +.daterangepicker.opensright .ranges, .daterangepicker.opensright .calendar { + float: right; + margin: 4px; +} + +.daterangepicker .ranges { + width: 160px; + text-align: left; +} + +.daterangepicker .ranges .range_inputs>div { + float: left; +} + +.daterangepicker .ranges .range_inputs>div:nth-child(2) { + padding-left: 11px; +} + +.daterangepicker .calendar { + display: none; + max-width: 270px; +} + +.daterangepicker .calendar th, .daterangepicker .calendar td { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + white-space: nowrap; + text-align: center; + min-width: 32px; +} + +.daterangepicker .ranges label { + color: #333; + display: block; + font-size: 11px; + font-weight: normal; + height: 20px; + line-height: 20px; + margin-bottom: 2px; + text-shadow: #fff 1px 1px 0px; + text-transform: uppercase; + width: 74px; +} + +.daterangepicker .ranges input { + font-size: 11px; +} + +.daterangepicker .ranges .input-mini { + background-color: #eee; + border: 1px solid #ccc; + border-radius: 4px; + color: #555; + display: block; + font-size: 11px; + height: 30px; + line-height: 30px; + vertical-align: middle; + margin: 0 0 10px 0; + padding: 0 6px; + width: 74px; +} + +.daterangepicker .ranges ul { + list-style: none; + margin: 0; + padding: 0; +} + +.daterangepicker .ranges li { + font-size: 13px; + background: #f5f5f5; + border: 1px solid #f5f5f5; + color: #08c; + padding: 3px 12px; + margin-bottom: 8px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + cursor: pointer; +} + +.daterangepicker .ranges li.active, .daterangepicker .ranges li:hover { + background: #08c; + border: 1px solid #08c; + color: #fff; +} + +.daterangepicker .calendar-date { + border: 1px solid #ddd; + padding: 4px; + border-radius: 4px; + background: #fff; +} + +.daterangepicker .calendar-time { + text-align: center; + margin: 8px auto 0 auto; + line-height: 30px; +} + +.daterangepicker { + position: absolute; + background: #fff; + top: 100px; + left: 20px; + padding: 4px; + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.daterangepicker.opensleft:before { + position: absolute; + top: -7px; + right: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.daterangepicker.opensleft:after { + position: absolute; + top: -6px; + right: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; + content: ''; +} + +.daterangepicker.opensright:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.daterangepicker.opensright:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; + content: ''; +} + +.daterangepicker table { + width: 100%; + margin: 0; +} + +.daterangepicker td, .daterangepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + cursor: pointer; + white-space: nowrap; +} + +.daterangepicker td.off { + color: #999; +} + +.daterangepicker td.disabled { + color: #999; +} + +.daterangepicker td.available:hover, .daterangepicker th.available:hover { + background: #eee; +} + +.daterangepicker td.in-range { + background: #ebf4f8; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.daterangepicker td.active, .daterangepicker td.active:hover { + background-color: #357ebd; + border-color: #3071a9; + color: #fff; +} + +.daterangepicker td.week, .daterangepicker th.week { + font-size: 80%; + color: #ccc; +} + +.daterangepicker select.monthselect, .daterangepicker select.yearselect { + font-size: 12px; + padding: 1px; + height: auto; + margin: 0; + cursor: default; +} + +.daterangepicker select.monthselect { + margin-right: 2%; + width: 56%; +} + +.daterangepicker select.yearselect { + width: 40%; +} + +.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.ampmselect { + width: 50px; + margin-bottom: 0; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/discussions.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/discussions.less new file mode 100644 index 0000000..c320eaa --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/discussions.less @@ -0,0 +1,141 @@ +/* Discussions +=================================================================== */ +.discussions { + + ul { + list-style: none; + margin: 0; + padding: 0; + + li { + font-size: 12px; + border: 1px solid lighten(@grey, 15%); + position: relative; + background: white; + margin: 0 40px 20px 80px; + padding: 10px; + + &:before { + content: ''; + width: 20px; + height: 20px; + top: 15px; + left: -20px; + position: absolute; + background: url("../img/disc-arrow.png") no-repeat; + background-size: 20px 20px; + } + + .author { + position: absolute; + z-index:1; + width: 60px; + float: left; + top: 0px; + left: -70px; + + img { + height: 50px; + .border-radius(2px); + } + + } + + .name { + position: absolute; + top: 10px; + left: 10px; + width: 100%; + background: lighten(@grey, 20%); + padding: 5px 10px 5px 10px; + } + + .date { + position: absolute; + top: 10px; + right: -1px; + z-index:1; + background: lighten(@grey, 15%); + padding: 5px 20px 5px 10px; + } + + .delete { + position: absolute; + background: lighten(@grey, 10%); + top: 10px; + right: -30px; + padding: 5px 10px; + display: inline-block; + cursor: pointer; + } + + .message { + border-bottom: 1px solid lighten(@grey, 20%); + margin: 20px -10px 0px -10px; + padding: 20px; + font-size: 12px; + } + + ul { + overflow: hidden; + + li { + .box-shadow; + border: none; + border-bottom: 1px solid lighten(@grey, 20%); + margin: 0 -10px; + padding-left: 70px; + + &:before { + display: none; + } + + &:last-child { + border-bottom: none; + + } + + .author { + top: 10px; + left: 10px; + + img { + height: 40px; + .border-radius(2px); + } + + } + + .name { + left: 70px; + } + + .date { + background: transparent; + right: 30px; + } + + .delete { + background: transparent; + right: 10px; + } + + .message { + border-bottom: none; + } + + textarea { + .box-shadow; + width: 100%; + font-size: 12px; + padding: 5px; + } + } + + } + + } + + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/feed.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/feed.less new file mode 100644 index 0000000..c976434 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/feed.less @@ -0,0 +1,119 @@ +/* Activity Feed +=================================================================== */ + +#feed { + background: lighten(@grey, 20%); + top: 0px; + right: 0px; + position:absolute; + height: 100%; + border-left: 1px solid lighten(@grey, 15%); + + h2 { + background: lighten(@grey, 15%); + padding: 12px; + margin: 0px -15px 10px -15px; + + a { + float: right; + color: @grey; + text-decoration: none; + cursor: pointer; + + &:hover { + color: @darkGrey; + } + } + } + + ul#filter { + margin: 0 0 10px -40px; + list-style: none; + .clearfix; + + li { + float: left; + margin-right: 20px; + cursor: pointer; + + a { + text-decoration: none; + + &.active { + font-weight: bold; + } + + &:hover { + color: inherit; + } + } + + } + + } + + ul#timeline { + margin: 0 0 0 10px; + list-style: none; + border-left: 1px solid lighten(@grey, 15%); + + li { + position: relative; + margin: 0 0 20px -20px; + font-size: 12px; + + i { + position: absolute; + top: -4px; + left: -36px; + background: lighten(@grey, 20%); + padding: 5px 0px; + font-size: 15px; + width: 30px; + text-align: center; + } + + &.tasks i { + color: @green; + } + + &.comments i { + color: @red; + } + + &.messages i { + color: @blue; + } + + .title { + font-weight: bold; + } + + .desc { + margin: 5px 0; + } + + .date, .separator, .name { + color: @grey; + } + + .separator { + margin: 0 5px; + } + + } + } + + #load-more { + color: lighten(@grey, 15%); + margin: 0 auto; + display: block; + text-align: center; + text-decoration: none; + + &:hover { + color: @darkGrey; + } + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/footer.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/footer.less new file mode 100644 index 0000000..28711f0 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/footer.less @@ -0,0 +1,17 @@ +/* Footer +=================================================================== */ +footer { + background: @darkGrey; + color: white; + height: 40px; + padding: 12px 20px 20px 20px!important; + margin: 0 !important; + position: relative; + z-index: 1; + font-size: 12px; + + a { + color: white; + font-weight: bold; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/forms.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/forms.less new file mode 100644 index 0000000..52d1626 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/forms.less @@ -0,0 +1,126 @@ +/* Forms +=================================================================== */ +.form-horizontal .form-group { + margin-right: 0px; + margin-left: 0px; +} + +.input-group-addon, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +input[type="file"], +.uneditable-input { + border-color: lighten(@grey, 20%); + .border-radius(2px); + .box-shadow; +} + +textarea { + border: 1px solid lighten(@grey, 20%); + .border-radius(2px) !important; +} + +.input-group-addon.clear { + background: white; + margin: 0 -1px; + color: @grey; +} + +.limiterBox { + border: 1px solid @grey; + border-top: none; + background-color: @grey; + padding: 3px 6px; + font-size: 10px; + color: white; + opacity: .9; + .box-sizing(content-box); +} + +.editor { + max-height: 250px; + height: 250px; + background-color: white; + border-collapse: separate; + border: 1px solid lighten(@grey, 10%) !important; + padding: 4px; + .box-sizing(content-box); + .border-radius(2px); + overflow: scroll; + outline: none; + margin-top: 20px; +} + +div[data-role="editor-toolbar"] { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.dropdown-menu a { + cursor: pointer; +} + +.twitter-typeahead .tt-query, +.twitter-typeahead .tt-hint { + margin-bottom: 0; +} + +.tt-dropdown-menu { + min-width: 160px; + margin-top: 2px; + padding: 5px 0; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0,0,0,.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); + -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); + box-shadow: 0 5px 10px rgba(0,0,0,.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.tt-suggestion { + display: block; + padding: 3px 20px; +} + +.tt-suggestion.tt-is-under-cursor { + color: #fff; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0) +} + +.tt-suggestion.tt-is-under-cursor a { + color: #fff; +} + +.tt-suggestion p { + margin: 0; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/header.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/header.less new file mode 100644 index 0000000..94010da --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/header.less @@ -0,0 +1,351 @@ +/* Header Section +=================================================================== */ +.navbar { + margin: 0; + min-height: 40px; + border: none; + background: @darkGrey; + .border-radius; + z-index: 2; + + a { + color: #7b7b7b; + + i { + margin-top: 2px; + } + + &:hover i { + opacity: .8; + filter: alpha(opacity=80); + -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; + } + + } + + #search { + position: relative; + background: darken(@darkGrey, 5%); + height: 30px; + .border-radius(2px); + margin: 5px 0 5px 16%; + + select { + margin: 4px 0 0 -11px; + height: 22px; + line-height: 22px; + background: lighten(@darkGrey, 15%); + border: none; + color: white; + .border-radius(1px); + text-align: center; + text-align:-moz-center; + text-align:-webkit-center; + text-align: -khtml-center; + font-size: 12px; + cursor: pointer; + width: 30%; + -webkit-appearance: none; + -moz-appearance: none; + text-indent: 0.01px; + text-overflow: ''; + padding: 2px 0px; + } + + @media screen and (-webkit-min-device-pixel-ratio:0) { + select { + padding: 0px 15px; + } + } + + input { + margin-left: 5px; + width: 70%; + background: transparent; + border: none; + font-size: 12px; + color: white; + } + + i { + position: absolute; + top: 8px; + right: 10px; + color: white; + } + } +} + +a.navbar-brand { + background: darken(@darkGrey, 5%); + text-align: center; + padding: 9px 0 10px 0 !important; + + span { + font-family: 'Kaushan Script', cursive; + color: #fff; + text-shadow: none; + } + + &.noBg { + background: @darkGrey; + border-bottom: none; + } + + &:hover { + background: darken(@darkGrey, 5%); + } +} + +.header-nav { + position: relative; + padding: 0px; + color: #fff !important; + background: #000 !important; + + .btn { + + display: inline-block; + margin: 0px; + font-size: 15px; + text-align: center; + background: transparent; + border: none; + .border-radius; + .box-shadow; + + } + + a.btn { + position: relative; + height: 30px; + width: 40px; + background: lighten(@darkGrey, 5%); + color: #fff !important; + text-shadow: none !important; + padding: 5px 0 !important; + margin: 5px 3px; + .border-radius(2px); + font-size: 12px; + + .number { + position: absolute; + font-size: 8px; + top: -3px; + right: 3px; + } + + &.account { + background: transparent; + height: 40px; + width: auto; + padding: 8px 0px 5px 10px !important; + margin: 0 -15px 0 3px; + + .avatar { + + width: 60px; + + img { + margin: -13px -10px -14px 10px; + height: 40px; + width: 40px; + } + + float: right; + + } + } + + &:hover { + background: darken(@darkGrey, 5%); + } + } + + .user { + display: inline-block; + text-align: left; + margin-top: -5px; + padding: 0px; + + .hello { + display: block; + font-size: 11px; + font-weight: bold; + } + + .name { + display: block; + margin-top: -6px !important; + font-size: 13px; + } + + } + +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: white; + background-color: darken(@darkGrey, 5%); + outline: 0; + .box-shadow; +} + +.dropdown-menu:after, +.dropdown-menu:before { + display: none !important; +} + +.dropdown-menu { + position: absolute; + top: 90%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 166px; + max-width: 300px; + padding: 0px; + margin: 0; + list-style: none; + text-shadow: none; + background: white; + border: 1px solid lighten(@grey,15%); + .border-radius; + .box-shadow; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + margin: 0px 1px; +} + +.dropdown-menu li a { + display: block; + padding: 5px 10px !important; + clear: both; + font-weight: normal; + line-height: 20px; + color: @darkGrey; + white-space: normal !important; +} + +.dropdown-menu li { + border-bottom: 1px solid lighten(@grey,20%); +} + +.dropdown-menu li:last-child { + border-bottom: 0px !important; +} + +.dropdown-menu li > a:hover, +.dropdown-menu li > a:focus, +.dropdown-submenu:hover > a { + color: #ffffff; + text-decoration: none; + background: lighten(@mainColor,10%); +} + +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + .gradient(#0088cc, #0077b3); +} + +.dropdown-menu .disabled > a, +.dropdown-menu .disabled > a:hover { + color: #999999; +} + +.dropdown-menu .disabled > a:hover { + text-decoration: none; + cursor: default; + background-color: transparent; +} + +.dropdown-menu-title { + background: lighten(@grey,20%); + color: @darkGrey; + padding: 5px 10px; + display: block; +} + +.dropdown-menu-sub-footer { + text-align: center; + background: lighten(@grey,20%); + cursor: pointer; +} + +.dropdown-menu ul, +.dropdown-menu ul li { + padding: 0px !important; + margin: 0px !important; +} + +ul.notifications li, +ul.tasks li, +ul.messages li{ + min-width: 260px; +} + +ul.notifications li .avatar img, +ul.tasks li .avatar img, +ul.messages li .avatar img { + float: left !important; + height: 40px; + width: 40px; + margin-top: 5px; + margin-right: 10px; + .border-radius(2px); +} + +ul.messages li .header { + display: block; +} + +ul.messages li .header .from { + font-size: 12px; + font-weight: bold; +} + +ul.notifications li .icon { + margin: -5px 10px -5px -10px !important; + padding: 7px 10px 9px 10px; + color: white; + width: 40px; + display: inline-block; + text-align: center; + + .backgroundColor; + +} + +ul.notifications li .time, +ul.tasks li .header .percent, +ul.messages li .header .time { + font-size: 11px; + font-weight: bold; + font-style: italic; + position: absolute; + right: 5px; +} + +ul.tasks li .title, +ul.notifications li .message { + font-size: 12px; +} + +ul.notifications li.warning a { + color: @orange; +} + +ul.messages li .message { + font-size: 11px; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/import.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/import.less new file mode 100644 index 0000000..04fee33 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/import.less @@ -0,0 +1,25 @@ +@import "jquery-ui-1.10.3.custom.css"; +@import "fullcalendar.css"; +@import "chosen.css"; +@import "select2.css"; +@import "jquery.cleditor.css"; +@import "jquery.noty.css"; +@import "noty_theme_default.css"; +@import "elfinder.min.css"; +@import "elfinder.theme.css"; +@import "uploadify.css"; +@import "jquery.gritter.css"; +@import "font-awesome.min.css"; +@import "font-awesome-ie7.min.css"; +@import "glyphicons.css"; +@import "halflings.css"; +@import "dropzone.css"; +@import "filetypes.css"; +@import "social.css"; +@import "xcharts.min.css"; +@import "jquery.easy-pie-chart.css"; +@import "icheck/all.css"; +@import "bootstrap-editable.css"; +@import url(http://fonts.googleapis.com/css?family=Lato:300); +@import url(http://fonts.googleapis.com/css?family=Lato:400); +@import url(http://fonts.googleapis.com/css?family=Kaushan+Script); \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/justgage.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/justgage.less new file mode 100644 index 0000000..cdd4dcc --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/justgage.less @@ -0,0 +1,6 @@ +/* Just Gage - Demo Charts +=================================================================== */ + +.sz1{width:200px;height:160px} +.sz0{margin:2em 0 0 0} +.sz0{width:100px;height:80px} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/main.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/main.less new file mode 100644 index 0000000..8161b1e --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/main.less @@ -0,0 +1,247 @@ +/* Basic +=================================================================== */ +.no-space [class*="span"] { + margin-left: 0; +} + +.noMarginLeft { + margin-left: 0px !important; +} + +.noPadding { + padding: 0px !important; +} + +body { + background: lighten(@grey, 20%); + color: @darkGrey; + border: none; + font-family: 'Lato', sans-serif; + font-weight: 400; + margin: 0; + padding: 0; + position:relative; + + &:after { + top: 0; + left: 14.422%; + margin-left: -1px; + position:absolute; + content: ''; + height: 100%; + width: 85.578%; + background: @bodyBackground; + border-left: 1px solid lighten(@grey, 15%); + z-index: 0; + } + + &:before { + content: ''; + position:absolute; + z-index: 0; + background: @bodyBackground; + width: 50%; + height: 100%; + top: 0; + right: 0; + z-index: 0; + } + + &.sidebar-minified { + + &:after { + top: 0; + left: 40px !important; + margin-left: -1px; + margin-right: 40px; + position:absolute; + content: ''; + height: 100%; + background: @bodyBackground; + border-left: 1px solid lighten(@grey, 15%); + z-index: 0; + } + + } + +} + +a { + color: @darkGrey; +} + +h1 { font-size: 32px; line-height: 32px; font-weight: 300} +h2 { font-size: 16px; line-height: 16px; font-weight: 300} +h3 { font-size: 15px; line-height: 15px; } +h4 { font-size: 14px; line-height: 14px; } +h5 { font-size: 13px; line-height: 13px; } +h6 { font-size: 12px; line-height: 12px; } + +#content { + padding: 20px; + position: relative; + background: @bodyBackground; + z-index: 1; + + &:before { + position: absolute; + content:''; + height: 100%; + width: 1px; + border-left: 1px solid lighten(@grey, 15%); + z-index: +1; + top: 0px; + left: -1px; + } + + &.sidebar-minified { + width: 100% !important; + border-left: 40px solid lighten(@grey, 20%); + margin-right: 1px !important; + } + + &.full { + width: 100% !important; + margin-left: 0px !important; + margin-right: 0px !important; + border: none !important; + } +} + +.well { + border: 1px solid #ddd; + background-color: #f6f6f6; + .box-shadow; + .border-radius(2px); +} + +.breadcrumb { + background: lighten(@grey, 20%); + .border-radius; + height: 40px; + position: relative; + border-bottom: 1px solid lighten(@grey, 15%); + + .choose-date { + position: absolute; + top:0px; + right: 0px; + height: 40px; + width: 254px; + border: none; + border-left: 1px solid lighten(@grey, 15%); + padding: 3px 10px; + + .input-group-addon, + input { + background: transparent; + border: none; + } + + .input-group-addon { + font-size: 12px; + } + + input { + padding: 0; + font-weight: 300; + + &:focus { + outline: none; + .box-shadow; + } + + } + + + } +} + +.box { + border: 1px solid lighten(@grey, 15%); + margin: 0px 0px 30px 0px; + + &.noOverflow { + overflow: hidden; + } + + .box-header { + background: white; + color: @darkGrey; + font-size: 16px; + overflow: hidden; + background: lighten(@grey, 25%); + border-bottom: 1px solid lighten(@grey, 15%); + height: 40px; + + h2 { + float:left; + padding: 10px 0px; + margin: 0px 0px 0px 20px; + + i { + border-right: 1px solid lighten(@grey, 15%); + color: lighten(@grey, 10%); + padding: 12px 0px; + height: 40px; + width: 40px; + display: inline-block; + text-align: center; + margin: -10px 20px -10px -20px; + font-size: 16px; + } + + } + + .box-icon { + float:right; + + i { + display: inline-block; + color: lighten(@grey, 10%); + text-align: center; + height: 40px; + width: 40px; + padding: 12px 0px; + .transition(all 0.1s ease-in-out); + border-left: 1px solid lighten(@grey, 10%); + text-decoration: none; + + &:hover { + } + } + + a { + margin-left: -3px !important; + } + + } + + } + + .box-content { + padding: 10px; + background: white; + + &.no-padding { + background: white; + padding: 1px 0; + } + } + +} + +/* Typography - Blockquote +=================================================================== */ +blockquote { + background: url(../img/quote.png) no-repeat 0px 10px; + font-style: italic; + border-left: none; + padding: 0 0 0 30px; +} + +/* Alerts +=================================================================== */ +.alert { + .border-radius(2px;) +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/mixins.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/mixins.less new file mode 100644 index 0000000..84833e5 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/mixins.less @@ -0,0 +1,58 @@ +// Default Mixins +//=================================================================== +.border-radius(@radius: 0px) { + -webkit-border-radius: @radius; + -moz-border-radius: @radius; + border-radius: @radius; +} + +.box-shadow(@arguments: none) { + -webkit-box-shadow: @arguments; + -moz-box-shadow: @arguments; + box-shadow: @arguments; +} + +.box-shadow-double(@arguments1: none, @arguments2: none) { + -webkit-box-shadow: @arguments1, @arguments2; + -moz-box-shadow: @arguments1, @arguments2; + box-shadow: @arguments1, @arguments2; +} + +.gradient(@from: none, @to: none) { + background-color: @to; + background-image: -webkit-gradient(linear, left top, left bottom, from(@from), to(@to)); + background-image: -webkit-linear-gradient(top, @from, @to); + background-image: -moz-linear-gradient(top, @from, @to); + background-image: -o-linear-gradient(top, @from, @to); + background-image: -ms-linear-gradient(top, @from, @to); + background-image: linear-gradient(top, @from, @to); +} + +.transition(@arguments: none) { + -webkit-transition:@arguments; + -moz-transition:@arguments; + -ms-transition:@arguments; + -o-transition:@arguments; + transition:@arguments; +} + +.box-sizing(@arguments: border-box) { + -webkit-box-sizing: @arguments; + -moz-box-sizing: @arguments; + box-sizing: @arguments; +} + +.clearfix { + *zoom: 1; + &:before, + &:after { + display: table; + content: ""; + // Fixes Opera/contenteditable bug: + // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952 + line-height: 0; + } + &:after { + clear: both; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/modal.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/modal.less new file mode 100644 index 0000000..ebde4ba --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/modal.less @@ -0,0 +1,5 @@ +body.modal-open, +.modal-open .navbar-fixed-top, +.modal-open .navbar-fixed-bottom { + margin-right: 0px; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/navigation.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/navigation.less new file mode 100644 index 0000000..0706427 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/navigation.less @@ -0,0 +1,327 @@ +/* Navigation Section +=================================================================== */ +a#main-menu-toggle { + background: darken(@darkGrey, 10%); + width: 40px; + height: 40px; + color: white; + position: absolute; + z-index: 1000; + top: 0px; + left: 0; + padding: 8px 13px; + font-size: 16px; + text-shadow: none; + text-decoration: none; + cursor: pointer; + + &.close { + opacity: 1; + background: darken(@darkGrey, 5%) !important; + padding: 10px 13px !important; + } +} + +a#main-menu-min { + display: block; + border-bottom: 1px solid lighten(@grey, 15%); + width: 100%; + margin: 30px 0; + position: relative; + text-decoration: none; + + i { + position: absolute; + bottom: -10px; + left: 50%; + margin-left: -10px; + width: 20px; + height: 20px; + background: lighten(@grey, 15%); + font-size: 14px; + padding: 3px 0px; + color: darken(@grey, 20%); + text-align: center; + + &:hover { + background: lighten(@grey, 10%); + color: darken(@grey, 25%); + } + } +} + +#sidebar-left { + padding: 10px !important; + z-index: 2; +} + +.sidebar-nav > ul { + margin: -9px -25px; + border: none; + padding-bottom: 1px; + font-size: 14px; + white-space: nowrap; +} + +.sidebar-nav > ul > li > ul, +.sidebar-nav > ul > li > ul > li > ul, +.sidebar-nav > ul > li > ul > li > ul > li > ul { + list-style: none; + display: none; + margin: 0; + padding: 0; + +} + +.nav.main-menu > li { + margin-top: -1px; +} + +.nav.main-menu > li > a, +.nav.main-menu > li > ul > li > a, +.nav.main-menu > li > ul > li > ul > li > a, +.nav.main-menu > li > ul > li > ul > li > ul > li > a { + margin: 0px; + height: 40px; + padding: 1px 0 0 0; + color: darken(@grey, 20%); + border: none; + border-bottom: 1px solid lighten(@grey, 15%); + background: transparent; + .border-radius; + text-decoration: none; + display: block; + position: relative; + + .chevron { + font-family: 'FontAwesome'; + position: absolute; + top: 2px; + right: -5px; + height: 40px; + width: 40px; + padding: 12px 0px; + display: inline-block; + text-align: center; + font-size: 10px; + color: @grey !important; + + &.opened { + + &:after { + height: 100%; + width: 100%; + content: "\f078"; + text-shadow: none; + } + + } + + &.closed { + + &:after { + height: 100%; + width: 100%; + content: "\f053"; + text-shadow: none; + color: @grey !important; + } + + } + + } + +} + +.nav.main-menu > li > a > i, +.nav.main-menu > li > ul > li > a > i { + margin-right: 10px; + height: 38px; + width: 40px; + padding: 13px 0px; + display: inline-block; + text-align: center; + border-right: 1px solid lighten(@grey, 15%); +} + +.nav.main-menu > li > ul > li > a > i, +.nav.main-menu > li > ul > li > ul > li > a > i, +.nav.main-menu > li > ul > li > ul > li > ul > li > a > i { + margin-right: 10px; + height: 38px; + width: 40px; + padding: 13px 0px; + display: inline-block; + text-align: center; + font-size: 13px; + border-right: 1px solid lighten(@grey, 15%); +} + +.nav.main-menu > li > ul > li > a { + background: lighten(@grey, 18%); +} +.nav.main-menu > li > ul > li > ul > li > a { + background: lighten(@grey, 17%); +} +.nav.main-menu > li > ul > li > ul > li > ul > li > a { + background: lighten(@grey, 16%); +} + +.nav.main-menu > li > a:hover, +.nav.main-menu > li > ul > li > a:hover, +.nav.main-menu > li > ul > li > ul > li > a:hover, +.nav.main-menu > li > ul > li > ul > li > ul > li > a:hover { + background: lighten(@grey, 10%); + .box-shadow; + .border-radius; +} + +.nav.main-menu > li > a:hover > i, +.nav.main-menu > li > ul > li > a:hover > i, +.nav.main-menu > li > ul > li > ul > li > a:hover > i, +.nav.main-menu > li > ul > li > ul > li > ul > li > a:hover > i { + border-right: 1px solid lighten(@grey, 8%); +} + +.nav.main-menu > li > a:hover, +.nav.main-menu > li > ul > li > a:hover { + background: lighten(@grey, 10%); + .box-shadow; + .border-radius; +} + +.nav.main-menu > li.active > a, +.nav.main-menu > li > ul > li.active > a, +.nav.main-menu > li > ul > li > ul > li.active > a, +.nav.main-menu > li > ul > li > ul > li > ul > li.active > a { + background: lighten(@grey, 10%); +} + +.nav.main-menu > li.active > a > i, +.nav.main-menu > li > ul > li.active > a > i, +.nav.main-menu > li > ul > li > ul > li.active > a > i, +.nav.main-menu > li > ul > li > ul > li > ul > li.active > a > i { + border-right: 1px solid lighten(@grey, 8%); +} + +.nav.main-menu > li.active > a:hover, +.nav.main-menu > li > ul > li.active > a:hover { + border: none; + color: white; +} + +.nav.main-menu > li.active > ul { + padding: 5px 0px; + background: lighten(@grey, 15%); +} + +.nav.main-menu > li:first-child > a { + margin: 0px; + .border-radius; +} + +.nav.main-menu > li:last-child > a { + .border-radius; +} + +#sidebar-left { + + &.minified { + width: 40px !important; + margin-right: -40px; + + .sidebar-nav { + + > ul { + + > li { + position: relative; + + > a { + width: 40px; + position: relative; + + &.open { + cursor: default; + } + + .chevron { + display: none; + position: absolute; + left: 178px; + z-index: 1000; + } + + .text { + position: absolute; + z-index: 1000; + background: lighten(@grey, 20%); + min-height: 40px; + width: 150px; + padding: 8px 15px; + border: 1px solid lighten(@grey, 15%); + top: 0px; + left: 39px; + display: none !important; + } + + } + + > ul { + display: none !important; + } + + &:hover { + + > a { + position: relative; + + .chevron { + display: inline-block; + } + + .text { + position: absolute; + z-index: 1000; + background: lighten(@grey, 20%); + min-height: 40px; + width: 180px; + padding: 8px 15px; + border: 1px solid lighten(@grey, 15%); + top: 0px; + left: 39px; + display: block !important; + } + + } + + > ul { + display: block !important; + position: absolute; + top: 39px; + left: 39px; + z-index: 1000; + width: 180px; + background: lighten(@grey, 20%); + border: 1px solid lighten(@grey, 15%); + border-bottom: none; + + > li { + + > a {} + + } + + } + + } + + } + + } + + } + + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/nestable.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/nestable.less new file mode 100644 index 0000000..e5cd6a4 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/nestable.less @@ -0,0 +1,236 @@ +/** + * Nestable + */ + +.dd { + position: relative; + display: block; + margin: 0; + padding: 0; + list-style: none; + font-size: 13px; + line-height: 20px; +} + +.dd-list { + display: block; + position: relative; + margin: 0; + padding: 0; + list-style: none; + + .dd-list { + padding-left: 30px; + } + +} + +.dd-collapsed .dd-list { + display: none; +} + +.dd-item, +.dd-empty, +.dd-placeholder { + display: block; + position: relative; + margin: 0; + padding: 0; + min-height: 20px; + font-size: 13px; + line-height: 20px; +} + +.dd-handle { + display: block; + height: 30px; + margin: 5px 0; + padding: 4px 10px; + text-decoration: none; + border: 1px solid lighten(@grey,15%); + background: lighten(@grey, 20%); + .border-radius(1px); + .box-sizing(border-box); + + &:hover { + color: @mainColor; + background: white; + } + + .icon { + float: right; + font-size: 16px; + margin-left: 10px; + + &:hover { + text-decoration: none; + } + } +} + +.dd-item > button { + display: block; + position: relative; + cursor: pointer; + float: left; + width: 25px; + height: 20px; + margin: 5px 0; + padding: 0; + text-indent: 100%; + white-space: nowrap; + overflow: hidden; + border: 0; + background: transparent; + font-size: 12px; + line-height: 1; + text-align: center; + font-weight: bold; +} +.dd-item > button:before { + content: '+'; + display: block; + position: absolute; + width: 100%; + text-align: center; + text-indent: 0; +} +.dd-item > button[data-action="collapse"]:before { + content: '-'; +} + +.dd-placeholder, +.dd-empty { + margin: 5px 0; + padding: 0; + min-height: 30px; + background: #f2fbff; + border: 1px dashed #b6bcbf; + .box-sizing(border-box); +} + +.dd-empty { + border: 1px dashed #bbb; + min-height: 100px; + background-color: #e5e5e5; + background-size: 60px 60px; + background-position: 0 0, 30px 30px; +} + +.dd-dragel { + position: absolute; + pointer-events: none; + z-index: 9999; +} +.dd-dragel > .dd-item .dd-handle { + margin-top: 0; +} +.dd-dragel .dd-handle { + .box-shadow(2px 4px 6px 0 rgba(0,0,0,.1)); +} + +/** + * Nestable Extras + */ + +.nestable-lists { + display: block; + clear: both; + padding: 30px 0; + width: 100%; + border: 0; + border-top: 2px solid #ddd; + border-bottom: 2px solid #ddd; +} + +#nestable-menu { + padding: 0; + margin: 20px 0; +} + +#nestable-output, +#nestable2-output { + width: 100%; + height: 7em; + font-size: 0.75em; + line-height: 1.333333em; + font-family: Consolas, monospace; + padding: 5px; + .box-sizing(border-box); +} + +#nestable2 .dd-handle { + color: white; + border: 1px solid @grey; + background: @grey; +} +#nestable2 .dd-handle:hover { + border: 1px solid @darkGrey; + background: @darkGrey; +} +#nestable2 .dd-item > button:before { + color: #fff; +} + +@media only screen and (min-width: 700px) { + + .dd { float: left; width: 48%; } + .dd + .dd { margin-left: 2%; } + +} + +.dd-hover > .dd-handle { + background: #2ea8e5 !important; +} + +/** + * Nestable Draggable Handles + */ + +.dd3-content { + display: block; + height: 30px; + margin: 5px 0; + padding: 5px 10px 5px 40px; + text-decoration: none; + font-weight: bold; + border: 1px solid lighten(@grey, 15%); + background: lighten(@grey, 20%); + .border-radius(2px); + .box-sizing(border-box); + + &:hover { + color: @mainColor; + background: #fff; + } +} + +.dd-dragel > .dd3-item > .dd3-content { + margin: 0; +} + +.dd3-item > button { + margin-left: 30px; +} + +.dd3-handle { + position: absolute; + margin: 0; + left: 0; + top: 0; + cursor: pointer; + width: 30px; + white-space: nowrap; + overflow: hidden; + border: 1px solid lighten(@grey, 15%); + background: lighten(@grey, 15%); + border-top-right-radius: 0; + border-bottom-right-radius: 0; + color: white; + + &:hover { + background: @grey; + color: white; + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/notifications_labels.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/notifications_labels.less new file mode 100644 index 0000000..1816315 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/notifications_labels.less @@ -0,0 +1,92 @@ +/* Notifications & Labels +=================================================================== */ +.notification { + position: absolute; + top: -12px; + right: -12px; + line-height: 16px; + height: 16px; + padding: 6px 10px; + color: white !important; + .border-radius(50em); + .box-sizing(content-box); +} + +.notification.small { + padding: 2px 7px; + color: white !important; + border-width: 1px; + border-style: solid; + .border-radius(50em); +} + +.notification.small.blue, +.notification.blue { + background: @blue; +} + +.notification.small.yellow, +.notification.yellow { + background: @yellow; +} + +.notification.small.red, +.notification.red { + background: @red; +} + +.notification.small.green, +.notification.green { + background: @darkGreen; +} + +.notification.small.orange, +.notification.orange { + background: @lightOrange; +} + +.notification.small.red, +.notification.red { + background: @red; +} + +.label, +.badge { + font-weight: 300; + font-size: 10px; + padding: 4px 6px; + border: none; + text-shadow: none; +} + +.label { + .border-radius(2px); +} + +.label-important, +.badge-important, +.label-important[href], +.badge-important[href] { + background: @red; +} + +.label-warning, +.badge-warning, +.label-warning[href], +.badge-warning[href] { + background: @lightOrange; +} + +.label-success, +.badge-success, +.label-success[href], +.badge-success[href] { + background: @darkGreen; +} + +.label-info, +.badge-info, +.label-info[href], +.badge-info[href] { + background: @lightBlue; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/on_off.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/on_off.less new file mode 100644 index 0000000..1361211 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/on_off.less @@ -0,0 +1,284 @@ +/* ============================================================ + * bootstrapSwitch v1.3 by Larentis Mattia @spiritualGuru + * http://www.larentis.eu/switch/ + * ============================================================ + * Licensed under the Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * ============================================================ */ + +@grayDarker: #222; +@grayDark: #333; +@white: #fff; +@orange: #f89406; + +@bodyBackground: @white; +@textColor: @grayDark; + +@linkColor: #08c; +@linkColorHover: darken(@linkColor, 15%); + +@btnBackground: @white; +@btnBackgroundHighlight: darken(@white, 10%); +@btnBorder: #ccc; + +@btnPrimaryBackground: @linkColor; +@btnPrimaryBackgroundHighlight: spin(@btnPrimaryBackground, 20%); + +@btnInfoBackground: #5bc0de; +@btnInfoBackgroundHighlight: #2f96b4; + +@btnSuccessBackground: #62c462; +@btnSuccessBackgroundHighlight: #51a351; + +@btnWarningBackground: lighten(@orange, 15%); +@btnWarningBackgroundHighlight: @orange; + +@btnDangerBackground: #ee5f5b; +@btnDangerBackgroundHighlight: #bd362f; + +@btnInverseBackground: #444; +@btnInverseBackgroundHighlight: @grayDarker; + +.border-radius(@radius) { + -webkit-border-radius: @radius; + -moz-border-radius: @radius; + border-radius: @radius; +} + +.border-top-left-radius(@radius) { + -webkit-border-top-left-radius: @radius; + -moz-border-radius-topleft: @radius; + border-top-left-radius: @radius; +} + +.border-bottom-left-radius(@radius) { + -webkit-border-bottom-left-radius: @radius; + -moz-border-radius-bottomleft: @radius; + border-bottom-left-radius: @radius; +} + +.border-left-radius(@radius) { + .border-top-left-radius(@radius); + .border-bottom-left-radius(@radius); +} + +// Transitions +.transition(@transition) { + -webkit-transition: @transition; + -moz-transition: @transition; + -o-transition: @transition; + transition: @transition; +} + +// Box sizing +.box-sizing(@boxmodel) { + -webkit-box-sizing: @boxmodel; + -moz-box-sizing: @boxmodel; + box-sizing: @boxmodel; +} + +// User select +// For selecting text on the page +.user-select(@select) { + -webkit-user-select: @select; + -moz-user-select: @select; + -ms-user-select: @select; + -o-user-select: @select; + user-select: @select; +} + +// Opacity +.opacity(@opacity) { + opacity: @opacity / 100; + filter: ~"alpha(opacity=@{opacity})"; +} + +// Gradient Bar Colors for buttons and alerts +.gradientBar(@primaryColor, @secondaryColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) { + color: @textColor; + text-shadow: @textShadow; + #gradient > .vertical(@primaryColor, @secondaryColor); + border-color: @secondaryColor @secondaryColor darken(@secondaryColor, 15%); + border-color: rgba(0, 0, 0, .1) rgba(0, 0, 0, .1) fadein(rgba(0, 0, 0, .1), 15%); +} + +// Gradients +#gradient { + .vertical(@startColor: #555, @endColor: #333) { + background-color: mix(@startColor, @endColor, 60%); + background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(to bottom, @startColor, @endColor); // Standard, IE10 + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor), argb(@endColor))); // IE9 and down + } +} + +.reset-filter() { + filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); +} + +.buttonBackground(@startColor, @endColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) { // gradientBar will set the background to a pleasing blend of these, to support IE<=9 + .gradientBar(@startColor, @endColor, @textColor, @textShadow); + *background-color: @endColor; /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + .reset-filter(); // in these cases the gradient won't cover the background, so we override + &:hover, &:focus, &:active, &.active, &.disabled, &[disabled] { + color: @textColor; + background-color: @endColor; + *background-color: darken(@endColor, 5%); + } + +// IE 7 + 8 can't handle box-shadow to show active, so we darken a bit ourselves + &:active, + &.active { + background-color: darken(@endColor, 10%) e("\9"); + } +} + +.has-switch { + display: inline-block; + cursor: pointer; + .border-radius(5px); + border: 1px solid; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + position: relative; + text-align: left; + overflow: hidden; + line-height: 8px; + .user-select(none); + + min-width: 100px; + + &.switch-mini { + min-width: 72px; + } + + &.switch-small { + min-width: 80px; + } + + &.switch-large { + min-width: 120px; + } + + &.deactivate { + .opacity(50); + cursor: default !important; + label, span { + cursor: default !important; + } + } + > div { + display: inline-block; + width: 150%; + position: relative; + top: 0; + + &.switch-animate { + .transition(left 0.5s); + } + &.switch-off { + left: -50%; + } + &.switch-on { + left: 0%; + } + } + input[type=checkbox] { + //debug + display: none; + //position: absolute; + //margin-left: 60%; + //z-index: 123; + } + + span, label { + .box-sizing(border-box); + + cursor: pointer; + position: relative; + display: inline-block; + height: 100%; + + padding-bottom: 4px; + padding-top: 4px; + font-size: 14px; + line-height: 20px; + + &.switch-mini { + padding-bottom: 4px; + padding-top: 4px; + font-size: 10px; + line-height: 9px; + } + + &.switch-small { + padding-bottom: 3px; + padding-top: 3px; + font-size: 12px; + line-height: 18px; + } + + &.switch-large { + padding-bottom: 9px; + padding-top: 9px; + font-size: 16px; + line-height: normal; + } + } + + label { + text-align: center; + margin-top: -1px; + margin-bottom: -1px; + z-index: 100; + width: 34%; + border-left: 1px solid @btnBorder; + border-right: 1px solid @btnBorder; + + .buttonBackground(@btnBackground, @btnBackgroundHighlight); + + i { + color: #000; + text-shadow: 0 1px 0 #fff; + line-height: 18px; + pointer-events: none; + } + } + + span { + text-align: center; + z-index: 1; + width: 33%; + + &.switch-left { + .border-left-radius(4px); + } + + &.switch-right { + .buttonBackground(@btnBackgroundHighlight, @btnBackground, @grayDark, 0 1px 1px rgba(255,255,255,.75)); + } + + &.switch-primary, &.switch-left { + .buttonBackground(@btnPrimaryBackgroundHighlight, @btnPrimaryBackground); + } + + &.switch-info { + .buttonBackground(@btnInfoBackgroundHighlight, @btnInfoBackground); + } + + &.switch-success { + .buttonBackground(@btnSuccessBackgroundHighlight, @btnSuccessBackground); + } + + &.switch-warning { + .buttonBackground(@btnWarningBackgroundHighlight, @btnWarningBackground); + } + + &.switch-danger { + .buttonBackground(@btnDangerBackgroundHighlight, @btnDangerBackground); + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/others.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/others.less new file mode 100644 index 0000000..4c0130c --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/others.less @@ -0,0 +1,99 @@ +/* Masonry Gallery +=================================================================== */ +.masonry-thumb { + display: inline-block; + vertical-align: top; + margin-bottom: 6px; +} + +/* Star Rating +=================================================================== */ +.rating { + unicode-bidi: bidi-override; + direction: rtl; + font-size: 30px; +} +.rating span.star, +.rating span.star { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + display: inline-block; +} +.rating span.star:hover, +.rating span.star:hover { + cursor: pointer; +} +.rating span.star:before, +.rating span.star:before { + content: "\f006"; + padding-right: 5px; + color: #999999; +} +.rating span.star:hover:before, +.rating span.star:hover:before, +.rating span.star:hover ~ span.star:before, +.rating span.star:hover ~ span.star:before { + content: "\f005"; + color: #e3cf7a; +} +/* Icons +=================================================================== */ +.glyphicons-icon-list { + + div { + margin: 10px 0; + + span, strong { + font-size: 10px; + } + + strong { + margin-top: -5px; + display:block; + } + } + +} + +.fontawesome-icon-list { + div { + margin: 5px 0; + } + .fa { + width: 20px; + text-align: center; + margin-right: 10px; + } +} + +/* File manager +=================================================================== */ +.elfinder .elfinder-button { + .box-sizing(content-box); +} + +/* Text with HR Line +=================================================================== */ +.text-with-hr { + text-align: center; + position: relative; + z-index: 2; + + &:before{ + position: absolute; + content: ''; + top: 20px; + left: 0px; + width: 100%; + border-bottom: 1px solid lighten(@grey, 20%); + z-index: -1; + } + + span { + display: inline-block; + background: white; + padding: 10px; + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-error.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-error.less new file mode 100644 index 0000000..f3dd0ef --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-error.less @@ -0,0 +1,18 @@ +/* Page 404 & Page 500 +=================================================================== */ +.box-error { + + margin-top: 200px; + + h1 { + float: left; + font-size: 48px; + margin-right: 20px; + } + + p { + margin-top: -8px; + font-weight: 300; + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-inbox.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-inbox.less new file mode 100644 index 0000000..e19bfae --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-inbox.less @@ -0,0 +1,323 @@ +/* Page: Inbox +=================================================================== */ +.inbox { + + .inbox-menu { + background: lighten(@grey, 20%); + border-right: 1px solid lighten(@grey, 15%); + padding-top: 30px; + + .btn { + width: 100%; + } + + ul { + margin-top: 30px; + padding: 0; + list-style: none; + + li { + height: 30px; + margin: 0 -15px; + padding: 5px 15px; + position: relative; + + &:hover, + &.active { + background: lighten(@grey, 15%); + } + + &.title { + margin: 20px -15px -10px -15px; + text-transform: uppercase; + font-size: 10px; + color: @grey; + + &:hover { + background: transparent; + } + } + + a { + display: block; + width: 100%; + text-decoration: none; + color: @darkGrey; + + i { + margin-right: 10px; + } + + .label { + position: absolute; + top: 10px; + right: 15px; + display: block; + min-width: 14px; + height: 14px; + padding: 2px; + } + + } + + } + } + + } + + .buttons { + + margin: 30px 0; + + .btn, + .btn-group .btn { + border: 1px solid lighten(@grey, 15%); + } + + .btn-group .caret { + border-top-color: darken(@grey,20%); + margin-top: -4px; + margin-left: 5px; + } + + } + + .messages { + background: white; + margin: 0; + border-right: 1px solid lighten(@grey, 15%); + } + + ul.messages-list { + list-style: none; + padding: 0; + + li { + .border-radius(2px); + cursor: pointer; + margin-bottom: 10px; + padding: 10px; + + &.unread { + .header, .title { + + font-weight: bold; + + } + } + + &.active { + background: lighten(@grey, 20%); + border: 1px solid lighten(@grey, 15%); + padding: 9px; + + .action { + color: lighten(@grey, 5%); + } + } + + .header { + margin: 0 0 5px 0; + + .from { + width: 49.9%; + white-space: nowrap; + overflow:hidden !important; + text-overflow: ellipsis; + } + + .date { + width: 50%; + text-align: right; + float: right; + } + + } + + .title { + margin: 0 0 5px 0; + white-space: nowrap; + overflow:hidden !important; + text-overflow: ellipsis; + } + + .description { + font-size: 12px; + padding-left: 29px; + } + + .action { + display: inline-block; + width: 16px; + text-align: center; + margin-right: 10px; + color: lighten(@grey, 15%); + + .fa-check-square-o { + margin: 0 -1px 0 1px; + } + + .fa-square { + float: left; + margin-top: -16px; + margin-left: 4px; + font-size: 11px; + color: white; + } + + .fa-star.bg { + float: left; + margin-top: -16px; + margin-left: 3px; + font-size: 12px; + color: white; + } + + } + + } + + } + + .message { + margin: 0; + background: white; + border-right: 1px solid lighten(@grey, 15%); + + textarea { + color: @darkGrey !important; + } + + .message-title { + padding-top: 10px; + font-weight: bold; + font-size: 14px; + } + + .header { + margin: 20px 0 30px 0; + padding: 10px 0 10px 0; + border-top: 1px solid lighten(@grey, 20%); + border-bottom: 1px solid lighten(@grey, 20%); + + .avatar { + .border-radius(2px); + height: 34px; + width: 34px; + float: left; + margin-right: 10px; + } + + i { + margin-top: 1px; + } + + .from { + display: inline-block; + width: 50%; + font-size: 12px; + margin-top: -2px; + color: @grey; + + span { + display: block; + font-size: 14px; + font-weight: bold; + color: @darkGrey; + } + } + + .date { + display: inline-block; + width: 29%; + text-align: right; + float: right; + font-size: 12px; + margin-top: 18px; + } + + } + + .attachments { + border-top: 3px solid #f9f9f9; + border-bottom: 3px solid #f9f9f9; + padding: 10px 0px; + margin-bottom: 20px; + font-size: 12px; + + ul { + list-style: none; + margin: 0 0 0 -40px; + + + li { + margin: 10px 0; + + .label { + padding: 2px 4px; + } + + span.quickMenu { + float: right; + text-align: right; + + .glyphicons { + padding: 5px 0 5px 25px; + + &:before{ + font-size: 14px; + margin: -2px 0px 0px 5px; + color: @grey; + } + + } + + } + + } + + } + + } + + } + + .contacts { + background: lighten(@grey, 20%); + padding-top: 30px; + + .btn { + width: 100%; + margin-bottom: 30px; + } + + ul { + padding: 0; + list-style: none; + + li { + height: 30px; + margin: 0 -15px; + padding: 5px 15px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis !important; + position: relative; + cursor: pointer; + + .label { + display: inline-block; + width: 6px; + height: 6px; + padding: 0; + margin: 0 5px 2px 0px; + } + + &:hover { + background: lighten(@grey, 15%); + } + + } + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-invoice.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-invoice.less new file mode 100644 index 0000000..13769a3 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-invoice.less @@ -0,0 +1,19 @@ +/* Page: Invoice +=================================================================== */ + +.invoice { + + .header { + .well { + p{ + padding: 0; + margin: 0px 0; + } + } + } + + table { + margin-bottom: 20px !important; + } + +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-lockscreen.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-lockscreen.less new file mode 100644 index 0000000..c3bb0c0 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-lockscreen.less @@ -0,0 +1,33 @@ +/* Page LockScreen +=================================================================== */ +.login-box-locked { + position: relative; + z-index: 9999; + background: rgba(255,255,255,.9); + padding: 30px; + border: 1px solid lighten(@grey, 20%); + margin-top: 250px; + + &.type2 { + background: rgba(255,255,255,.7); + } + + img.avatar { + float: left; + width: 120px; + margin-right: 20px; + } + + p { + margin-top: -8px; + font-weight: 300; + } + + a { + display: block; + font-weight: 300; + margin-top: 5px; + font-size: 12px; + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-login-register.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-login-register.less new file mode 100644 index 0000000..ef00949 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-login-register.less @@ -0,0 +1,85 @@ +/* Login Box & Register Box +=================================================================== */ +.login-box, +.register-box { + width: 400px; + padding: 20px; + margin: 100px auto; + background: #fff; + + .header { + background: @darkGrey; + color: white; + text-align: center; + margin: -20px -20px 20px -20px; + padding: 15px; + text-transform: uppercase; + } + + form.login { + + input[type="text"], + input[type="password"] { + border-right: none !important; + .border-radius(2px 0 0 2px); + } + + .input-group-addon { + height: 0px !important; + border: 1px solid lighten(@grey, 20%) !important; + background: white; + .border-radius(0 2px 2px 0); + border-left: 1px none !important; + margin-left: -1px !important; + } + + } + + label { + margin: 10px 5px -10px 5px; + } + + input[type="text"], + input[type="password"] { + border: 1px solid lighten(@grey, 20%); + .box-shadow; + .border-radius; + padding: 0px 10px; + height: 40px; + .border-radius(2px); + + &:focus { + outline: none; + } + } + + .confirm { + position: relative; + margin: 20px 0 10px -15px; + + input { + } + + label { + position: absolute; + top: -9px; + left: 30px; + } + } + + form.register { + .input-group-addon { + height: 0px !important; + width: 35%; + border: 1px solid lighten(@grey, 20%) !important; + background: lighten(@grey, 20%) !important; + .border-radius; + } + } + + button { + margin: 15px 0px !important; + } + + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-pricing-tables.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-pricing-tables.less new file mode 100644 index 0000000..c955812 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-pricing-tables.less @@ -0,0 +1,246 @@ +/* Price Tables +=================================================================== */ +.price-table.type1 { + margin-top: 22px; + padding-left: 1px; + + ul { + position: relative; + z-index: 1; + list-style: none; + float: left; + margin:0px -1px 0px -1px; + padding: 0px; + text-align: center; + border: 1px solid lighten(@grey, 15%); + background: @bodyBackground; + + li:nth-child(2n+1) { + background: lighten(@grey, 20%); + } + + li.header { + + } + + li.price { + background: @darkGrey; + color: white; + font-size: 18px; + font-weight: bold; + text-shadow: none; + padding: 20px 0px; + height: 58px; + } + + li.strike { + text-decoration: line-through; + } + + li { + font-size: 12px; + text-shadow: none; + padding: 10px 0px; + + span { + font-weight: bold; + } + } + + } + + ul.best-option { + border: 3px solid @blue; + margin:-27px -3px 0px -3px; + z-index: 2; + + li.header { + font-size: 16px; + font-weight: bold; + padding: 20px 0px; + position: relative; + overflow: hidden; + + span { + font-size: 10px; + line-height: 12px; + position: absolute; + top: -20px; + left: -141px; + background: @blue; + color: white; + padding: 30px 130px 5px 130px; + -webkit-transform:rotate(315deg); + -moz-transform:rotate(315deg); + -ms-transform:rotate(315deg); + -o-transform:rotate(315deg); + } + + } + + li.price { + font-size: 24px; + font-weight: bold; + padding: 20px 0px; + background: @blue; + } + + } + +} + +.price-table.type2 { + margin-top: 22px; + padding-left: 1px; + + ul { + position: relative; + z-index: 1; + list-style: none; + float: left; + margin:0px -1px 0px -1px; + padding: 0px; + text-align: center; + border: 1px solid lighten(@grey, 10%); + background: white; + + li.header { + background: @grey; + color: white; + font-size: 20px; + padding-bottom: 70px; + margin-bottom: 60px; + } + + li.price { + background: @grey; + color: white; + font-size: 40px; + font-weight: bold; + padding: 26px 0px; + border: 4px solid lighten(@grey, 20%); + .border-radius(50em); + display: inline-block; + height: 116px; + width: 116px; + top: 45px; + left: 50%; + margin-left: -54px; + position: absolute; + + span { + font-size: 20px; + } + } + + li.strike { + text-decoration: line-through; + } + + li { + font-size: 12px; + padding: 10px 0px; + border-bottom: 1px solid lighten(@grey, 20%); + background: white; + + span { + font-weight: bold; + } + } + + li.select { + position: relative; + background: @grey; + padding: 0px; + + a { + color: white; + font-weight: 700; + font-size: 14px; + text-decoration: none; + display: block; + width: 100%; + height: 100%; + padding: 10px 0px; + } + + &:before { + content: ''; + position: absolute; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-bottom: 10px solid @grey; + top: -10px; + left: 50%; + margin-left: -5px; + } + + &:hover { + background: darken(lighten(@grey, 20%), 20%); + + &:before { + border-bottom: 10px solid darken(lighten(@grey, 20%), 20%); + } + + } + + } + + } + + ul.best-option { + + li.header { + font-weight: bold; + position: relative; + background: darken(@green, 20%); + } + + li.price { + font-weight: bold; + background: @green; + border: 4px solid darken(@green, 10%); + } + + li.select { + position: relative; + background: darken(@green, 20%); + + &:before { + border-bottom: 10px solid darken(@green, 20%); + } + + &:hover { + background: darken(@green, 30%); + + &:before { + border-bottom: 10px solid darken(@green, 30%); + } + + } + + } + + } + +} + +.price-table.five ul { + width: 20%; +} + +.price-table.four ul { + width: 25%; +} + +.price-table.three ul { + width: 33.333%; +} + +.price-table.two ul { + width: 50%; +} + +.price-table.one ul { + width: 100%; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-profile.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-profile.less new file mode 100644 index 0000000..87b79b5 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-profile.less @@ -0,0 +1,89 @@ +/* Page: Invoice +=================================================================== */ + +.profile-image { + width: 100%; + border: 5px solid white; + outline: 1px solid lighten(@grey, 15%) +} + +.profile h3 { + padding: 0 5px; +} + +ul.profile-details { + margin-top: 10px; + padding: 0 5px; + list-style: none; + color: darken(@grey, 20%); + + li { + position: relative; + margin: 0 0 20px 0; + padding-left: 22px; + + div { + color: @grey; + + i { + position: absolute; + top: 4px; + left: -5px; + color: lighten(@grey,10%); + width: 20px; + text-align: center; + } + + + + } + + input[type="text"] { + color: black !important; + } + + } +} + +ul.friends-list { + padding: 0; + list-style: none; + + li { + width: auto; + min-width: 170px; + margin-bottom: 20px; + border: 1px solid lighten(@grey, 20%); + background: lighten(@grey, 25%); + float: left; + padding: 5px; + margin: 0px 0px 5px 5px; + white-space: nowrap; + overflow: hidden; + + &:last-child { + margin-bottom: 0; + } + + .avatar { + float: left; + margin-right: 10px; + width: 40px; + + img { + width: 40px; + } + + } + + a { + display: inline-block; + font-size: 22px; + line-height: 8px; + text-decoration: none; + color: @grey; + } + + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-todo.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-todo.less new file mode 100644 index 0000000..0edab2a --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/page-todo.less @@ -0,0 +1,432 @@ +/* Page: Tasks +=================================================================== */ +.page-todo { + + .tasks { + background: white; + padding: 0; + border-right: 1px solid lighten(@grey, 15%); + margin: -30px 15px -30px -15px; + + } + + .task-list { + padding: 30px 15px; + height: 100%; + } + + .graph { + height: 100%; + } + + .priority.high { + background: lighten(@red, 30%); + margin-bottom: 1px; + + span { + background: @red; + padding: 2px 10px; + color: white; + display: inline-block; + font-size: 12px; + } + } + + .priority.medium { + background: lighten(@lightOrange, 35%); + margin-bottom: 1px; + + span { + background: @lightOrange; + padding: 2px 10px; + color: white; + display: inline-block; + font-size: 12px; + } + } + + .priority.low { + background: lighten(@darkGreen, 35%); + margin-bottom: 1px; + + span { + background: @darkGreen; + padding: 2px 10px; + color: white; + display: inline-block; + font-size: 12px; + } + } + + .task { + border-bottom: 1px solid #f9f9f9; + margin-bottom: 1px; + position: relative; + + .desc { + display: inline-block; + width: 75%; + padding: 10px 10px; + font-size: 12px; + + .title { + font-size: 18px; + margin-bottom: 5px; + } + + } + + .time { + display: inline-block; + width: 15%; + padding: 10px 10px 10px 0px; + font-size: 12px; + text-align: right; + position: absolute; + top: 0px; + right: 0px; + + .date { + font-size: 18px; + margin-bottom: 5px; + } + } + } + + .task.last { + border-bottom: 1px solid transparent; + } + + .task.high { + border-left: 2px solid @red; + } + + .task.medium { + border-left: 2px solid @lightOrange; + } + + .task.low { + border-left: 2px solid @darkGreen; + } + + .timeline { + width: auto; + height: 100%; + margin: 20px auto; + position: relative; + + &:before { + position: absolute; + content: ''; + height: 100%; + width: 4px; + background: lighten(@grey,20%); + left: 50%; + margin-left:-2px; + } + } + + .timeslot { + display: inline-block; + position: relative; + width: 100%; + margin: 5px 0px; + + .task { + position: absolute; + width: 42%; + padding-right: 18px; + display: block; + height: auto; + border: none; + .box-sizing(content-box); + + span { + border: 2px solid @lightBlue; + background: lighten(@lightBlue, 30%); + padding: 5px; + display: block; + font-size: 11px; + .border-radius(2px); + + span.details { + font-size: 16px; + margin-bottom: 10px; + } + + span.remaining{ + font-size: 14px; + } + + span { + border: 0px; + background: transparent; + padding: 0px; + } + + } + + .arrow { + position: absolute; + top: 6px; + right: 0px; + height: 20px; + width: 20px; + background: url(../img/timeline-left-arrow.png) no-repeat; + } + } + + .icon { + position: absolute; + border: 2px solid @grey; + background: @darkGrey; + .border-radius(50em); + height: 30px; + width: 30px; + left: 50%; + margin-left: -16px; + color: white; + font-size: 14px; + line-height: 30px; + text-align: center; + text-shadow: none; + z-index: 2; + .box-sizing(content-box); + + } + + .time { + background: lighten(@grey,20%); + position: absolute; + .border-radius(4px); + top: 1px; + left: 50%; + padding: 5px 10px 5px 40px; + z-index: 1; + margin-top: 1px; + } + + } + + .timeslot.alt { + + .task { + left: auto; + right: -20px; + padding-left: 18px; + .box-sizing(content-box); + + .arrow { + position: absolute; + top: 6px; + left: 0px; + height: 20px; + width: 20px; + background: url(../img/timeline-right-arrow.png) no-repeat; + } + } + + .time { + top: 1px; + left: auto; + right: 50%; + padding: 5px 40px 5px 10px; + } + + } + +} + +/* Higher than 992 (desktop devices) +====================================================================== */ +@media only screen and (min-width: 992px) and (max-width: 1199px){ + + .page-todo { + + task { + + .desc { + display: inline-block; + width: 70%; + padding: 10px 10px; + font-size: 12px; + + .title { + font-size: 16px; + margin-bottom: 5px; + } + } + + .time { + display: inline-block; + float: right; + width: 20%; + padding: 10px 10px; + font-size: 12px; + text-align: right; + + .date { + font-size: 16px; + margin-bottom: 5px; + } + } + } + } +} + + +/* Tablet Portrait (devices and browsers) +====================================================================== */ +@media only screen and (min-width: 768px) and (max-width: 991px) { + + .page-todo { + + .task { + border-bottom: 1px solid #f9f9f9; + margin-bottom: 1px; + + .desc { + display: inline-block; + width: 65%; + padding: 10px 10px; + font-size: 10px; + margin-right: -20px; + + .title { + font-size: 14px; + margin-bottom: 5px; + } + } + + .time { + display: inline-block; + float: right; + width: 25%; + padding: 10px 10px; + font-size: 10px; + text-align: right; + + .date { + font-size: 14px; + margin-bottom: 5px; + } + } + } + + .timeslot { + + .task { + + span { + border: 2px solid rgba(103, 194, 239, 1); + background: rgba(103, 194, 239, .1); + padding: 5px; + display: block; + font-size: 10px; + + span { + border: 0px; + background: transparent; + padding: 0px; + } + + span.details { + font-size: 14px; + margin-bottom: 0px; + } + + span.remaining { + font-size: 12px; + } + + } + + } + + } + + } + +} + +/* All Mobile Sizes (devices and browser) +====================================================================== */ +@media only screen and (max-width: 767px) { + + .page-todo { + + .tasks { + position: relative; + margin: 0px !important; + } + + .graph { + position: relative; + margin: 0px !important; + } + + .task { + border-bottom: 1px solid #f9f9f9; + margin-bottom: 1px; + + .desc { + display: inline-block; + width: 65%; + padding: 10px 10px; + font-size: 10px; + margin-right: -20px; + + .title{ + font-size: 14px; + margin-bottom: 5px; + } + } + + .time { + display: inline-block; + float: right; + width: 25%; + padding: 10px 10px; + font-size: 10px; + text-align: right; + + .date { + font-size: 14px; + margin-bottom: 5px; + } + } + } + + .timeslot { + + .task { + + span { + padding: 5px; + display: block; + font-size: 10px; + + span { + border: 0px; + background: transparent; + padding: 0px; + } + + span.details { + font-size: 14px; + margin-bottom: 0px; + } + + span.remaining { + font-size: 12px; + } + + } + + } + + } + + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/quick-buttons.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/quick-buttons.less new file mode 100644 index 0000000..50d0cba --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/quick-buttons.less @@ -0,0 +1,49 @@ +/* Quick Buttons +=================================================================== */ +.quick-button { + border: 1px solid lighten(@grey, 15%); + background: lighten(@grey, 20%); + margin-bottom: -1px; + padding: 30px 0px 10px 0px; + font-size: 14px; + display:block; + text-align: center; + cursor: pointer; + position: relative; + .transition(all 0.3s ease); + color: @grey; + .border-radius(2px); + + &:hover { + color: @darkGrey; + text-decoration: none; + background: lighten(@grey, 15%); + } + + .notification { + .border-radius(2px); + top: -1px; + right: -1px; + font-size: 10px; + } + + i { + font-size: 32px; + } + + &.small { + padding: 15px 0px 0px 0px; + font-size: 10px; + + i { + font-size: 20px; + } + + .notification { + top: -1px; + right: -1px; + font-size: 7px; + padding: 4px 5px; + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/responsive.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/responsive.less new file mode 100644 index 0000000..60bef3b --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/responsive.less @@ -0,0 +1,373 @@ +/* Higher than 1200 (desktop devices) +====================================================================== */ +@media (min-width: 1200px) { + + .hidden-xs, + .hidden-sm, + .hidden-md, + .hidden-lg { + display: inline-block !important; + } + + + a.navbar-brand { + position: absolute; + width: 14.422%; + left: 15px; + } + + .navbar-collapse { + max-height: 100%; + } + + .container { + width: 100% !important; + + #content { + padding: 30px; + margin: 0; + height: 100%; + width: 85.578%; + } + + #sidebar-left { + width: 14.422%; + } + + .breadcrumb { + margin: -30px -30px 30px -30px; + padding: 10px 30px; + } + + } + +} + +/* Higher than 992 (desktop devices) +====================================================================== */ +@media only screen and (min-width: 992px) and (max-width: 1199px){ + + .hidden-xs, + .hidden-sm, + .hidden-md, + .hidden-lg { + display: inline-block !important; + } + + a.navbar-brand { + position: absolute; + width: 14.422%; + left: 15px; + } + + .navbar-collapse { + max-height: 100%; + } + + .container { + width: 100% !important; + + #content { + padding: 30px; + margin: 0; + height: 100%; + width: 85.578%; + } + + #sidebar-left { + width: 14.422%; + } + + .breadcrumb { + margin: -30px -30px 30px -30px; + padding: 10px 30px; + } + + } + +} + +/* Tablet Portrait (devices and browsers) +====================================================================== */ +@media only screen and (min-width: 768px) and (max-width: 991px) { + + + a#main-menu-toggle { + margin-left: 8.334%; + } + + a.navbar-brand { + width: 8.334%; + padding: 8px 0px !important; + position: absolute; + left: 15px; + + span { + font-size: 12px; + } + } + + .navbar-collapse { + max-height: 100%; + } + + .container { + width: 100% !important; + + #content { + padding: 30px; + } + + #sidebar-left { + margin-left: 0px !important; + width: 8.334% !important; + } + + .breadcrumb { + margin: -30px -30px 30px -30px; + padding: 10px 30px; + } + + } + + .sidebar-nav > ul { + margin: -9px -10px; + border: none; + padding-bottom: 1px; + font-size: 18px; + } + + .nav.main-menu > li > ul > li, + .nav.main-menu > li > ul > li > ul > li, + .nav.main-menu > li > ul > li > ul > li > ul > li { + width: 100%; + } + + .nav.main-menu > li > a > i, + .nav.main-menu > li > ul > li > a > i, + .nav.main-menu > li > ul > li > ul > li > a > i, + .nav.main-menu > li > ul > li > ul > li > ul > li > a > i { + height: 38px; + width: 100%; + padding: 11px 0px; + display: inline-block; + text-align: center; + border-right: 1px solid lighten(@grey, 15%); + } + + .btn-navbar { + display: none !important; + } + + .nav-collapse, + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + margin-left: -20px !important; + } + + .sidebar-nav { + padding:0; + margin-bottom:0; + } + +} + +/* All Mobile Sizes (devices and browser) +====================================================================== */ +@media only screen and (max-width: 767px) { + + body { + &:after, &:before { + display: none; + } + } + + a.navbar-brand { + margin-bottom: 0px; + } + + #search { + margin-left: 10px !important; + } + + .hidden-sm { + display: inline-block !important; + } + + .navbar-toggle { + position: absolute; + top:-3px; + right: -10px; + z-index: 100; + background: transparent !important; + text-shadow: none !important; + border: none !important; + + .icon-bar { + background: white; + } + } + + .navbar-collapse { + max-height: 300px; + border-top: none; + box-shadow: none; + overflow-x: hidden; + padding-right: 0px; + padding-left: 0px; + } + + + .header-nav { + + display: none; + + li { + float: left; + } + + } + + .pull-right { + width: 100%; + margin: 10px auto; + text-align: center; + } + + #content { + overflow: hidden; + + .breadcrumb { + margin: -4px -5px 30px -5px; + } + + } + + #sidebar-left { + min-height: 0px; + padding: 0 !important; + } + + .sidebar-nav { + border-bottom: 1px solid lighten(@grey,15%); + } + + .sidebar-nav > ul { + margin: 0 0px; + background: @bodyBackground; + } + + /* Page: Messages + =================================================================== */ + .message-view { + margin: 0; + } + + .price-table-overlay { + width: 100% !important; + overflow-x: scroll; + } + + .price-table.five { + width: 1000px; + } + + .price-table.four { + width: 800px; + } + + .price-table.three { + width: 900px; + } + + .price-table.five ul { + width: 200px; + } + + .price-table.four ul { + width: 200px; + } + + .price-table.three ul { + width: 300px; + } + + .price-table.two ul { + width: 50%; + } + + .price-table.one ul { + width: 100%; + } + +} + +/* Mobile Landscape Size to Tablet Portrait (devices and browsers) +====================================================================== */ +@media only screen and (min-width: 480px) and (max-width: 767px) { + + body { + padding: 0px; + } + + #content { + padding: 5px; + } + +} + +/* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) +=================================================================== */ +@media only screen and (max-width: 479px) { + + body { + padding: 0px; + } + + .col-xxs-12 { + width: 100%; + } + + a.navbar-brand { + background: transparent; + + &:hover { + background: transparent; + } + } + + #search { + select { + display: none; + } + + input { + margin-top: 5px; + margin-left: -10px !important; + width: 100% !important; + } + } + + #content { + padding: 5px; + } + + .quick-button, + .quick-button-small { + margin-bottom: 20px; + } + + .discussions { + + ul { + + li { + + .date { + display: none; + } + } + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/skill-bars.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/skill-bars.less new file mode 100644 index 0000000..79c3a98 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/skill-bars.less @@ -0,0 +1,35 @@ +/* Skill Bars +=================================================================== */ +ul.skill-bar { + padding: 0px; + + h5 { + margin-bottom:6px; + } + + li { + margin-bottom:12px; + list-style: none; + padding-left: 0px; + + .meter { + height: 20px; + position: relative; + background: lighten(@grey,20%); + + span { + display: block; + height: 100%; + position: relative; + overflow: hidden; + color: white; + background: @grey; + .backgroundColor; + text-align: right; + padding-right: 10px; + margin: 0; + } + } + } +} + diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/sliders_progress_bars.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/sliders_progress_bars.less new file mode 100644 index 0000000..4eec662 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/sliders_progress_bars.less @@ -0,0 +1,214 @@ +/* UI - Sliders & Progress +=================================================================== */ +.slider { + background: lighten(@grey, 20%); + border: none; + height: 10px; + position: relative; + z-index: 10; + margin: 5px 0px !important; + + .ui-slider-range { + position: absolute; + .box-sizing(content-box); + } + + &.small { + height: 6px; + } + +} + +.ui-slider-handle { + border: 1px solid lighten(@grey, 10%); + outline: none !important; +} + +.ui-slider-horizontal { + + .ui-slider-handle { + background: url("../img/handle.png") no-repeat center center scroll white !important; + background-position: 50% 50%; + background-size: 8px 8px !important; + } + +} + +.ui-slider-horizontal { + + &.small { + + .ui-slider-handle { + background: url("../img/handle.png") no-repeat center center scroll white !important; + background-position: 50% 50%; + background-size: 8px 8px !important; + width: 14px !important; + height: 14px !important; + } + + } + +} + +.sliderVertical { + background: lighten(@grey, 20%); + border: none; + top: auto; + bottom: auto; + width: 10px !important; + position: relative; + float: left; + height: 100px; + margin: 10px 20px; + width: 5px; + + .ui-slider-range { + height: 100%; + width: 100%; + top: auto; + bottom: auto; + .border-radius(2px); + .box-sizing(content-box); + + } + + .ui-slider-handle { + background: url("../img/handlev.png") no-repeat center center scroll white !important; + background-position: 50% 50%; + background-size: 8px 8px !important; + left: 50%; + margin: 9px 0px -9px -9px !important; + } + + .ui-slider-range-max { + top: 0; + } + + .ui-slider-range-min { + bottom: 0; + } + + &.small { + width: 6px !important; + position: relative; + float: left; + height: 100px; + margin: 10px 20px; + width: 5px; + + .ui-slider-handle { + background: url("../img/handlev.png") no-repeat center center scroll white !important; + background-position: 50% 50%; + background-size: 8px 8px !important; + width: 14px; + height: 14px; + margin: 0px 0px -7px -7px !important; + } + + } + +} + +.sliderBlue .ui-slider-range, .progressBlue .ui-progressbar-value { + background: @blue; +} + +.sliderGreen .ui-slider-range, .progressGreen .ui-progressbar-value { + background: @green; +} + +.sliderDarkGreen .ui-slider-range, .progressDarkGreen .ui-progressbar-value { + background: @darkGreen; +} + +.sliderPink .ui-slider-range, .progressPink .ui-progressbar-value { + background: @pink; +} + +.sliderOrange .ui-slider-range, .progressOrange .ui-progressbar-value { + background: @orange; +} + +.sliderLightOrange .ui-slider-range, .progressLightOrange .ui-progressbar-value { + background: @lightOrange; +} + +.sliderRed .ui-slider-range, .progressRed .ui-progressbar-value { + background: @red; +} + +.sliderYellow .ui-slider-range, .progressYellow .ui-progressbar-value { + background: @yellow; +} + +.progress { + background: lighten(@grey, 20%); + color: lighten(@grey, 20%); + border: none; + height: 14px; + .box-shadow; + position: relative; + margin-top: -2px; + + .ui-progressbar-value { + border: none; + height: 100%; + top: 1px; + position: absolute; + left: 1px; + .box-shadow; + .border-radius(2px); + } + + &.slim { + height: 10px; + } + +} + +.progressBarValue { + + span { + font-size: 12px; + } + + span.progressCustomValueVal { + font-size: 18px; + font-weight: 700; + padding:0 5px; + color: @orange; + } + +} + +.progressSlim { + background: lighten(@grey, 10%); + border: none; + height: 10px; + position: relative; + margin-top: -2px; + + .ui-progressbar-value { + border-color: transparent; + height: 100%; + top: 0px; + position: absolute; + left: 0px; + .border-radius(2px); + } +} + +.tasks .progressSlim { + overflow: hidden; + border: none !important; + height: 8px; + .box-shadow; + margin-top: 0px; + + .ui-progressbar-value { + overflow: hidden; + margin: 0px; + border: none !important; + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/smallstats.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/smallstats.less new file mode 100644 index 0000000..860434f --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/smallstats.less @@ -0,0 +1,236 @@ +/* Widget Stats +=================================================================== */ + +.jqstooltip { + .box-sizing(content-box); +} + +.smallstat { + background: white; + padding: 10px; + position: relative; + text-align: right; + + .linechart-overlay, .boxchart-overlay { + width: 84px; + padding: 10px; + text-align: center; + margin-right: 10px; + float: left; + .backgroundColor; + overflow: hidden; + } + + .piechart-overlay { + padding: 5px; + text-align: center; + margin-right: 10px; + float: left; + .backgroundColor; + overflow: hidden; + } + + .piechart { + color: white; + font-size: 10px; + } + + i { + text-align: center; + display: block; + color: white; + width: 50px; + font-size: 22px; + padding: 14px 0px; + float: left; + margin-right: 10px; + .backgroundColor; + + } + + .title { + top: 12px; + color: @grey; + display: block; + font-size: 12px; + margin-top: 4px; + font-weight: bold; + } + + .value { + font-size: 20px; + + } + + .more { + background: lighten(@grey, 20%); + border-top: 1px solid lighten(@grey, 15%); + margin: 12px -10px -10px -10px; + padding: 5px 10px; + display: block; + font-size: 12px; + text-align: left; + + &:hover { + color: @darkGrey; + text-decoration: none; + } + + span { + + } + + i { + padding: 0; + margin: 4px 0 0 0; + display: inline; + color: @darkGrey; + font-size: 10px; + float: right; + width: 10px; + } + } + +} + +/* Box Stats +=================================================================== */ +ul.stats { + list-style: none; + padding: 0; + border-top: 1px solid lighten(@grey, 20%); + margin: 20px -10px -10px -10px; + .clearfix; + + li { + position: relative; + z-index: 2; + width: 25%; + border-right: 1px solid lighten(@grey, 20%); + float: left; + text-align: center; + padding: 20px 0px; + margin: 0; + overflow:hidden; + + &:fisrt-child { + + } + + &:last-child { + border: none; + } + + .bgchart { + width: 100%; + height: 100%; + position: absolute; + z-index: -1; + top: 0px; + left: 0px; + } + + } + +} + +/* Info Box +=================================================================== */ +.info-box { + + .backgroundColor { + color: white; + padding: 10px; + } + + .title, .value { + font-weight: bold; + font-size: 12px; + margin: 0; + padding: 0; + } + + .date, .change { + font-size: 10px; + margin: 0; + padding: 0; + } + + .title, .date { + float: left; + } + + .value, .change { + float: right; + } + + .quarters { + background: white; + .clearfix; + + .quarter { + padding: 10px; + span { + display: block; + font-size: 10px; + color: @grey; + } + } + + .q1, .q2, .q3, .q4 { + width: 50%; + float:left; + } + + .q1, .q2 { + border-bottom: 1px solid lighten(@grey, 20%); + height: 60px; + } + + .q2 { + padding: 0; + } + + .q2, .q4 { + text-align: right; + } + + .q4 { + border-left: 1px solid lighten(@grey, 20%); + } + + .verticalChart { + float: right; + text-align: center; + margin: 3px 0 0 0; + width: 100%; + padding: 6px; + + .singleBar { + width: 10.5%; + margin:0 0px 0 3px; + + .bar { + height: 22px; + .border-radius(1px); + + .value { + background: @grey; + .border-radius(1px); + } + } + + .title { + margin: 2px auto 0 auto; + text-align: center; + color: @grey; + font-size: 8px; + font-weight: 400; + width: 100%; + } + } + } + + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/switch-input.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/switch-input.less new file mode 100644 index 0000000..06a7b0f --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/switch-input.less @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2013 Thibaut Courouble + * http://www.cssflow.com + * + * Licensed under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + */ + +.switch { + position: relative; + display: inline-block; + vertical-align: top; + width: 56px; + height: 20px; + padding: 3px; + background-color: white; + .border-radius(2px); + box-shadow: inset 0 -1px white, inset 0 1px 1px rgba(0, 0, 0, 0.05); + cursor: pointer; + .box-sizing(content-box); +} + +.switch-input { + position: absolute; + top: 0; + left: 0; + opacity: 0; +} + +.switch-label { + position: relative; + display: block; + height: inherit; + font-size: 10px; + text-transform: uppercase; + background: @lightGrey; + border-radius: inherit; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.15); + -webkit-transition: 0.15s ease-out; + -moz-transition: 0.15s ease-out; + -o-transition: 0.15s ease-out; + transition: 0.15s ease-out; + -webkit-transition-property: opacity background; + -moz-transition-property: opacity background; + -o-transition-property: opacity background; + transition-property: opacity background; +} +.switch-label:before, +.switch-label:after { + position: absolute; + top: 50%; + margin-top: -.5em; + line-height: 1; + -webkit-transition: inherit; + -moz-transition: inherit; + -o-transition: inherit; + transition: inherit; +} +.switch-label:before { + content: attr(data-off); + right: 11px; + color: #aaa; + text-shadow: 0 1px rgba(255, 255, 255, 0.5); +} +.switch-label:after { + content: attr(data-on); + left: 11px; + color: white; + text-shadow: 0 1px rgba(0, 0, 0, 0.2); + opacity: 0; +} +.switch-input:checked ~ .switch-label { + background: @grey; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15), inset 0 0 3px rgba(0, 0, 0, 0.2); +} +.switch-input:checked ~ .switch-label:before { + opacity: 0; +} +.switch-input:checked ~ .switch-label:after { + opacity: 1; +} + +.switch-handle { + position: absolute; + top: 4px; + left: 4px; + width: 18px; + height: 18px; + background: white; + .border-radius(2px);; + box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2); + background-image: -webkit-linear-gradient(top, white 40%, #f0f0f0); + background-image: -moz-linear-gradient(top, white 40%, #f0f0f0); + background-image: -o-linear-gradient(top, white 40%, #f0f0f0); + background-image: linear-gradient(to bottom, white 40%, #f0f0f0); + -webkit-transition: left 0.15s ease-out; + -moz-transition: left 0.15s ease-out; + -o-transition: left 0.15s ease-out; + transition: left 0.15s ease-out; +} +.switch-handle:before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + margin: -6px 0 0 -6px; + width: 12px; + height: 12px; + background: #f9f9f9; + .border-radius(2px); + box-shadow: inset 0 1px rgba(0, 0, 0, 0.02); + background-image: -webkit-linear-gradient(top, #eeeeee, white); + background-image: -moz-linear-gradient(top, #eeeeee, white); + background-image: -o-linear-gradient(top, #eeeeee, white); + background-image: linear-gradient(to bottom, #eeeeee, white); +} +.switch-input:checked ~ .switch-handle { + left: 40px; + box-shadow: -1px 1px 5px rgba(0, 0, 0, 0.2); +} + +.switch-primary > .switch-input:checked ~ .switch-label { + background: @blue; +} + +.switch-success > .switch-input:checked ~ .switch-label { + background: @darkGreen; +} + +.switch-warning > .switch-input:checked ~ .switch-label { + background: @lightOrange; +} + +.switch-important > .switch-input:checked ~ .switch-label { + background: @red; +} + +.switch-info > .switch-input:checked ~ .switch-label { + background: @lightBlue; +} + +.switch-danger > .switch-input:checked ~ .switch-label { + background: #d9534f; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/table.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/table.less new file mode 100644 index 0000000..5bb6555 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/table.less @@ -0,0 +1,65 @@ +table { + + tr { + + td, th { + + &.left { text-align: left } + &.center { text-align: center } + &.right { text-align: right } + + } + + td { + + .progress { + margin: 3px 0 0 0; + } + + } + + } + + &.table-clear { + + tr,td { + border: none !important; + } + + } + + &.small-font { + font-size: 12px; + } + +} + +.table thead > tr > th, +.table tbody > tr > th, +.table tfoot > tr > th, +.table thead > tr > td, +.table tbody > tr > td, +.table tfoot > tr > td { + padding: 8px; + line-height: 1.428571429; + vertical-align: top; + border-top: 1px solid lighten(@grey,20%); +} + +.table thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid lighten(@grey,20%); +} + +.table-bordered { + border: 1px solid lighten(@grey,20%); +} + +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid lighten(@grey,20%); +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/tabs.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/tabs.less new file mode 100644 index 0000000..64089e8 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/tabs.less @@ -0,0 +1,81 @@ +/* Tabs +=================================================================== */ +.nav-tabs { + + li { + + a { + border-color: lighten(@grey, 15%); + .border-radius(); + background: lighten(@grey, 20%); + margin: 6px -1px -6px 0px; + line-height: 1; + + &:hover { + border-color: lighten(@grey, 15%); + background: lighten(@grey, 15%); + } + } + + &.active > a { + line-height: 1.428571429; + margin: 0 -1px 0 0; + } + + } + +} + +.tab-content { + background: white; + border: 1px solid lighten(@grey, 15%); + border-top: none; + padding: 10px; +} + +.box-header { + + .nav-tabs { + border: none; + float: right; + + li { + + a { + background: transparent; + border: none; + border-left: 1px solid lighten(@grey, 10%); + .border-radius(); + margin: 0; + font-size: 14px; + line-height: 16px; + font-weight: 300; + padding: 11px 15px; + height: 40px; + } + + &.active > a { + background: white; + border: none; + border-left: 1px solid lighten(@grey, 10%); + } + + &:hover { + border: none; + } + + &:last-child { + margin-right: 3px; + } + } + + } +} + +.box-content { + .tab-content { + background: transparent; + border: none; + padding: 0; + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/tickets.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/tickets.less new file mode 100644 index 0000000..746af30 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/tickets.less @@ -0,0 +1,64 @@ +/* Support tickets +=================================================================== */ +ul.tickets { + margin:0 0 0 -40px; + + li:last-child { + border-bottom: none; + } + + li:first-child { + border-top: none; + border-bottom: 1px solid @borderGrey; + } + + li { + list-style: none; + padding: 5px 0; + border-bottom: 1px solid @borderGrey; + font-size: 12px; + + &.ticket { + .left { + display: inline-block; + width: 60% + } + + .right { + display: inline-block; + width: 39%; + text-align: right; + } + + .status { + width: 100px; + display: inline-block; + text-align: center; + } + + .date { + width: 150px; + display: inline-block; + text-align: center; + } + + .title { + display: inline-block; + font-weight: bold; + } + + .name { + display: inline-block; + + } + + .number { + display: inline-block; + font-weight: bold; + margin-left: 20px; + } + + } + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/timepicker.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/timepicker.less new file mode 100644 index 0000000..cf9f226 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/timepicker.less @@ -0,0 +1,141 @@ +/* + * Timepicker Component for Twitter Bootstrap + * + * Copyright 2013 Joris de Wit + * + * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +.bootstrap-timepicker { + position: relative; + + &.pull-right { + .bootstrap-timepicker-widget { + &.dropdown-menu { + left: auto; + right: 0; + + &:before { + left: auto; + right: 12px; + } + &:after { + left: auto; + right: 13px; + } + } + } + } + + .input-group-addon { + cursor: pointer; + -webkit-border-radius: 4px 0px 0px 4px !important; + border-radius: 4px 0px 0px 4px !important; + border-right: 0px; + + } +} +.bootstrap-timepicker-widget { + &.dropdown-menu { + padding: 2px 3px 2px 2px; + margin-left: 54px; + &.open { + display: inline-block; + } + &:before { + border-bottom: 7px solid rgba(0, 0, 0, 0.2); + border-left: 7px solid transparent; + border-right: 7px solid transparent; + content: ""; + display: inline-block; + left: 9px; + position: absolute; + top: -7px; + } + &:after { + border-bottom: 6px solid #FFFFFF; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + content: ""; + display: inline-block; + left: 10px; + position: absolute; + top: -6px; + } + } + + a.btn, input { + border-radius: 4px; + } + + table { + width: 100%; + margin: 0; + + td { + text-align: center; + height: 30px; + margin: 0; + padding: 2px; + + &:not(.separator) { + min-width: 30px; + } + + span { + width: 100%; + } + a { + border: 1px transparent solid; + width: 100%; + display: inline-block; + margin: 0; + padding: 8px 0; + outline: 0; + color: #333; + + &:hover { + text-decoration: none; + background-color: #eee; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border-color: #ddd; + } + + i { + margin-top: 2px; + } + } + input { + width: 25px; + margin: 0; + text-align: center; + border: 1px solid @grey; + } + } + } +} + +.bootstrap-timepicker-widget .modal-content { + padding: 4px; +} + +@media (min-width: 767px) { + .bootstrap-timepicker-widget.modal { + width: 200px; + margin-left: -100px; + } +} + +@media (max-width: 767px) { + .bootstrap-timepicker { + width: 100%; + + .dropdown-menu { + width: 100%; + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/todo.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/todo.less new file mode 100644 index 0000000..466089d --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/todo.less @@ -0,0 +1,71 @@ +/* ToDo List +=================================================================== */ +.todo { + + ul { + list-style: none; + padding: 0px; + margin: -10px; + + li { + background: white; + margin-left: 0px !important; + padding: 10px 10px 10px 35px; + border-bottom: 1px solid lighten(@grey, 20%); + font-size: 12px; + position: relative; + + &:last-child { + border-bottom: 0px; + } + + .label { + position: absolute; + right: 10px; + } + + .todo-actions{ + position: absolute; + left: 0px; + margin-top: 2px; + + a { + text-decoration: none; + } + + i { + font-size: 14px; + color: lighten(@grey, 15%); + margin: -1px 5px 0px 10px; + display: block; + + &.done { + color: lighten(@grey, 10%); + } + + &:hover { + color: @grey; + } + } + } + + .remove { + display: none; + position: absolute; + right: 10px; + color: @grey; + } + + &:hover { + .label { + position: absolute; + right: 30px; + } + .remove { + display: inline; + } + } + + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/tree.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/tree.less new file mode 100644 index 0000000..bdf579f --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/tree.less @@ -0,0 +1,99 @@ +.tree { + + border: 1px solid #BBBBBB; + border-radius: 4px 4px 4px 4px; + overflow-y: auto; + overflow-x: hidden; + padding: 10px 15px 0 15px; + position: relative; + + .tree-folder { + + width: 100%; + min-height: 20px; + cursor: pointer; + margin-top: 1px; + + .tree-folder-header { + + position: relative; + height: 20px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + + &:hover { + background-color: @grey; + } + + i { + position: absolute; + float: left; + top: 1px; + left: 5px; + } + + .tree-folder-name { + padding-left: 29px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + } + + .tree-folder-content { + margin-left: 23px; + } + + } + + .tree-item { + + position: relative; + width: 100%; + height: 20px; + cursor: pointer; + margin-top: 1px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + + &:hover { + background-color: @grey; + } + + .tree-item-name { + position: absolute; + left: 29px; + } + + .tree-dot { + position: absolute; + top: 8px; + left: 10px; + display: block; + width: 4px; + height: 4px; + background-color: @darkGrey; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + } + + .icon-ok { + position: absolute; + top: 1px; + left: 5px; + } + + } + + .tree-selected { + background-color: @grey; + + &:hover { + background-color: @grey; + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/users-list.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/users-list.less new file mode 100644 index 0000000..6f1d0bb --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/users-list.less @@ -0,0 +1,95 @@ +/* Users List +=================================================================== */ +ul.users-list { + padding: 0; + + a:hover { + text-decoration:none; + } + + li:last-child { + border-bottom: none; + min-height: 51px; + } + + li:first-child { + border-top: none; + border-bottom: 1px solid lighten(@grey,20%); + } + + li { + min-height: 60px; + padding: 5px 10px; + list-style:none; + border-bottom: 1px solid lighten(@grey,20%); + font-size: 12px; + + a { + + img.avatar { + height: 40px; + width: 40px; + float: left; + margin-top: 3px; + margin-right: 15px; + .border-radius(2px); + } + } + + .name { + margin: 5px 0 -2px 0; + font-size: 14px; + font-weight: bold; + + .dropdown { + float: right; + margin: -1px 0; + + a { + color: @grey; + font-size: 11px; + text-decoration: none; + } + + ul li { + padding: 0; + min-height: 10px; + + i { + display: inline-block; + width: 20px; + } + + } + + } + + } + + span { + display: inline-block; + margin-right: 5px; + font-size: 10px; + color: @grey; + } + + .place { + width: 35% + } + + + + i { + color: @grey; + margin-right: 2px; + font-size: 11px; + } + } + + &.no-padding { + + li { + padding: 5px 0; + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/less/wizard.less b/gridplatform/bootstrap/static/bootstrap/genius/css/less/wizard.less new file mode 100755 index 0000000..45f3f93 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/less/wizard.less @@ -0,0 +1,138 @@ +/* FuelUX Wizard +=================================================================== */ +.wizard { + + .clearfix; + position: relative; + overflow: hidden; + margin-bottom: 20px; + + ul { + list-style: none outside none; + padding: 0; + margin: 0; + width: 4000px; + + li { + float: left; + margin: 0; + padding: 0 20px 0 30px; + height: 40px; + line-height: 40px; + position: relative; + background: lighten(@grey,25%); + color: @grey; + font-size: 16px; + cursor: default; + + &:first-child { + .border-radius(2px 0 0 2px); + } + + &:last-child { + .border-radius(0 2px 2px 0); + } + + .chevron { + border: 48px solid transparent; + border-left: 28px solid white; + border-right: 0; + display: block; + position: absolute; + right: -14px; + top: -28px; + z-index: 1; + } + + .chevron:before { + border: 48px solid transparent; + border-left: 28px solid lighten(@grey,25%); + border-right: 0; + content: ""; + display: block; + position: absolute; + right: 5px; + top: -48px; + } + + &.complete { + background: @green; + color: white; + + &:hover { + background: #e7eff8; + cursor: pointer; + + .chevron:before { + border-left: 28px solid #e7eff8; + } + } + + .chevron:before { + border-left: 28px solid @green; + } + } + &.active { + background: @grey; + color: white; + + .chevron:before { + border-left: 28px solid @grey; + } + } + .badge { + margin-right: 8px; + } + } + + li:first-child { + border-radius: 4px 0 0 4px; + padding-left: 20px; + } + } + + .actions { + z-index: 1000; + position: absolute; + right: 0; + line-height: 46px; + float: right; + padding-left: 15px; + padding-right: 15px; + vertical-align: middle; + + a { + line-height: 45px; + font-size: 12px; + margin-right: 8px; + } + + .btn-prev { + i { + margin-right: 5px; + } + } + + .btn-next { + i { + margin-left: 5px; + } + } + } +} + +.step-content { + .step-pane { + display: none; + } + + .active { + display: block; + + .btn-group { + .active { + display: inline-block; + } + } + } +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/noty_theme_default.css b/gridplatform/bootstrap/static/bootstrap/genius/css/noty_theme_default.css new file mode 100755 index 0000000..da94e8c --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/noty_theme_default.css @@ -0,0 +1,240 @@ + +/* CORE STYLES*/ + + /* noty bar */ + .noty_bar.noty_theme_default { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAoCAYAAAAPOoFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPZJREFUeNq81tsOgjAMANB2ov7/7ypaN7IlIwi9rGuT8QSc9EIDAsAznxvY4pXPKr05RUE5MEVB+TyWfCEl9LZApYopCmo9C4FKSMtYoI8Bwv79aQJU4l6hXXCZrQbokJEksxHo9KMOgc6w1atHXM8K9DVC7FQnJ0i8iK3QooGgbnyKgMDygBWyYFZoqx4qS27KqLZJjA1D0jK6QJcYEQEiWv9PGkTsbqxQ8oT+ZtZB6AkdsJnQDnMoHXHLGKOgDYuCWmYhEERCI5gaamW0bnHdA3k2ltlIN+2qKRyCND0bhqSYCyTB3CAOc4WusBEIpkeBuPgJMAAX8Hs1NfqHRgAAAABJRU5ErkJggg==') repeat-x scroll left top #fff; + } + + /* if you use noty with customContainer you can access noty with this way + * .noty_custom_container noty will add automaticly this class to your customContainer + * .noty_theme_default your theme + * .noty_layout_inline your layout + */ + + /* custom container */ + .noty_custom_container.noty_theme_default.noty_layout_inline { + position: relative; + } + + /* custom growl container */ + .noty_custom_container.noty_theme_default.noty_layout_inline .noty_cont.noty_layout_inline { + position: static; + } + /* custom noty bar */ + .noty_custom_container.noty_theme_default.noty_layout_inline .noty_bar { + border-width: 1px; + border-style: solid; + position: static; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + } + .noty_custom_container.noty_theme_default.noty_layout_inline .noty_bar .noty_message { + font-size: 13px; + padding: 4px; + } + .noty_custom_container.noty_theme_default.noty_layout_inline .noty_bar .noty_message .noty_buttons { + margin-top: -1px; + } + + /* noty_message */ + .noty_bar.noty_theme_default .noty_message { + padding: 8px 14px; + font-size: 16px; + font-weight: bold; + width: auto; + } + .noty_bar.noty_theme_default.noty_closable .noty_message { + padding: 8px 34px 8px 14px; + } + + /* noty_buttons */ + .noty_bar.noty_theme_default .noty_message .noty_buttons { + float: right; + font-size: 13px; + margin-top: -4px; + margin-left: 4px; + } + + /* noty_button */ + .noty_bar.noty_theme_default .noty_message .noty_buttons button { + margin-left: 5px; + } + + /* noty close button */ + .noty_bar.noty_theme_default .noty_close { + position: absolute; + top: 10px; + right: 10px; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAORJREFUeNq0lU0OgjAQhRm5gUl3rLyBB3BDQjwI4TDcgmu4NqwNJGxdueqWA4zzCJoxtvxoeckLzbz2C5ShEDNHDiXis/gkPooPY/0uvomv4ov48bUSQGUSF+Ka51WPc0kzNGwvLnm9ynHtB5B+hGkoaWDB/6t4AZOFe7ZkTxMAc1dqreU0TbnrunetbVvOsmzIPMoBrFwJYGgCY8wAgjFGDZlHFYCNK9EAXPUYmUcNgL0v1dAFMKjfRSsVx/H0hC0eOfhLmWwbfTcYozbXNsEbO/int8nhEPz4CnbAUuhfwFOAAQAA48KKOuexjwAAAABJRU5ErkJggg=='); + width: 20px; + height: 20px; + } + + /* noty modal */ + .noty_modal.noty_theme_default { + opacity: 0.7; + } + +/* LAYOUTS */ + + /* noty_layout_top */ + .noty_bar.noty_theme_default.noty_layout_top { + border-bottom: 3px solid #eee; + } + + /* noty_layout_bottom */ + .noty_bar.noty_theme_default.noty_layout_bottom { + border-top: 3px solid #eee; + } + + .noty_bar.noty_theme_default.noty_layout_center .noty_close { + top: 8px; + } + + .noty_bar.noty_theme_default.noty_layout_center .noty_message .noty_buttons { + margin-top: -2px + } + + /* noty_layout_topLeft & noty_layout_topRight */ + .noty_bar.noty_theme_default.noty_layout_center, + .noty_bar.noty_theme_default.noty_layout_topLeft, + .noty_bar.noty_theme_default.noty_layout_topRight, + .noty_bar.noty_theme_default.noty_layout_bottomLeft, + .noty_bar.noty_theme_default.noty_layout_bottomRight { + border: 1px solid #eee; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + } + .noty_bar.noty_theme_default.noty_layout_center .noty_message, + .noty_bar.noty_theme_default.noty_layout_topLeft .noty_message, + .noty_bar.noty_theme_default.noty_layout_topRight .noty_message, + .noty_bar.noty_theme_default.noty_layout_bottomLeft .noty_message, + .noty_bar.noty_theme_default.noty_layout_bottomRight .noty_message { + font-size: 13px; + font-weight: normal; + } + .noty_bar.noty_theme_default.noty_layout_topLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_layout_topRight .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_layout_bottomLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_layout_bottomRight .noty_message .noty_buttons { + float: none; + border-top: 1px solid #ccc; + margin-left: 0; + margin-top: 10px; + padding-top: 10px; + text-align: right; + } + + /* noty_layout_topCenter */ + .noty_bar.noty_theme_default.noty_layout_topCenter { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + } + .noty_bar.noty_theme_default.noty_layout_topCenter .noty_message { + font-weight: normal; + font-size: 13px; + } + .noty_bar.noty_theme_default.noty_layout_topCenter .noty_close { + top: 50%; + margin-top: -10px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + } + .noty_bar.noty_theme_default.noty_layout_topCenter.noty_success { + border: 1px solid #50C24E; + } + .noty_bar.noty_theme_default.noty_layout_topCenter .noty_message .noty_buttons { + margin-left: 15px; + margin-top: 0px + } + +/* NOTIFICATION TYPES */ + + /* noty_notification */ + .noty_bar.noty_theme_default.noty_notification { + background-color: #fff; + border-color: #ccc; + color: #555; + } + .noty_bar.noty_theme_default.noty_notification.noty_layout_topLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_notification.noty_layout_topRight .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_notification.noty_layout_bottomLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_notification.noty_layout_bottomRight .noty_message .noty_buttons { + border-color: #ccc; + } + + /* noty_warning */ + .noty_bar.noty_theme_default.noty_warning { + background-color: #FFEAA8; + border-color: #FFC237; + color: #826200; + } + .noty_bar.noty_theme_default.noty_warning.noty_layout_topLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_warning.noty_layout_topRight .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_warning.noty_layout_bottomLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_warning.noty_layout_bottomRight .noty_message .noty_buttons { + border-color: #FFC237; + } + + /* noty_alert */ + .noty_bar.noty_theme_default.noty_alert { + background-color: #fff; + border-color: #ccc; + } + .noty_bar.noty_theme_default.noty_alert.noty_layout_topLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_alert.noty_layout_topRight .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_alert.noty_layout_bottomLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_alert.noty_layout_bottomRight .noty_message .noty_buttons { + border-color: #ccc; + } + + /* noty_error */ + .noty_bar.noty_theme_default.noty_error { + background-color: red; + color: #fff; + border-color: darkred; + } + .noty_bar.noty_theme_default.noty_error .noty_message { + font-weight: bold; + } + .noty_bar.noty_theme_default.noty_error.noty_layout_topLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_error.noty_layout_topRight .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_error.noty_layout_bottomLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_error.noty_layout_bottomRight .noty_message .noty_buttons { + border-color: darkred; + } + + /* noty_success */ + .noty_bar.noty_theme_default.noty_success { + background-color: lightgreen; + color: darkgreen; + border-color: #50C24E; + } + .noty_bar.noty_theme_default.noty_success.noty_layout_topLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_success.noty_layout_topRight .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_success.noty_layout_bottomLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_success.noty_layout_bottomRight .noty_message .noty_buttons { + border-color: #50C24E; + } + + /* noty_information */ + .noty_bar.noty_theme_default.noty_information { + background-color: #57B7E2; + border-color: #0B90C4; + color: #fff; + } + .noty_bar.noty_theme_default.noty_information.noty_layout_topLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_information.noty_layout_topRight .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_information.noty_layout_bottomLeft .noty_message .noty_buttons, + .noty_bar.noty_theme_default.noty_information.noty_layout_bottomRight .noty_message .noty_buttons { + border-color: #0B90C4; + } + \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/print.css b/gridplatform/bootstrap/static/bootstrap/genius/css/print.css new file mode 100644 index 0000000..9c5a69e --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/print.css @@ -0,0 +1,38 @@ +body { + font-size: 12px !important; +} + +body:before, +body:after, +#sidebar-left, +footer, +#content:before, +.btn { + display: none; +} + +#content { + width: 100% !important; +} + +.notice, .recap { + display: inline-block !important; + margin: 0; +} + +.notice { + float: left; + width: 55%; +} + +.recap { + width: 40%; + float: right; + white-space: nowrap; +} + +th { + white-space: nowrap; +} + + diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/retina.css b/gridplatform/bootstrap/static/bootstrap/genius/css/retina.css new file mode 100644 index 0000000..48883fc --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/retina.css @@ -0,0 +1,25 @@ +/* Retina Display Hack +=================================================================== */ +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { + + .timeslot .task .arrow { + background: url(../img/timeline-left-arrow@2x.png) no-repeat; + background-size: 100%; + } + + .timeslot.alt .task .arrow { + background: url(../img/timeline-right-arrow@2x.png) no-repeat; + background-size: 100%; + } + + ul.chat li.left .message .arrow { + background: url(../img/chat-left@2x.png) no-repeat 0px 0px; + background-size: 100%; + } + + ul.chat li.right .message .arrow { + background: url(../img/chat-right@2x.png) no-repeat 0px 0px; + background-size: 100%; + } + +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/retina.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/retina.min.css new file mode 100644 index 0000000..cb52814 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/retina.min.css @@ -0,0 +1 @@ +@media(-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.timeslot .task .arrow{background:url(../img/timeline-left-arrow@2x.png) no-repeat;background-size:100%}.timeslot.alt .task .arrow{background:url(../img/timeline-right-arrow@2x.png) no-repeat;background-size:100%}ul.chat li.left .message .arrow{background:url(../img/chat-left@2x.png) no-repeat 0 0;background-size:100%}ul.chat li.right .message .arrow{background:url(../img/chat-right@2x.png) no-repeat 0 0;background-size:100%}} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/select2.css b/gridplatform/bootstrap/static/bootstrap/genius/css/select2.css new file mode 100755 index 0000000..17dcc05 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/select2.css @@ -0,0 +1,615 @@ +/* +Version: 3.4.3 Timestamp: Tue Sep 17 06:47:14 PDT 2013 +*/ +.select2-container { + margin: 0; + position: relative; + display: inline-block; + /* inline-block for ie7 */ + zoom: 1; + *display: inline; + vertical-align: middle; +} + +.select2-container, +.select2-drop, +.select2-search, +.select2-search input { + /* + Force border-box so that % widths fit the parent + container without overlap because of margin/padding. + + More Info : http://www.quirksmode.org/css/box.html + */ + -webkit-box-sizing: border-box; /* webkit */ + -moz-box-sizing: border-box; /* firefox */ + box-sizing: border-box; /* css3 */ +} + +.select2-container .select2-choice { + display: block; + height: 26px; + padding: 0 0 0 8px; + overflow: hidden; + position: relative; + + border: 1px solid #aaa; + white-space: nowrap; + line-height: 26px; + color: #444; + text-decoration: none; + + border-radius: 4px; + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #fff; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0); + background-image: linear-gradient(top, #fff 0%, #eee 50%); +} + +.select2-container.select2-drop-above .select2-choice { + border-bottom-color: #aaa; + + border-radius: 0 0 4px 4px; + + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); + background-image: linear-gradient(top, #eee 0%, #fff 90%); +} + +.select2-container.select2-allowclear .select2-choice .select2-chosen { + margin-right: 42px; +} + +.select2-container .select2-choice > .select2-chosen { + margin-right: 26px; + display: block; + overflow: hidden; + + white-space: nowrap; + + text-overflow: ellipsis; +} + +.select2-container .select2-choice abbr { + display: none; + width: 12px; + height: 12px; + position: absolute; + right: 24px; + top: 8px; + + font-size: 1px; + text-decoration: none; + + border: 0; + background: url('../img/select2.png') right top no-repeat; + cursor: pointer; + outline: 0; +} + +.select2-container.select2-allowclear .select2-choice abbr { + display: inline-block; +} + +.select2-container .select2-choice abbr:hover { + background-position: right -11px; + cursor: pointer; +} + +.select2-drop-mask { + border: 0; + margin: 0; + padding: 0; + position: fixed; + left: 0; + top: 0; + min-height: 100%; + min-width: 100%; + height: auto; + width: auto; + opacity: 0; + z-index: 9998; + /* styles required for IE to work */ + background-color: #fff; + filter: alpha(opacity=0); +} + +.select2-drop { + width: 100%; + margin-top: -1px; + position: absolute; + z-index: 9999; + top: 100%; + + background: #fff; + color: #000; + border: 1px solid #aaa; + border-top: 0; + + border-radius: 0 0 4px 4px; + + -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop-auto-width { + border-top: 1px solid #aaa; + width: auto; +} + +.select2-drop-auto-width .select2-search { + padding-top: 4px; +} + +.select2-drop.select2-drop-above { + margin-top: 1px; + border-top: 1px solid #aaa; + border-bottom: 0; + + border-radius: 4px 4px 0 0; + + -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop-active { + border: 1px solid #5897fb; + border-top: none; +} + +.select2-drop.select2-drop-above.select2-drop-active { + border-top: 1px solid #5897fb; +} + +.select2-container .select2-choice .select2-arrow { + display: inline-block; + width: 18px; + height: 100%; + position: absolute; + right: 0; + top: 0; + + border-left: 1px solid #aaa; + border-radius: 0 4px 4px 0; + + background-clip: padding-box; + + background: #ccc; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); + background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0); + background-image: linear-gradient(top, #ccc 0%, #eee 60%); +} + +.select2-container .select2-choice .select2-arrow b { + display: block; + width: 100%; + height: 100%; + background: url('../img/select2.png') no-repeat 0 1px; +} + +.select2-search { + display: inline-block; + width: 100%; + min-height: 26px; + margin: 0; + padding-left: 4px; + padding-right: 4px; + + position: relative; + z-index: 10000; + + white-space: nowrap; +} + +.select2-search input { + width: 100%; + height: auto !important; + min-height: 26px; + padding: 4px 20px 4px 5px; + margin: 0; + + outline: 0; + font-family: sans-serif; + font-size: 1em; + + border: 1px solid #aaa; + border-radius: 0; + + -webkit-box-shadow: none; + box-shadow: none; + + background: #fff url('../img/select2.png') no-repeat 100% -22px; + background: url('../img/select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('../img/select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat 100% -22px, linear-gradient(top, #fff 85%, #eee 99%); +} + +.select2-drop.select2-drop-above .select2-search input { + margin-top: 4px; +} + +.select2-search input.select2-active { + background: #fff url('../img/select2-spinner.gif') no-repeat 100%; + background: url('../img/select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('../img/select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2-spinner.gif') no-repeat 100%, linear-gradient(top, #fff 85%, #eee 99%); +} + +.select2-container-active .select2-choice, +.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} + +.select2-dropdown-open .select2-choice { + border-bottom-color: transparent; + -webkit-box-shadow: 0 1px 0 #fff inset; + box-shadow: 0 1px 0 #fff inset; + + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + + background-color: #eee; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(top, #fff 0%, #eee 50%); +} + +.select2-dropdown-open.select2-drop-above .select2-choice, +.select2-dropdown-open.select2-drop-above .select2-choices { + border: 1px solid #5897fb; + border-top-color: transparent; + + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(bottom, #fff 0%, #eee 50%); +} + +.select2-dropdown-open .select2-choice .select2-arrow { + background: transparent; + border-left: none; + filter: none; +} +.select2-dropdown-open .select2-choice .select2-arrow b { + background-position: -18px 1px; +} + +/* results */ +.select2-results { + max-height: 200px; + padding: 0 0 0 4px; + margin: 4px 4px 4px 0; + position: relative; + overflow-x: hidden; + overflow-y: auto; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.select2-results ul.select2-result-sub { + margin: 0; + padding-left: 0; +} + +.select2-results ul.select2-result-sub > li .select2-result-label { padding-left: 20px } +.select2-results ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 40px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 60px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 80px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 100px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 110px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 120px } + +.select2-results li { + list-style: none; + display: list-item; + background-image: none; +} + +.select2-results li.select2-result-with-children > .select2-result-label { + font-weight: bold; +} + +.select2-results .select2-result-label { + padding: 3px 7px 4px; + margin: 0; + cursor: pointer; + + min-height: 1em; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select2-results .select2-highlighted { + background: #3875d7; + color: #fff; +} + +.select2-results li em { + background: #feffde; + font-style: normal; +} + +.select2-results .select2-highlighted em { + background: transparent; +} + +.select2-results .select2-highlighted ul { + background: #fff; + color: #000; +} + + +.select2-results .select2-no-results, +.select2-results .select2-searching, +.select2-results .select2-selection-limit { + background: #f4f4f4; + display: list-item; +} + +/* +disabled look for disabled choices in the results dropdown +*/ +.select2-results .select2-disabled.select2-highlighted { + color: #666; + background: #f4f4f4; + display: list-item; + cursor: default; +} +.select2-results .select2-disabled { + background: #f4f4f4; + display: list-item; + cursor: default; +} + +.select2-results .select2-selected { + display: none; +} + +.select2-more-results.select2-active { + background: #f4f4f4 url('../img/select2-spinner.gif') no-repeat 100%; +} + +.select2-more-results { + background: #f4f4f4; + display: list-item; +} + +/* disabled styles */ + +.select2-container.select2-container-disabled .select2-choice { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container.select2-container-disabled .select2-choice .select2-arrow { + background-color: #f4f4f4; + background-image: none; + border-left: 0; +} + +.select2-container.select2-container-disabled .select2-choice abbr { + display: none; +} + + +/* multiselect */ + +.select2-container-multi .select2-choices { + height: auto !important; + height: 1%; + margin: 0; + padding: 0; + position: relative; + + border: 1px solid #aaa; + cursor: text; + overflow: hidden; + + background-color: #fff; + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff)); + background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%); + background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%); + background-image: linear-gradient(top, #eee 1%, #fff 15%); +} + +.select2-locked { + padding: 3px 5px 3px 5px !important; +} + +.select2-container-multi .select2-choices { + min-height: 26px; +} + +.select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} +.select2-container-multi .select2-choices li { + float: left; + list-style: none; +} +.select2-container-multi .select2-choices .select2-search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} + +.select2-container-multi .select2-choices .select2-search-field input { + padding: 5px; + margin: 1px 0; + + font-family: sans-serif; + font-size: 100%; + color: #666; + outline: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + background: transparent !important; +} + +.select2-container-multi .select2-choices .select2-search-field input.select2-active { + background: #fff url('../img/select2-spinner.gif') no-repeat 100% !important; +} + +.select2-default { + color: #999 !important; +} + +.select2-container-multi .select2-choices .select2-search-choice { + padding: 3px 5px 3px 18px; + margin: 3px 0 3px 5px; + position: relative; + + line-height: 13px; + color: #333; + cursor: default; + border: 1px solid #aaaaaa; + + border-radius: 3px; + + -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #e4e4e4; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); +} +.select2-container-multi .select2-choices .select2-search-choice .select2-chosen { + cursor: default; +} +.select2-container-multi .select2-choices .select2-search-choice-focus { + background: #d4d4d4; +} + +.select2-search-choice-close { + display: block; + width: 12px; + height: 13px; + position: absolute; + right: 3px; + top: 4px; + + font-size: 1px; + outline: none; + background: url('../img/select2.png') right top no-repeat; +} + +.select2-container-multi .select2-search-choice-close { + left: 3px; +} + +.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { + background-position: right -11px; +} +.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { + background-position: right -11px; +} + +/* disabled styles */ +.select2-container-multi.select2-container-disabled .select2-choices { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice { + padding: 3px 5px 3px 5px; + border: 1px solid #ddd; + background-image: none; + background-color: #f4f4f4; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none; + background: none; +} +/* end multiselect */ + + +.select2-result-selectable .select2-match, +.select2-result-unselectable .select2-match { + text-decoration: underline; +} + +.select2-offscreen, .select2-offscreen:focus { + clip: rect(0 0 0 0) !important; + width: 1px !important; + height: 1px !important; + border: 0 !important; + margin: 0 !important; + padding: 0 !important; + overflow: hidden !important; + position: absolute !important; + outline: 0 !important; + left: 0px !important; + top: 0px !important; +} + +.select2-display-none { + display: none; +} + +.select2-measure-scrollbar { + position: absolute; + top: -10000px; + left: -10000px; + width: 100px; + height: 100px; + overflow: scroll; +} +/* Retina-ize icons */ + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) { + .select2-search input, .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice .select2-arrow b { + background-image: url('../img/select2x2.png') !important; + background-repeat: no-repeat !important; + background-size: 60px 40px !important; + } + .select2-search input { + background-position: 100% -21px !important; + } +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/social.css b/gridplatform/bootstrap/static/bootstrap/genius/css/social.css new file mode 100644 index 0000000..8aa0175 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/social.css @@ -0,0 +1,357 @@ +/*! + * + * Project: GLYPHICONS HALFLINGS + * Author: Jan Kovarik - www.glyphicons.com + * Twitter: @glyphicons + * + */ +@font-face { + font-family: 'Glyphicons Social Regular'; + src: url('../fonts/glyphicons-social-regular.eot'); + src: url('../fonts/glyphicons-social-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-social-regular.woff') format('woff'), url('../fonts/glyphicons-social-regular.ttf') format('truetype'), url('../fonts/glyphicons-social-regular.svg#glyphicons_socialregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.social { + display: inline-block; + position: relative; + padding-left: 30px; + color: #1d1d1b; + text-decoration: none; + *display: inline; + *zoom: 1; + vertical-align: middle; +} +.social:before { + position: absolute; + left: 0; + top: 0; + display: inline-block; + margin: 0 5px 0 0; + font: 24px/1em 'Glyphicons Social Regular'; + font-style: normal; + font-weight: normal; + color: #1d1d1b; + *display: inline; + *zoom: 1; + vertical-align: middle; + text-transform: none; + -webkit-font-smoothing: antialiased; +} +.social.white:before { + color: #fff; +} +.social.pinterest:before { + content: "\E001"; +} +.social.dropbox:before { + content: "\E002"; +} +.social.google_plus:before { + content: "\E003"; +} +.social.jolicloud:before { + content: "\E004"; +} +.social.yahoo:before { + content: "\E005"; +} +.social.blogger:before { + content: "\E006"; +} +.social.picasa:before { + content: "\E007"; +} +.social.amazon:before { + content: "\E008"; +} +.social.tumblr:before { + content: "\E009"; +} +.social.wordpress:before { + content: "\E010"; +} +.social.instapaper:before { + content: "\E011"; +} +.social.evernote:before { + content: "\E012"; +} +.social.xing:before { + content: "\E013"; +} +.social.zootool:before { + content: "\E014"; +} +.social.dribbble:before { + content: "\E015"; +} +.social.deviantart:before { + content: "\E016"; +} +.social.read_it_later:before { + content: "\E017"; +} +.social.linked_in:before { + content: "\E018"; +} +.social.forrst:before { + content: "\E019"; +} +.social.pinboard:before { + content: "\E020"; +} +.social.behance:before { + content: "\E021"; +} +.social.github:before { + content: "\E022"; +} +.social.youtube:before { + content: "\E023"; +} +.social.skitch:before { + content: "\E024"; +} +.social.foursquare:before { + content: "\E025"; +} +.social.quora:before { + content: "\E026"; +} +.social.badoo:before { + content: "\E027"; +} +.social.spotify:before { + content: "\E028"; +} +.social.stumbleupon:before { + content: "\E029"; +} +.social.readability:before { + content: "\E030"; +} +.social.facebook:before { + content: "\E031"; +} +.social.twitter:before { + content: "\E032"; +} +.social.instagram:before { + content: "\E033"; +} +.social.posterous_spaces:before { + content: "\E034"; +} +.social.vimeo:before { + content: "\E035"; +} +.social.flickr:before { + content: "\E036"; +} +.social.last_fm:before { + content: "\E037"; +} +.social.rss:before { + content: "\E038"; +} +.social.skype:before { + content: "\E039"; +} +.social.e-mail:before { + content: "\E040"; +} +.social.vine:before { + content: "\E041"; +} +.social.myspace:before { + content: "\E042"; +} +.social.goodreads:before { + content: "\E043"; +} +.social.apple:before { + content: "\F8FF"; +} +.social.windows:before { + content: "\E045"; +} +.social.yelp:before { + content: "\E046"; +} +.social.playstation:before { + content: "\E047"; +} +.social.xbox:before { + content: "\E048"; +} +.social.android:before { + content: "\E049"; +} +.social.ios:before { + content: "\E050"; +} +.social-icon { + display: inline-block; + width: 24px; + height: 24px; + margin: 0 8px 0 0; + line-height: 14px; + vertical-align: text-top; + background-position: 0 0; + background-repeat: no-repeat; + vertical-align: top; + *display: inline; + *zoom: 1; + *margin-right: .3em; +} +.social-icon.pinterest { + background-position: 0px 0px; +} +.social-icon.dropbox { + background-position: -48px 0px; +} +.social-icon.google_plus { + background-position: -96px 0px; +} +.social-icon.jolicloud { + background-position: -144px 0px; +} +.social-icon.yahoo { + background-position: -192px 0px; +} +.social-icon.blogger { + background-position: -240px 0px; +} +.social-icon.picasa { + background-position: -288px 0px; +} +.social-icon.amazon { + background-position: -336px 0px; +} +.social-icon.tumblr { + background-position: -384px 0px; +} +.social-icon.wordpress { + background-position: -432px 0px; +} +.social-icon.instapaper { + background-position: 0px -48px; +} +.social-icon.evernote { + background-position: -48px -48px; +} +.social-icon.xing { + background-position: -96px -48px; +} +.social-icon.zootool { + background-position: -144px -48px; +} +.social-icon.dribbble { + background-position: -192px -48px; +} +.social-icon.deviantart { + background-position: -240px -48px; +} +.social-icon.read_it_later { + background-position: -288px -48px; +} +.social-icon.linked_in { + background-position: -336px -48px; +} +.social-icon.forrst { + background-position: -384px -48px; +} +.social-icon.pinboard { + background-position: -432px -48px; +} +.social-icon.behance { + background-position: 0px -96px; +} +.social-icon.github { + background-position: -48px -96px; +} +.social-icon.youtube { + background-position: -96px -96px; +} +.social-icon.skitch { + background-position: -144px -96px; +} +.social-icon.foursquare { + background-position: -192px -96px; +} +.social-icon.quora { + background-position: -240px -96px; +} +.social-icon.badoo { + background-position: -288px -96px; +} +.social-icon.spotify { + background-position: -336px -96px; +} +.social-icon.stumbleupon { + background-position: -384px -96px; +} +.social-icon.readability { + background-position: -432px -96px; +} +.social-icon.facebook { + background-position: 0px -144px; +} +.social-icon.twitter { + background-position: -48px -144px; +} +.social-icon.instagram { + background-position: -96px -144px; +} +.social-icon.posterous_spaces { + background-position: -144px -144px; +} +.social-icon.vimeo { + background-position: -192px -144px; +} +.social-icon.flickr { + background-position: -240px -144px; +} +.social-icon.last_fm { + background-position: -288px -144px; +} +.social-icon.rss { + background-position: -336px -144px; +} +.social-icon.skype { + background-position: -384px -144px; +} +.social-icon.e-mail { + background-position: -432px -144px; +} +.social-icon.vine { + background-position: 0px -192px; +} +.social-icon.myspace { + background-position: -48px -192px; +} +.social-icon.goodreads { + background-position: -96px -192px; +} +.social-icon.apple { + background-position: -144px -192px; +} +.social-icon.windows { + background-position: -192px -192px; +} +.social-icon.yelp { + background-position: -240px -192px; +} +.social-icon.playstation { + background-position: -288px -192px; +} +.social-icon.xbox { + background-position: -336px -192px; +} +.social-icon.android { + background-position: -384px -192px; +} +.social-icon.ios { + background-position: -432px -192px; +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/style.css b/gridplatform/bootstrap/static/bootstrap/genius/css/style.css new file mode 100644 index 0000000..049c8b5 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/style.css @@ -0,0 +1,6124 @@ +/*! +* Author: Łukasz Holeczek +* Template: Genius Dashboard - Bootstrap Admin Template +* Version: 1.0.3 +* Bootstrap version: 3.0.3 +* Copyright 2014 creativeLabs +* www: http://bootstrapmaster.com +* mail: lukasz@bootstrapmaster.com +* You can buy this theme on WrapBootstrap: https://wrapbootstrap.com/theme/genius-bootstrap-admin-template-WB0JM6RMD +* You can find our other themes on: https://bootstrapmaster.com +*/ + +@import "jquery-ui-1.10.3.custom.css"; +@import "fullcalendar.css"; +@import "chosen.css"; +@import "select2.css"; +@import "jquery.cleditor.css"; +@import "jquery.noty.css"; +@import "noty_theme_default.css"; +@import "elfinder.min.css"; +@import "elfinder.theme.css"; +@import "uploadify.css"; +@import "jquery.gritter.css"; +@import "font-awesome.min.css"; +@import "font-awesome-ie7.min.css"; +@import "glyphicons.css"; +@import "halflings.css"; +@import "dropzone.css"; +@import "filetypes.css"; +@import "social.css"; +@import "xcharts.min.css"; +@import "jquery.easy-pie-chart.css"; +@import "icheck/all.css"; +@import "bootstrap-editable.css"; +@import url(https://fonts.googleapis.com/css?family=Lato:300); +@import url(https://fonts.googleapis.com/css?family=Lato:400); +@import url(https://fonts.googleapis.com/css?family=Kaushan+Script); + +/* Basic +=================================================================== */ +.no-space [class*="span"] { + margin-left: 0; +} +.noMarginLeft { + margin-left: 0px !important; +} +.noPadding { + padding: 0px !important; +} +body { + background: #e9ebec; + color: #34383c; + border: none; + font-family: 'Lato', sans-serif; + font-weight: 400; + margin: 0; + padding: 0; + position: relative; +} +body:after { + top: 0; + left: 14.422%; + margin-left: -1px; + position: absolute; + content: ''; + height: 100%; + width: 85.578%; + background: #f3f3f3; + border-left: 1px solid #dbdee0; + z-index: 0; +} +body:before { + content: ''; + position: absolute; + background: #f3f3f3; + width: 50%; + height: 100%; + top: 0; + right: 0; + z-index: 0; +} +body.sidebar-minified:after { + top: 0; + left: 40px !important; + margin-left: -1px; + margin-right: 40px; + position: absolute; + content: ''; + height: 100%; + background: #f3f3f3; + border-left: 1px solid #dbdee0; + z-index: 0; +} +a { + color: #34383c; +} +h1 { + font-size: 32px; + line-height: 32px; + font-weight: 300; +} +h2 { + font-size: 16px; + line-height: 16px; + font-weight: 300; +} +h3 { + font-size: 15px; + line-height: 15px; +} +h4 { + font-size: 14px; + line-height: 14px; +} +h5 { + font-size: 13px; + line-height: 13px; +} +h6 { + font-size: 12px; + line-height: 12px; +} +#content { + padding: 20px; + position: relative; + background: #f3f3f3; + z-index: 1; +} +#content:before { + position: absolute; + content: ''; + height: 100%; + width: 1px; + border-left: 1px solid #dbdee0; + z-index: 1; + top: 0px; + left: -1px; +} +#content.sidebar-minified { + width: 100% !important; + border-left: 40px solid #e9ebec; + margin-right: 1px !important; +} +#content.full { + width: 100% !important; + margin-left: 0px !important; + margin-right: 0px !important; + border: none !important; +} +.well { + border: 1px solid #ddd; + background-color: #f6f6f6; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.breadcrumb { + background: #e9ebec; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + height: 40px; + position: relative; + border-bottom: 1px solid #dbdee0; +} +.breadcrumb .choose-date { + position: absolute; + top: 0px; + right: 0px; + height: 40px; + width: 254px; + border: none; + border-left: 1px solid #dbdee0; + padding: 3px 10px; +} +.breadcrumb .choose-date .input-group-addon, +.breadcrumb .choose-date input { + background: transparent; + border: none; +} +.breadcrumb .choose-date .input-group-addon { + font-size: 12px; +} +.breadcrumb .choose-date input { + padding: 0; + font-weight: 300; +} +.breadcrumb .choose-date input:focus { + outline: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.box { + border: 1px solid #dbdee0; + margin: 0px 0px 30px 0px; +} +.box.noOverflow { + overflow: hidden; +} +.box .box-header { + background: white; + color: #34383c; + font-size: 16px; + overflow: hidden; + background: #f7f7f8; + border-bottom: 1px solid #dbdee0; + height: 40px; +} +.box .box-header h2 { + float: left; + padding: 10px 0px; + margin: 0px 0px 0px 20px; +} +.box .box-header h2 i { + border-right: 1px solid #dbdee0; + color: #ced1d4; + padding: 12px 0px; + height: 40px; + width: 40px; + display: inline-block; + text-align: center; + margin: -10px 20px -10px -20px; + font-size: 16px; +} +.box .box-header .box-icon { + float: right; +} +.box .box-header .box-icon i { + display: inline-block; + color: #ced1d4; + text-align: center; + height: 40px; + width: 40px; + padding: 12px 0px; + -webkit-transition: all 0.1s ease-in-out; + -moz-transition: all 0.1s ease-in-out; + -ms-transition: all 0.1s ease-in-out; + -o-transition: all 0.1s ease-in-out; + transition: all 0.1s ease-in-out; + border-left: 1px solid #ced1d4; + text-decoration: none; +} +.box .box-header .box-icon a { + margin-left: -3px !important; +} +.box .box-content { + padding: 10px; + background: white; +} +.box .box-content.no-padding { + background: white; + padding: 1px 0; +} +/* Typography - Blockquote +=================================================================== */blockquote { + background: url(../img/quote.png) no-repeat 0px 10px; + font-style: italic; + border-left: none; + padding: 0 0 0 30px; +} +/* Alerts +=================================================================== */ +.alert { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +/* Main Colors +=================================================================== */ +.blue { + color: #36a9e1; +} +.lightBlue { + color: #67c2ef; +} +.green { + color: #bdea74; +} +.darkGreen { + color: #78cd51; +} +.pink { + color: #e84c8a; +} +.orange { + color: #fa603d; +} +.lightOrange { + color: #fabb3d; +} +.red { + color: #ff5454; +} +.yellow { + color: #eae874; +} +.white { + color: white; +} +.grey { + color: #b2b8bd; +} +.backgroundColor.blue { + background: #36a9e1; +} +.backgroundColor.lightBlue { + background: #67c2ef; +} +.backgroundColor.green { + background: #bdea74; +} +.backgroundColor.darkGreen { + background: #78cd51; +} +.backgroundColor.pink { + background: #e84c8a; +} +.backgroundColor.orange { + background: #fa603d; +} +.backgroundColor.lightOrange { + background: #fabb3d; +} +.backgroundColor.red { + background: #ff5454; +} +.backgroundColor.yellow { + background: #eae874; +} +.backgroundColor.white { + background: white; +} +.backgroundColor.grey { + background: #b2b8bd; +} +.backgroundColorTitle.blue .title { + background: #36a9e1; +} +.backgroundColorTitle.lightBlue .title { + background: #67c2ef; +} +.backgroundColorTitle.green .title { + background: #bdea74; +} +.backgroundColorTitle.darkGreen .title { + background: #78cd51; +} +.backgroundColorTitle.pink .title { + background: #e84c8a; +} +.backgroundColorTitle.orange .title { + background: #fa603d; +} +.backgroundColorTitle.lightOrange .title { + background: #fabb3d; +} +.backgroundColorTitle.red .title { + background: #ff5454; +} +.backgroundColorTitle.yellow .title { + background: #eae874; +} +.backgroundColorTitle.white .title { + background: white; +} +.backgroundColorTitle.grey .title { + background: #b2b8bd; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, +.clearfix:after { + display: table; + content: ""; + line-height: 0; +} +.clearfix:after { + clear: both; +} +/* Header Section +=================================================================== */ +.navbar { + margin: 0; + min-height: 40px; + border: none; + background: #34383c; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + z-index: 2; +} +.navbar a { + color: #7b7b7b; +} +.navbar a i { + margin-top: 2px; +} +.navbar a:hover i { + opacity: .8; + filter: alpha(opacity=80); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; +} +.navbar #search { + position: relative; + background: #282b2e; + height: 30px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + margin: 5px 0 5px 16%; +} +.navbar #search select { + margin: 4px 0 0 -11px; + height: 22px; + line-height: 22px; + background: #585e65; + border: none; + color: white; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + text-align: center; + text-align: -moz-center; + text-align: -webkit-center; + text-align: -khtml-center; + font-size: 12px; + cursor: pointer; + width: 30%; + -webkit-appearance: none; + -moz-appearance: none; + text-indent: 0.01px; + text-overflow: ''; + padding: 2px 0px; +} +@media screen and (-webkit-min-device-pixel-ratio: 0) { + .navbar #search select { + padding: 0px 15px; + } +} +.navbar #search input { + margin-left: 5px; + width: 70%; + background: transparent; + border: none; + font-size: 12px; + color: white; +} +.navbar #search i { + position: absolute; + top: 8px; + right: 10px; + color: white; +} +a.navbar-brand { + background: #282b2e; + text-align: center; + padding: 9px 0 10px 0 !important; +} +a.navbar-brand span { + font-family: 'Kaushan Script', cursive; + color: #fff; + text-shadow: none; +} +a.navbar-brand.noBg { + background: #34383c; + border-bottom: none; +} +a.navbar-brand:hover { + background: #282b2e; +} +.header-nav { + position: relative; + padding: 0px; + color: #fff !important; + background: #000 !important; +} +.header-nav .btn { + display: inline-block; + margin: 0px; + font-size: 15px; + text-align: center; + background: transparent; + border: none; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.header-nav a.btn { + position: relative; + height: 30px; + width: 40px; + background: #40454a; + color: #fff !important; + text-shadow: none !important; + padding: 5px 0 !important; + margin: 5px 3px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + font-size: 12px; +} +.header-nav a.btn .number { + position: absolute; + font-size: 8px; + top: -3px; + right: 3px; +} +.header-nav a.btn.account { + background: transparent; + height: 40px; + width: auto; + padding: 8px 0px 5px 10px !important; + margin: 0 -15px 0 3px; +} +.header-nav a.btn.account .avatar { + width: 60px; + float: right; +} +.header-nav a.btn.account .avatar img { + margin: -13px -10px -14px 10px; + height: 40px; + width: 40px; +} +.header-nav a.btn:hover { + background: #282b2e; +} +.header-nav .user { + display: inline-block; + text-align: left; + margin-top: -5px; + padding: 0px; +} +.header-nav .user .hello { + display: block; + font-size: 11px; + font-weight: bold; +} +.header-nav .user .name { + display: block; + margin-top: -6px !important; + font-size: 13px; +} +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: white; + background-color: #282b2e; + outline: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.dropdown-menu:after, +.dropdown-menu:before { + display: none !important; +} +.dropdown-menu { + position: absolute; + top: 90%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 166px; + max-width: 300px; + padding: 0px; + margin: 0; + list-style: none; + text-shadow: none; + background: white; + border: 1px solid #dbdee0; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + margin: 0px 1px; +} +.dropdown-menu li a { + display: block; + padding: 5px 10px !important; + clear: both; + font-weight: normal; + line-height: 20px; + color: #34383c; + white-space: normal !important; +} +.dropdown-menu li { + border-bottom: 1px solid #e9ebec; +} +.dropdown-menu li:last-child { + border-bottom: 0px !important; +} +.dropdown-menu li > a:hover, +.dropdown-menu li > a:focus, +.dropdown-submenu:hover > a { + color: #ffffff; + text-decoration: none; + background: #62bce8; +} +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0077b3; + background-image: -webkit-gradient(linear, left top, left bottom, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: -ms-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(top, #0088cc, #0077b3); +} +.dropdown-menu .disabled > a, +.dropdown-menu .disabled > a:hover { + color: #999999; +} +.dropdown-menu .disabled > a:hover { + text-decoration: none; + cursor: default; + background-color: transparent; +} +.dropdown-menu-title { + background: #e9ebec; + color: #34383c; + padding: 5px 10px; + display: block; +} +.dropdown-menu-sub-footer { + text-align: center; + background: #e9ebec; + cursor: pointer; +} +.dropdown-menu ul, +.dropdown-menu ul li { + padding: 0px !important; + margin: 0px !important; +} +ul.notifications li, +ul.tasks li, +ul.messages li { + min-width: 260px; +} +ul.notifications li .avatar img, +ul.tasks li .avatar img, +ul.messages li .avatar img { + float: left !important; + height: 40px; + width: 40px; + margin-top: 5px; + margin-right: 10px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +ul.messages li .header { + display: block; +} +ul.messages li .header .from { + font-size: 12px; + font-weight: bold; +} +ul.notifications li .icon { + margin: -5px 10px -5px -10px !important; + padding: 7px 10px 9px 10px; + color: white; + width: 40px; + display: inline-block; + text-align: center; +} +ul.notifications li .icon.blue { + background: #36a9e1; +} +ul.notifications li .icon.lightBlue { + background: #67c2ef; +} +ul.notifications li .icon.green { + background: #bdea74; +} +ul.notifications li .icon.darkGreen { + background: #78cd51; +} +ul.notifications li .icon.pink { + background: #e84c8a; +} +ul.notifications li .icon.orange { + background: #fa603d; +} +ul.notifications li .icon.lightOrange { + background: #fabb3d; +} +ul.notifications li .icon.red { + background: #ff5454; +} +ul.notifications li .icon.yellow { + background: #eae874; +} +ul.notifications li .icon.white { + background: white; +} +ul.notifications li .icon.grey { + background: #b2b8bd; +} +ul.notifications li .time, +ul.tasks li .header .percent, +ul.messages li .header .time { + font-size: 11px; + font-weight: bold; + font-style: italic; + position: absolute; + right: 5px; +} +ul.tasks li .title, +ul.notifications li .message { + font-size: 12px; +} +ul.notifications li.warning a { + color: #fa603d; +} +ul.messages li .message { + font-size: 11px; +} +/* Navigation Section +=================================================================== */ +a#main-menu-toggle { + background: #1c1e21; + width: 40px; + height: 40px; + color: white; + position: absolute; + z-index: 1000; + top: 0px; + left: 0; + padding: 8px 13px; + font-size: 16px; + text-shadow: none; + text-decoration: none; + cursor: pointer; +} +a#main-menu-toggle.close { + opacity: 1; + background: #282b2e !important; + padding: 10px 13px !important; +} +a#main-menu-min { + display: block; + border-bottom: 1px solid #dbdee0; + width: 100%; + margin: 30px 0; + position: relative; + text-decoration: none; +} +a#main-menu-min i { + position: absolute; + bottom: -10px; + left: 50%; + margin-left: -10px; + width: 20px; + height: 20px; + background: #dbdee0; + font-size: 14px; + padding: 3px 0px; + color: #7c848d; + text-align: center; +} +a#main-menu-min i:hover { + background: #ced1d4; + color: #6f7880; +} +#sidebar-left { + padding: 10px !important; + z-index: 2; +} +.sidebar-nav > ul { + margin: -9px -25px; + border: none; + padding-bottom: 1px; + font-size: 14px; + white-space: nowrap; +} +.sidebar-nav > ul > li > ul, +.sidebar-nav > ul > li > ul > li > ul, +.sidebar-nav > ul > li > ul > li > ul > li > ul { + list-style: none; + display: none; + margin: 0; + padding: 0; +} +.nav.main-menu > li { + margin-top: -1px; +} +.nav.main-menu > li > a, +.nav.main-menu > li > ul > li > a, +.nav.main-menu > li > ul > li > ul > li > a, +.nav.main-menu > li > ul > li > ul > li > ul > li > a { + margin: 0px; + height: 40px; + padding: 1px 0 0 0; + color: #7c848d; + border: none; + border-bottom: 1px solid #dbdee0; + background: transparent; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + text-decoration: none; + display: block; + position: relative; +} +.nav.main-menu > li > a .chevron, +.nav.main-menu > li > ul > li > a .chevron, +.nav.main-menu > li > ul > li > ul > li > a .chevron, +.nav.main-menu > li > ul > li > ul > li > ul > li > a .chevron { + font-family: 'FontAwesome'; + position: absolute; + top: 2px; + right: -5px; + height: 40px; + width: 40px; + padding: 12px 0px; + display: inline-block; + text-align: center; + font-size: 10px; + color: #b2b8bd !important; +} +.nav.main-menu > li > a .chevron.opened:after, +.nav.main-menu > li > ul > li > a .chevron.opened:after, +.nav.main-menu > li > ul > li > ul > li > a .chevron.opened:after, +.nav.main-menu > li > ul > li > ul > li > ul > li > a .chevron.opened:after { + height: 100%; + width: 100%; + content: "\f078"; + text-shadow: none; +} +.nav.main-menu > li > a .chevron.closed:after, +.nav.main-menu > li > ul > li > a .chevron.closed:after, +.nav.main-menu > li > ul > li > ul > li > a .chevron.closed:after, +.nav.main-menu > li > ul > li > ul > li > ul > li > a .chevron.closed:after { + height: 100%; + width: 100%; + content: "\f053"; + text-shadow: none; + color: #b2b8bd !important; +} +.nav.main-menu > li > a > i, +.nav.main-menu > li > ul > li > a > i { + margin-right: 10px; + height: 38px; + width: 40px; + padding: 13px 0px; + display: inline-block; + text-align: center; + border-right: 1px solid #dbdee0; +} +.nav.main-menu > li > ul > li > a > i, +.nav.main-menu > li > ul > li > ul > li > a > i, +.nav.main-menu > li > ul > li > ul > li > ul > li > a > i { + margin-right: 10px; + height: 38px; + width: 40px; + padding: 13px 0px; + display: inline-block; + text-align: center; + font-size: 13px; + border-right: 1px solid #dbdee0; +} +.nav.main-menu > li > ul > li > a { + background: #e4e5e7; +} +.nav.main-menu > li > ul > li > ul > li > a { + background: #e1e3e5; +} +.nav.main-menu > li > ul > li > ul > li > ul > li > a { + background: #dee0e2; +} +.nav.main-menu > li > a:hover, +.nav.main-menu > li > ul > li > a:hover, +.nav.main-menu > li > ul > li > ul > li > a:hover, +.nav.main-menu > li > ul > li > ul > li > ul > li > a:hover { + background: #ced1d4; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; +} +.nav.main-menu > li > a:hover > i, +.nav.main-menu > li > ul > li > a:hover > i, +.nav.main-menu > li > ul > li > ul > li > a:hover > i, +.nav.main-menu > li > ul > li > ul > li > ul > li > a:hover > i { + border-right: 1px solid #c8ccd0; +} +.nav.main-menu > li > a:hover, +.nav.main-menu > li > ul > li > a:hover { + background: #ced1d4; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; +} +.nav.main-menu > li.active > a, +.nav.main-menu > li > ul > li.active > a, +.nav.main-menu > li > ul > li > ul > li.active > a, +.nav.main-menu > li > ul > li > ul > li > ul > li.active > a { + background: #ced1d4; +} +.nav.main-menu > li.active > a > i, +.nav.main-menu > li > ul > li.active > a > i, +.nav.main-menu > li > ul > li > ul > li.active > a > i, +.nav.main-menu > li > ul > li > ul > li > ul > li.active > a > i { + border-right: 1px solid #c8ccd0; +} +.nav.main-menu > li.active > a:hover, +.nav.main-menu > li > ul > li.active > a:hover { + border: none; + color: white; +} +.nav.main-menu > li.active > ul { + padding: 5px 0px; + background: #dbdee0; +} +.nav.main-menu > li:first-child > a { + margin: 0px; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; +} +.nav.main-menu > li:last-child > a { + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; +} +#sidebar-left.minified { + width: 40px !important; + margin-right: -40px; +} +#sidebar-left.minified .sidebar-nav > ul > li { + position: relative; +} +#sidebar-left.minified .sidebar-nav > ul > li > a { + width: 40px; + position: relative; +} +#sidebar-left.minified .sidebar-nav > ul > li > a.open { + cursor: default; +} +#sidebar-left.minified .sidebar-nav > ul > li > a .chevron { + display: none; + position: absolute; + left: 178px; + z-index: 1000; +} +#sidebar-left.minified .sidebar-nav > ul > li > a .text { + position: absolute; + z-index: 1000; + background: #e9ebec; + min-height: 40px; + width: 150px; + padding: 8px 15px; + border: 1px solid #dbdee0; + top: 0px; + left: 39px; + display: none !important; +} +#sidebar-left.minified .sidebar-nav > ul > li > ul { + display: none !important; +} +#sidebar-left.minified .sidebar-nav > ul > li:hover > a { + position: relative; +} +#sidebar-left.minified .sidebar-nav > ul > li:hover > a .chevron { + display: inline-block; +} +#sidebar-left.minified .sidebar-nav > ul > li:hover > a .text { + position: absolute; + z-index: 1000; + background: #e9ebec; + min-height: 40px; + width: 180px; + padding: 8px 15px; + border: 1px solid #dbdee0; + top: 0px; + left: 39px; + display: block !important; +} +#sidebar-left.minified .sidebar-nav > ul > li:hover > ul { + display: block !important; + position: absolute; + top: 39px; + left: 39px; + z-index: 1000; + width: 180px; + background: #e9ebec; + border: 1px solid #dbdee0; + border-bottom: none; +} +/* Buttons +=================================================================== */ +.btn { + border: none; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + text-shadow: none; + background: #e9ebec; + color: #7c848d; +} +.btn i { + margin-top: 2px; +} +.btn-primary { + color: #ffffff; + background: #36a9e1; +} +.btn-primary:hover, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #1e8fc6; +} +.btn-primary:active, +.btn-primary.active { + background-color: #1c89be; +} +.btn-warning { + color: #ffffff; + background: #fabb3d; +} +.btn-warning:hover, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f9aa0b; +} +.btn-warning:active, +.btn-warning.active { + background-color: #f4a406; +} +.btn-danger { + color: #ffffff; + background: #ff5454; +} +.btn-danger:hover, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #ff2121; +} +.btn-danger:active, +.btn-danger.active { + background-color: #ff1717; +} +.btn-success { + color: #ffffff; + background: #78cd51; +} +.btn-success:hover, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #5db734; +} +.btn-success:active, +.btn-success.active { + background-color: #59af32; +} +.btn-info { + color: #ffffff; + background: #67c2ef; +} +.btn-info:hover, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #39afea; +} +.btn-info:active, +.btn-info.active { + background-color: #30ace9; +} +.btn-inverse { + color: #ffffff; + background: #444444; +} +.btn-inverse:hover, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #2b2b2b; + color: #ffffff; +} +.btn-inverse:active, +.btn-inverse.active { + background-color: #252525; +} +.btn-facebook, +.btn-twitter, +.btn-linkedin { + color: white; + position: relative; + text-align: center; + height: 40px; + width: 100%; + font-family: 'FontAwesome'; + font-weight: bold; + padding: 10px 0; +} +.btn-facebook:before, +.btn-twitter:before, +.btn-linkedin:before { + position: absolute; + display: block; + height: 40px; + width: 40px; + top: 0; + left: 0; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + font-size: 20px; + padding: 6px 0; +} +.btn-facebook span, +.btn-twitter span, +.btn-linkedin span { + margin-left: 40px; +} +.btn-facebook:hover, +.btn-twitter:hover, +.btn-linkedin:hover { + color: white; +} +.btn-facebook { + background: #3b5998; +} +.btn-facebook:before { + content: "\f09a"; + background: #344e86; +} +.btn-facebook:hover { + background: #344e86; +} +.btn-facebook:hover:before { + background: #2d4373; +} +.btn-twitter { + background: #00aced; +} +.btn-twitter:before { + content: "\f099"; + background: #0099d4; +} +.btn-twitter:hover { + background: #0099d4; +} +.btn-twitter:hover:before { + background: #0087ba; +} +.btn-linkedin { + background: #4875B4; +} +.btn-linkedin:before { + content: "\f0e1"; + background: #4169a2; +} +.btn-linkedin:hover { + background: #4169a2; +} +.btn-linkedin:hover:before { + background: #395d90; +} +/* Tabs +=================================================================== */ +.nav-tabs li a { + border-color: #dbdee0; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + background: #e9ebec; + margin: 6px -1px -6px 0px; + line-height: 1; +} +.nav-tabs li a:hover { + border-color: #dbdee0; + background: #dbdee0; +} +.nav-tabs li.active > a { + line-height: 1.428571429; + margin: 0 -1px 0 0; +} +.tab-content { + background: white; + border: 1px solid #dbdee0; + border-top: none; + padding: 10px; +} +.box-header .nav-tabs { + border: none; + float: right; +} +.box-header .nav-tabs li a { + background: transparent; + border: none; + border-left: 1px solid #ced1d4; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + margin: 0; + font-size: 14px; + line-height: 16px; + font-weight: 300; + padding: 11px 15px; + height: 40px; +} +.box-header .nav-tabs li.active > a { + background: white; + border: none; + border-left: 1px solid #ced1d4; +} +.box-header .nav-tabs li:hover { + border: none; +} +.box-header .nav-tabs li:last-child { + margin-right: 3px; +} +.box-content .tab-content { + background: transparent; + border: none; + padding: 0; +} +/* Forms +=================================================================== */ +.form-horizontal .form-group { + margin-right: 0px; + margin-left: 0px; +} +.input-group-addon, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +input[type="file"], +.uneditable-input { + border-color: #e9ebec; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + border: 1px solid #e9ebec; + -webkit-border-radius: 2px !important; + -moz-border-radius: 2px !important; + border-radius: 2px !important; +} +.input-group-addon.clear { + background: white; + margin: 0 -1px; + color: #b2b8bd; +} +.limiterBox { + border: 1px solid #b2b8bd; + border-top: none; + background-color: #b2b8bd; + padding: 3px 6px; + font-size: 10px; + color: white; + opacity: .9; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.editor { + max-height: 250px; + height: 250px; + background-color: white; + border-collapse: separate; + border: 1px solid #ced1d4 !important; + padding: 4px; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + overflow: scroll; + outline: none; + margin-top: 20px; +} +div[data-role="editor-toolbar"] { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.dropdown-menu a { + cursor: pointer; +} +.twitter-typeahead .tt-query, +.twitter-typeahead .tt-hint { + margin-bottom: 0; +} +.tt-dropdown-menu { + min-width: 160px; + margin-top: 2px; + padding: 5px 0; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} +.tt-suggestion { + display: block; + padding: 3px 20px; +} +.tt-suggestion.tt-is-under-cursor { + color: #fff; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} +.tt-suggestion.tt-is-under-cursor a { + color: #fff; +} +.tt-suggestion p { + margin: 0; +} +/* Notifications & Labels +=================================================================== */ +.notification { + position: absolute; + top: -12px; + right: -12px; + line-height: 16px; + height: 16px; + padding: 6px 10px; + color: white !important; + -webkit-border-radius: 50em; + -moz-border-radius: 50em; + border-radius: 50em; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.notification.small { + padding: 2px 7px; + color: white !important; + border-width: 1px; + border-style: solid; + -webkit-border-radius: 50em; + -moz-border-radius: 50em; + border-radius: 50em; +} +.notification.small.blue, +.notification.blue { + background: #36a9e1; +} +.notification.small.yellow, +.notification.yellow { + background: #eae874; +} +.notification.small.red, +.notification.red { + background: #ff5454; +} +.notification.small.green, +.notification.green { + background: #78cd51; +} +.notification.small.orange, +.notification.orange { + background: #fabb3d; +} +.notification.small.red, +.notification.red { + background: #ff5454; +} +.label, +.badge { + font-weight: 300; + font-size: 10px; + padding: 4px 6px; + border: none; + text-shadow: none; +} +.label { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.label-important, +.badge-important, +.label-important[href], +.badge-important[href] { + background: #ff5454; +} +.label-warning, +.badge-warning, +.label-warning[href], +.badge-warning[href] { + background: #fabb3d; +} +.label-success, +.badge-success, +.label-success[href], +.badge-success[href] { + background: #78cd51; +} +.label-info, +.badge-info, +.label-info[href], +.badge-info[href] { + background: #67c2ef; +} +body.modal-open, +.modal-open .navbar-fixed-top, +.modal-open .navbar-fixed-bottom { + margin-right: 0px; +} +/* Collapse +=================================================================== */ +.panel-group .panel { + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + border: 1px solid #dbdee0; +} +.panel-group .panel .panel-heading { + background: #f7f7f8; +} +/* Footer +=================================================================== */ +footer { + background: #34383c; + color: white; + height: 40px; + padding: 12px 20px 20px 20px!important; + margin: 0 !important; + position: relative; + z-index: 1; + font-size: 12px; +} +footer a { + color: white; + font-weight: bold; +} +/* Vertical Bar Chart +=================================================================== */ +.verticalChart { + margin: 10px; +} +.verticalChart .singleBar { + width: 6%; + display: block; + margin: 0 2% 0% 2%; + float: left; +} +.verticalChart .singleBar .bar { + position: relative; + height: 120px; + background: #f9f9f9; + overflow: hidden; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.verticalChart .singleBar .bar .value { + position: absolute; + bottom: 0; + width: 100%; + background: #bdea74; + color: white; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.verticalChart .singleBar .bar .value span { + position: absolute; + font-size: 12px; + bottom: 0; + width: 100%; + height: 20px; + color: white; + text-shadow: 0px -1px 0px #bdea74, 0px 1px 0px #bdea74, 1px 0px 0px #bdea74, -1px 0px 0px #bdea74, -1px -1px 0px #bdea74, -1px 1px 0px #bdea74, 1px 1px 0px #bdea74, 1px -1px 0px #bdea74; + display: none; + text-align: center; +} +.verticalChart .singleBar .title { + margin-top: 5px; + text-align: center; + color: #34383c; +} +/* Browsers Stats +=================================================================== */ +.browserStat.big { + display: inline-block; + width: 49%; + text-align: center; + margin-bottom: 20px; + padding: 0px; +} +.browserStat { + display: inline-block; + width: 32%; + text-align: center; + margin: 0px; + padding: 0px; +} +.browserStat span { + display: block; + text-align: center; + margin-top: 10px; +} +/* Small Chart +=================================================================== */ +.smallchart { + background: white; + text-align: center; +} +.smallchart .title { + padding: 10px; + color: white; + background: #dbdee0; +} +.smallchart .content { + padding: 40px 0px; + background: #dbdee0; +} +.smallchart .content i { + font-size: 40px; + color: white; +} +.smallchart .value { + color: #34383c; + padding: 10px; +} +.smallchart.blue .title { + background: #36a9e1; +} +.smallchart.lightBlue .title { + background: #67c2ef; +} +.smallchart.green .title { + background: #bdea74; +} +.smallchart.darkGreen .title { + background: #78cd51; +} +.smallchart.pink .title { + background: #e84c8a; +} +.smallchart.orange .title { + background: #fa603d; +} +.smallchart.lightOrange .title { + background: #fabb3d; +} +.smallchart.red .title { + background: #ff5454; +} +.smallchart.yellow .title { + background: #eae874; +} +.smallchart.white .title { + background: white; +} +.smallchart.grey .title { + background: #b2b8bd; +} +/* Sparkline stats +=================================================================== */ +.sparkLineStats { + position: relative; + margin-bottom: -4px; +} +.sparkLineStats ul { + margin: 0 0 0 -40px; + list-style: none; +} +.sparkLineStats ul li { + margin-bottom: 0; + line-height: 32px; + padding-top: 3px; + font-size: 12px; +} +.sparkLineStats ul li div { + float: left; +} +.sparkLineStats ul li div:first-child { + margin-right: 5px; +} +.sparkLineStats ul li .number { + font-size: 17px; + font-weight: 700; + padding: 0px 0px 0px 2px; + color: #fa603d; +} +.sparkLineStats ul li h4 { + position: relative; + border-bottom: 1px solid #c4c4c4; + padding-bottom: 0px; + margin-bottom: 10px; + line-height: 37px; + -webkit-box-shadow: 0 1px 0px #ffffff; + -moz-box-shadow: 0 1px 0px #ffffff; + box-shadow: 0 1px 0px #ffffff; +} +/* Chart.JS responsive fix +=================================================================== */ +canvas.chartjs { + width: 100% !important; + max-width: 2000px; + height: auto !important; +} +/* Widget Stats +=================================================================== */ +.jqstooltip { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.smallstat { + background: white; + padding: 10px; + position: relative; + text-align: right; +} +.smallstat .linechart-overlay, +.smallstat .boxchart-overlay { + width: 84px; + padding: 10px; + text-align: center; + margin-right: 10px; + float: left; + overflow: hidden; +} +.smallstat .linechart-overlay.blue, +.smallstat .boxchart-overlay.blue { + background: #36a9e1; +} +.smallstat .linechart-overlay.lightBlue, +.smallstat .boxchart-overlay.lightBlue { + background: #67c2ef; +} +.smallstat .linechart-overlay.green, +.smallstat .boxchart-overlay.green { + background: #bdea74; +} +.smallstat .linechart-overlay.darkGreen, +.smallstat .boxchart-overlay.darkGreen { + background: #78cd51; +} +.smallstat .linechart-overlay.pink, +.smallstat .boxchart-overlay.pink { + background: #e84c8a; +} +.smallstat .linechart-overlay.orange, +.smallstat .boxchart-overlay.orange { + background: #fa603d; +} +.smallstat .linechart-overlay.lightOrange, +.smallstat .boxchart-overlay.lightOrange { + background: #fabb3d; +} +.smallstat .linechart-overlay.red, +.smallstat .boxchart-overlay.red { + background: #ff5454; +} +.smallstat .linechart-overlay.yellow, +.smallstat .boxchart-overlay.yellow { + background: #eae874; +} +.smallstat .linechart-overlay.white, +.smallstat .boxchart-overlay.white { + background: white; +} +.smallstat .linechart-overlay.grey, +.smallstat .boxchart-overlay.grey { + background: #b2b8bd; +} +.smallstat .piechart-overlay { + padding: 5px; + text-align: center; + margin-right: 10px; + float: left; + overflow: hidden; +} +.smallstat .piechart-overlay.blue { + background: #36a9e1; +} +.smallstat .piechart-overlay.lightBlue { + background: #67c2ef; +} +.smallstat .piechart-overlay.green { + background: #bdea74; +} +.smallstat .piechart-overlay.darkGreen { + background: #78cd51; +} +.smallstat .piechart-overlay.pink { + background: #e84c8a; +} +.smallstat .piechart-overlay.orange { + background: #fa603d; +} +.smallstat .piechart-overlay.lightOrange { + background: #fabb3d; +} +.smallstat .piechart-overlay.red { + background: #ff5454; +} +.smallstat .piechart-overlay.yellow { + background: #eae874; +} +.smallstat .piechart-overlay.white { + background: white; +} +.smallstat .piechart-overlay.grey { + background: #b2b8bd; +} +.smallstat .piechart { + color: white; + font-size: 10px; +} +.smallstat i { + text-align: center; + display: block; + color: white; + width: 50px; + font-size: 22px; + padding: 14px 0px; + float: left; + margin-right: 10px; +} +.smallstat i.blue { + background: #36a9e1; +} +.smallstat i.lightBlue { + background: #67c2ef; +} +.smallstat i.green { + background: #bdea74; +} +.smallstat i.darkGreen { + background: #78cd51; +} +.smallstat i.pink { + background: #e84c8a; +} +.smallstat i.orange { + background: #fa603d; +} +.smallstat i.lightOrange { + background: #fabb3d; +} +.smallstat i.red { + background: #ff5454; +} +.smallstat i.yellow { + background: #eae874; +} +.smallstat i.white { + background: white; +} +.smallstat i.grey { + background: #b2b8bd; +} +.smallstat .title { + top: 12px; + color: #b2b8bd; + display: block; + font-size: 12px; + margin-top: 4px; + font-weight: bold; +} +.smallstat .value { + font-size: 20px; +} +.smallstat .more { + background: #e9ebec; + border-top: 1px solid #dbdee0; + margin: 12px -10px -10px -10px; + padding: 5px 10px; + display: block; + font-size: 12px; + text-align: left; +} +.smallstat .more:hover { + color: #34383c; + text-decoration: none; +} +.smallstat .more i { + padding: 0; + margin: 4px 0 0 0; + display: inline; + color: #34383c; + font-size: 10px; + float: right; + width: 10px; +} +/* Box Stats +=================================================================== */ +ul.stats { + list-style: none; + padding: 0; + border-top: 1px solid #e9ebec; + margin: 20px -10px -10px -10px; + *zoom: 1; +} +ul.stats:before, +ul.stats:after { + display: table; + content: ""; + line-height: 0; +} +ul.stats:after { + clear: both; +} +ul.stats li { + position: relative; + z-index: 2; + width: 25%; + border-right: 1px solid #e9ebec; + float: left; + text-align: center; + padding: 20px 0px; + margin: 0; + overflow: hidden; +} +ul.stats li:last-child { + border: none; +} +ul.stats li .bgchart { + width: 100%; + height: 100%; + position: absolute; + z-index: -1; + top: 0px; + left: 0px; +} +/* Info Box +=================================================================== */ +.info-box .backgroundColor { + color: white; + padding: 10px; +} +.info-box .title, +.info-box .value { + font-weight: bold; + font-size: 12px; + margin: 0; + padding: 0; +} +.info-box .date, +.info-box .change { + font-size: 10px; + margin: 0; + padding: 0; +} +.info-box .title, +.info-box .date { + float: left; +} +.info-box .value, +.info-box .change { + float: right; +} +.info-box .quarters { + background: white; + *zoom: 1; +} +.info-box .quarters:before, +.info-box .quarters:after { + display: table; + content: ""; + line-height: 0; +} +.info-box .quarters:after { + clear: both; +} +.info-box .quarters .quarter { + padding: 10px; +} +.info-box .quarters .quarter span { + display: block; + font-size: 10px; + color: #b2b8bd; +} +.info-box .quarters .q1, +.info-box .quarters .q2, +.info-box .quarters .q3, +.info-box .quarters .q4 { + width: 50%; + float: left; +} +.info-box .quarters .q1, +.info-box .quarters .q2 { + border-bottom: 1px solid #e9ebec; + height: 60px; +} +.info-box .quarters .q2 { + padding: 0; +} +.info-box .quarters .q2, +.info-box .quarters .q4 { + text-align: right; +} +.info-box .quarters .q4 { + border-left: 1px solid #e9ebec; +} +.info-box .quarters .verticalChart { + float: right; + text-align: center; + margin: 3px 0 0 0; + width: 100%; + padding: 6px; +} +.info-box .quarters .verticalChart .singleBar { + width: 10.5%; + margin: 0 0px 0 3px; +} +.info-box .quarters .verticalChart .singleBar .bar { + height: 22px; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; +} +.info-box .quarters .verticalChart .singleBar .bar .value { + background: #b2b8bd; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; +} +.info-box .quarters .verticalChart .singleBar .title { + margin: 2px auto 0 auto; + text-align: center; + color: #b2b8bd; + font-size: 8px; + font-weight: 400; + width: 100%; +} +/* Discussions +=================================================================== */ +.discussions ul { + list-style: none; + margin: 0; + padding: 0; +} +.discussions ul li { + font-size: 12px; + border: 1px solid #dbdee0; + position: relative; + background: white; + margin: 0 40px 20px 80px; + padding: 10px; +} +.discussions ul li:before { + content: ''; + width: 20px; + height: 20px; + top: 15px; + left: -20px; + position: absolute; + background: url("../img/disc-arrow.png") no-repeat; + background-size: 20px 20px; +} +.discussions ul li .author { + position: absolute; + z-index: 1; + width: 60px; + float: left; + top: 0px; + left: -70px; +} +.discussions ul li .author img { + height: 50px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.discussions ul li .name { + position: absolute; + top: 10px; + left: 10px; + width: 100%; + background: #e9ebec; + padding: 5px 10px 5px 10px; +} +.discussions ul li .date { + position: absolute; + top: 10px; + right: -1px; + z-index: 1; + background: #dbdee0; + padding: 5px 20px 5px 10px; +} +.discussions ul li .delete { + position: absolute; + background: #ced1d4; + top: 10px; + right: -30px; + padding: 5px 10px; + display: inline-block; + cursor: pointer; +} +.discussions ul li .message { + border-bottom: 1px solid #e9ebec; + margin: 20px -10px 0px -10px; + padding: 20px; + font-size: 12px; +} +.discussions ul li ul { + overflow: hidden; +} +.discussions ul li ul li { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + border: none; + border-bottom: 1px solid #e9ebec; + margin: 0 -10px; + padding-left: 70px; +} +.discussions ul li ul li:before { + display: none; +} +.discussions ul li ul li:last-child { + border-bottom: none; +} +.discussions ul li ul li .author { + top: 10px; + left: 10px; +} +.discussions ul li ul li .author img { + height: 40px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.discussions ul li ul li .name { + left: 70px; +} +.discussions ul li ul li .date { + background: transparent; + right: 30px; +} +.discussions ul li ul li .delete { + background: transparent; + right: 10px; +} +.discussions ul li ul li .message { + border-bottom: none; +} +.discussions ul li ul li textarea { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + width: 100%; + font-size: 12px; + padding: 5px; +} +/* Chat Widget +=================================================================== */ +.chat { + position: relative; + background: white; +} +.chat .contacts { + position: absolute; + height: 100%; + float: left; + width: 30%; + background: #e9ebec; + border-right: 1px solid #dbdee0; +} +.chat .contacts ul.list { + list-style: none; + margin: 0; + padding: 0; +} +.chat .contacts ul.list li { + position: relative; + padding: 5px 10px; + border-bottom: 1px solid #dbdee0; + cursor: pointer; +} +.chat .contacts ul.list li:hover { + background: #b2b8bd; +} +.chat .contacts ul.list li img.avatar { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + width: 40px; + margin-right: 10px; +} +.chat .contacts ul.list li .status { + display: block; + position: absolute; + top: 42%; + right: 20px; + width: 8px; + height: 8px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.chat .contacts ul.list li .status.online { + background: #bdea74; +} +.chat .contacts ul.list li .status.offline { + background: #b2b8bd; +} +.chat .contacts ul.list li .status.busy { + background: #fa603d; +} +.chat .contacts ul.list li .important { + font-size: 11px; + display: inline-block; + position: absolute; + top: 1px; + left: 35px; + font-size: 10px; + padding: 3px 7px; + color: white; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + background: #ff5454; +} +.chat .conversation { + width: 70%; + float: right; +} +.chat .conversation .actions { + background: #34383c; + width: 100%; + height: 50px; +} +.chat .conversation .actions a { + display: block; + color: white; + padding: 16px; + font-size: 18px; + width: 18px; + float: left; +} +.chat .conversation .actions img.avatar { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + width: 30px; + margin: 10px 0px 10px 10px; +} +.chat .conversation ul { + height: 516px; + overflow-y: scroll; + list-style: none; + margin: 0; + padding: 0; +} +.chat .conversation ul li { + position: relative; + padding: 15px 10px 10px 60px; + border-bottom: 1px solid #dbdee0; +} +.chat .conversation ul li img.avatar { + top: 10px; + left: 10px; + position: absolute; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + width: 40px; + margin-right: 10px; +} +.chat .conversation ul li .name { + font-weight: bold; + text-transform: uppercase; +} +.chat .conversation ul li .time { + font-weight: bold; + right: 10px; + position: absolute; + color: #b2b8bd; + font-size: 11px; +} +.chat .conversation ul li .message { + margin-top: 10px; + font-size: 12px; +} +.chat .conversation .form { + border-top: 2px solid #dbdee0; + height: 60px; + padding: 10px; +} +.chat .conversation .form input { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100%; + height: 100%; +} +.chat.alt .contacts { + width: 60px; +} +.chat.alt .contacts ul.list { + list-style: none; + margin: 0; + padding: 0; +} +.chat.alt .contacts ul.list li { + text-align: center; +} +.chat.alt .contacts ul.list li img.avatar { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + width: 40px; + margin: 0 auto; +} +.chat.alt .contacts ul.list li .name { + display: none; +} +.chat.alt .contacts ul.list li .status { + top: 70%; + right: 10px; +} +.chat.alt .conversation { + width: auto; + margin-left: 60px; +} +/* Calendar Widget +=================================================================== */ +.calendar { + background: white; +} +.calendar .calendar-details { + background: #dbdee0; + color: white; + font-weight: 300px; + position: relative; + padding: 20px; +} +.calendar .calendar-details .day { + font-size: 20px; + text-transform: uppercase; + float: left; + margin: 10px; +} +.calendar .calendar-details .date { + font-size: 20px; + margin: 10px; + text-transform: uppercase; +} +.calendar .calendar-details ul.events { + list-style: none; + margin: 0; + padding: 0; +} +.calendar .calendar-details ul.events li { + margin: 0px 10px; +} +.calendar .calendar-details .add-event { + display: block; + bottom: 10px; + border-bottom: #b2b8bd; + padding: 13px 5px 0 5px; +} +.calendar .calendar-details .add-event input { + width: 100%; + color: white; + border: 0; + font-size: 12px; + margin: 0; + padding: 5px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + background: #ced1d4; + z-index: 9; +} +.calendar .fc { + padding: 20px; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.calendar .fc-widget-header, +.calendar .fc-widget-content { + border-color: #e9ebec; +} +.calendar .fc-state-default { + background: white; + border: none; + color: #b2b8bd; + text-shadow: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + margin-top: -5px; + margin-left: -10px; +} +.calendar .fc-state-hover, +.calendar .fc-state-down, +.calendar .fc-state-active, +.calendar .fc-state-disabled { + color: #34383c; + background: white; +} +.calendar .fc-day-number { + margin: 0px 0 0 -30px; + padding: 5px !important; + text-align: left; + font-size: 10px; + font-weight: 300; +} +.calendar .fc-state-highlight { + background: transparent; +} +.calendar .fc-state-highlight .fc-day-number { + color: #36a9e1; + font-weight: 700; +} +.calendar .event { + background: #36a9e1; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + color: white; +} +.calendar .fc-grid .fc-day-number { + float: none; + padding: 0 2px; + text-align: center; +} +.calendar .fc-grid .fc-other-month .fc-day-number { + opacity: 1; + filter: alpha(opacity=1); + color: #b2b8bd; +} +.calendar .fc-event { + border: 0; + height: 1px; + background: #b2b8bd; +} +.calendar .fc-event .fc-event-inner { + display: none; +} +/* Dashboard Lists +=================================================================== */ +ul.dashboard-list { + padding: 0; +} +ul.dashboard-list a:hover { + text-decoration: none; +} +ul.dashboard-list li:last-child { + border-bottom: none; +} +ul.dashboard-list li:first-child { + border-top: none; + border-bottom: 1px solid #e9ebec; +} +ul.dashboard-list li { + padding: 5px 0; + list-style: none; + border-bottom: 1px solid #e9ebec; + font-size: 12px; +} +ul.dashboard-list li a span { + display: inline-block; + font-size: 18px; + font-weight: bold; + margin-right: 10px; + text-align: right; + width: 50px; + zoom: 1; +} +ul.dashboard-list li a img.avatar { + height: 50px; + width: 50px; + float: left; + margin-top: 3px; + margin-right: 15px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +ul.dashboard-list li i { + font-size: 18px; + opacity: .7; + filter: alpha(opacity=70); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; +} +/* Users List +=================================================================== */ +ul.users-list { + padding: 0; +} +ul.users-list a:hover { + text-decoration: none; +} +ul.users-list li:last-child { + border-bottom: none; + min-height: 51px; +} +ul.users-list li:first-child { + border-top: none; + border-bottom: 1px solid #e9ebec; +} +ul.users-list li { + min-height: 60px; + padding: 5px 10px; + list-style: none; + border-bottom: 1px solid #e9ebec; + font-size: 12px; +} +ul.users-list li a img.avatar { + height: 40px; + width: 40px; + float: left; + margin-top: 3px; + margin-right: 15px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +ul.users-list li .name { + margin: 5px 0 -2px 0; + font-size: 14px; + font-weight: bold; +} +ul.users-list li .name .dropdown { + float: right; + margin: -1px 0; +} +ul.users-list li .name .dropdown a { + color: #b2b8bd; + font-size: 11px; + text-decoration: none; +} +ul.users-list li .name .dropdown ul li { + padding: 0; + min-height: 10px; +} +ul.users-list li .name .dropdown ul li i { + display: inline-block; + width: 20px; +} +ul.users-list li span { + display: inline-block; + margin-right: 5px; + font-size: 10px; + color: #b2b8bd; +} +ul.users-list li .place { + width: 35%; +} +ul.users-list li i { + color: #b2b8bd; + margin-right: 2px; + font-size: 11px; +} +ul.users-list.no-padding li { + padding: 5px 0; +} +/* Comments Lists ex. +=================================================================== */ +ul.comments-list { + padding: 0; +} +ul.comments-list a:hover { + text-decoration: none; +} +ul.comments-list li:last-child { + border-bottom: none; +} +ul.comments-list li:first-child { + border-top: none; + border-bottom: 1px solid #e9ebec; +} +ul.comments-list li { + padding: 5px 10px; + list-style: none; + border-bottom: 1px solid #e9ebec; + font-size: 12px; +} +ul.comments-list li a img.avatar { + height: 50px; + width: 50px; + float: left; + margin-top: 3px; + margin-right: 15px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +ul.comments-list li div { + margin-left: 65px; +} +ul.comments-list li div.date { + margin-top: 5px; + font-size: 10px; + font-weight: bold; + color: #b2b8bd; +} +ul.comments-list.no-padding li { + padding: 5px 0; +} +/* ToDo List +=================================================================== */ +.todo ul { + list-style: none; + padding: 0px; + margin: -10px; +} +.todo ul li { + background: white; + margin-left: 0px !important; + padding: 10px 10px 10px 35px; + border-bottom: 1px solid #e9ebec; + font-size: 12px; + position: relative; +} +.todo ul li:last-child { + border-bottom: 0px; +} +.todo ul li .label { + position: absolute; + right: 10px; +} +.todo ul li .todo-actions { + position: absolute; + left: 0px; + margin-top: 2px; +} +.todo ul li .todo-actions a { + text-decoration: none; +} +.todo ul li .todo-actions i { + font-size: 14px; + color: #dbdee0; + margin: -1px 5px 0px 10px; + display: block; +} +.todo ul li .todo-actions i.done { + color: #ced1d4; +} +.todo ul li .todo-actions i:hover { + color: #b2b8bd; +} +.todo ul li .remove { + display: none; + position: absolute; + right: 10px; + color: #b2b8bd; +} +.todo ul li:hover .label { + position: absolute; + right: 30px; +} +.todo ul li:hover .remove { + display: inline; +} +/* Activity Feed +=================================================================== */ +#feed { + background: #e9ebec; + top: 0px; + right: 0px; + position: absolute; + height: 100%; + border-left: 1px solid #dbdee0; +} +#feed h2 { + background: #dbdee0; + padding: 12px; + margin: 0px -15px 10px -15px; +} +#feed h2 a { + float: right; + color: #b2b8bd; + text-decoration: none; + cursor: pointer; +} +#feed h2 a:hover { + color: #34383c; +} +#feed ul#filter { + margin: 0 0 10px -40px; + list-style: none; + *zoom: 1; +} +#feed ul#filter:before, +#feed ul#filter:after { + display: table; + content: ""; + line-height: 0; +} +#feed ul#filter:after { + clear: both; +} +#feed ul#filter li { + float: left; + margin-right: 20px; + cursor: pointer; +} +#feed ul#filter li a { + text-decoration: none; +} +#feed ul#filter li a.active { + font-weight: bold; +} +#feed ul#filter li a:hover { + color: inherit; +} +#feed ul#timeline { + margin: 0 0 0 10px; + list-style: none; + border-left: 1px solid #dbdee0; +} +#feed ul#timeline li { + position: relative; + margin: 0 0 20px -20px; + font-size: 12px; +} +#feed ul#timeline li i { + position: absolute; + top: -4px; + left: -36px; + background: #e9ebec; + padding: 5px 0px; + font-size: 15px; + width: 30px; + text-align: center; +} +#feed ul#timeline li.tasks i { + color: #bdea74; +} +#feed ul#timeline li.comments i { + color: #ff5454; +} +#feed ul#timeline li.messages i { + color: #36a9e1; +} +#feed ul#timeline li .title { + font-weight: bold; +} +#feed ul#timeline li .desc { + margin: 5px 0; +} +#feed ul#timeline li .date, +#feed ul#timeline li .separator, +#feed ul#timeline li .name { + color: #b2b8bd; +} +#feed ul#timeline li .separator { + margin: 0 5px; +} +#feed #load-more { + color: #dbdee0; + margin: 0 auto; + display: block; + text-align: center; + text-decoration: none; +} +#feed #load-more:hover { + color: #34383c; +} +/* UI - Sliders & Progress +=================================================================== */ +.slider { + background: #e9ebec; + border: none; + height: 10px; + position: relative; + z-index: 10; + margin: 5px 0px !important; +} +.slider .ui-slider-range { + position: absolute; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.slider.small { + height: 6px; +} +.ui-slider-handle { + border: 1px solid #ced1d4; + outline: none !important; +} +.ui-slider-horizontal .ui-slider-handle { + background: url("../img/handle.png") no-repeat center center scroll #ffffff !important; + background-position: 50% 50%; + background-size: 8px 8px !important; +} +.ui-slider-horizontal.small .ui-slider-handle { + background: url("../img/handle.png") no-repeat center center scroll #ffffff !important; + background-position: 50% 50%; + background-size: 8px 8px !important; + width: 14px !important; + height: 14px !important; +} +.sliderVertical { + background: #e9ebec; + border: none; + top: auto; + bottom: auto; + width: 10px !important; + position: relative; + float: left; + height: 100px; + margin: 10px 20px; + width: 5px; +} +.sliderVertical .ui-slider-range { + height: 100%; + width: 100%; + top: auto; + bottom: auto; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.sliderVertical .ui-slider-handle { + background: url("../img/handlev.png") no-repeat center center scroll #ffffff !important; + background-position: 50% 50%; + background-size: 8px 8px !important; + left: 50%; + margin: 9px 0px -9px -9px !important; +} +.sliderVertical .ui-slider-range-max { + top: 0; +} +.sliderVertical .ui-slider-range-min { + bottom: 0; +} +.sliderVertical.small { + width: 6px !important; + position: relative; + float: left; + height: 100px; + margin: 10px 20px; + width: 5px; +} +.sliderVertical.small .ui-slider-handle { + background: url("../img/handlev.png") no-repeat center center scroll #ffffff !important; + background-position: 50% 50%; + background-size: 8px 8px !important; + width: 14px; + height: 14px; + margin: 0px 0px -7px -7px !important; +} +.sliderBlue .ui-slider-range, +.progressBlue .ui-progressbar-value { + background: #36a9e1; +} +.sliderGreen .ui-slider-range, +.progressGreen .ui-progressbar-value { + background: #bdea74; +} +.sliderDarkGreen .ui-slider-range, +.progressDarkGreen .ui-progressbar-value { + background: #78cd51; +} +.sliderPink .ui-slider-range, +.progressPink .ui-progressbar-value { + background: #e84c8a; +} +.sliderOrange .ui-slider-range, +.progressOrange .ui-progressbar-value { + background: #fa603d; +} +.sliderLightOrange .ui-slider-range, +.progressLightOrange .ui-progressbar-value { + background: #fabb3d; +} +.sliderRed .ui-slider-range, +.progressRed .ui-progressbar-value { + background: #ff5454; +} +.sliderYellow .ui-slider-range, +.progressYellow .ui-progressbar-value { + background: #eae874; +} +.progress { + background: #e9ebec; + color: #e9ebec; + border: none; + height: 14px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + position: relative; + margin-top: -2px; +} +.progress .ui-progressbar-value { + border: none; + height: 100%; + top: 1px; + position: absolute; + left: 1px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.progress.slim { + height: 10px; +} +.progressBarValue span { + font-size: 12px; +} +.progressBarValue span.progressCustomValueVal { + font-size: 18px; + font-weight: 700; + padding: 0 5px; + color: #fa603d; +} +.progressSlim { + background: #ced1d4; + border: none; + height: 10px; + position: relative; + margin-top: -2px; +} +.progressSlim .ui-progressbar-value { + border-color: transparent; + height: 100%; + top: 0px; + position: absolute; + left: 0px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.tasks .progressSlim { + overflow: hidden; + border: none !important; + height: 8px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + margin-top: 0px; +} +.tasks .progressSlim .ui-progressbar-value { + overflow: hidden; + margin: 0px; + border: none !important; +} +/* Quick Buttons +=================================================================== */ +.quick-button { + border: 1px solid #dbdee0; + background: #e9ebec; + margin-bottom: -1px; + padding: 30px 0px 10px 0px; + font-size: 14px; + display: block; + text-align: center; + cursor: pointer; + position: relative; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -ms-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; + color: #b2b8bd; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.quick-button:hover { + color: #34383c; + text-decoration: none; + background: #dbdee0; +} +.quick-button .notification { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + top: -1px; + right: -1px; + font-size: 10px; +} +.quick-button i { + font-size: 32px; +} +.quick-button.small { + padding: 15px 0px 0px 0px; + font-size: 10px; +} +.quick-button.small i { + font-size: 20px; +} +.quick-button.small .notification { + top: -1px; + right: -1px; + font-size: 7px; + padding: 4px 5px; +} +/* Circle stats +=================================================================== */ +.tempStats { + text-align: center !important; +} +.tempStatBox { + width: 120px; + padding: 25px 0px; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + margin: 0 auto; +} +.tempStatBox .tempStat { + position: relative; + font-size: 34px; + line-height: 100px; + -webkit-border-radius: 50em; + -moz-border-radius: 50em; + border-radius: 50em; + border: 10px solid #FFF; + background: #f9f9f9; + height: 100px; + width: 100px; + text-align: center; + margin: 0 auto; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.tempStatBox .tempStat:before { + content: ""; + top: -10px; + left: -10px; + height: 120px; + width: 120px; + position: absolute; + -webkit-border-radius: 50em; + -moz-border-radius: 50em; + border-radius: 50em; + background: transparent; + -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3), 0px 1px 0px #ffffff; + -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3), 0px 1px 0px #ffffff; + box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3), 0px 1px 0px #ffffff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.tempStatBox .tempStat:after { + content: ""; + top: 0px; + left: 0px; + height: 98px; + width: 98px; + position: absolute; + -webkit-border-radius: 50em; + -moz-border-radius: 50em; + border-radius: 50em; + border: 1px solid #fff; + background: transparent; + -webkit-box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.4); + -moz-box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.4); + box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.4); + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.tempStatBox .tempStat.t0 { + border-color: #67c2ef; +} +.tempStatBox .tempStat.t20 { + border-color: #bdea74; +} +.tempStatBox .tempStat.t40 { + border-color: #eae874; +} +.tempStatBox .tempStat.t60 { + border-color: #fabb3d; +} +.tempStatBox .tempStat.t80 { + border-color: #fa603d; +} +.tempStatBox .tempStat.t100 { + border-color: #ff5454; +} +.tempStatBox span { + width: 100%; + text-align: center; + display: block; + margin-top: 10px; + text-shadow: 0px 1px 0px #fff; +} +/* Circle stats +=================================================================== */ +.circleStats { + text-align: center; + position: relative; +} +.circleStatsItem { + position: relative; + background: rgba(255, 255, 255, 0.7); + -webkit-box-shadow: inset 0 0px 0 2px rgba(0, 0, 0, 0.2), 0 0px 0 4px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 0px 0 2px rgba(0, 0, 0, 0.2), 0 0px 0 4px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 0px 0 2px rgba(0, 0, 0, 0.2), 0 0px 0 4px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 50em; + -moz-border-radius: 50em; + border-radius: 50em; + width: 120px; + height: 120px; + margin: 10px auto; +} +.circleStatsItem i { + font-size: 30px; + position: absolute; + top: 30%; + margin-top: 0px; + width: 100%; + text-align: center; +} +.circleStatsItem input { + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + border: none; + height: auto; + position: absolute; + top: 15px; + left: 120px; + padding: 5px 0px !important; + border-color: rgba(0, 0, 0, 0.8); +} +.circleStatsItem input:focus { + outline: 0; + outline: thin dotted 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.circleStatsItem .plus { + font-size: 16px; + position: absolute; + top: 55%; + margin-left: 30px; +} +.circleStatsItem .percent { + font-size: 14px; + position: absolute; + top: 57%; + margin-left: 78px; +} +.circleStatsItem.orange, +.circleStatsItem.orange i { + color: #fa603d; +} +.circleStatsItem.lightorange, +.circleStatsItem.lightorange i { + color: #fabb3d; +} +.circleStatsItem.blue, +.circleStatsItem.blue i { + color: #36a9e1; +} +.circleStatsItem.green, +.circleStatsItem.green i { + color: #bdea74; +} +.circleStatsItem.yellow, +.circleStatsItem.yellow i { + color: #eae874; +} +.circleStatsItem.pink, +.circleStatsItem.pink i { + color: #e84c8a; +} +.circleStatsItemBox { + position: relative; + background: #67c2ef; + width: 100%; + min-width: 130px; + height: 160px; + margin: 10px auto; + padding-top: 40px; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.circleStatsItemBox .header { + background: rgba(255, 255, 255, 0.2); + color: rgba(255, 255, 255, 0.9); + width: 100%; + height: 20px; + padding: 5px 0px; + position: absolute; + top: 0px; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.circleStatsItemBox .footer { + background: rgba(0, 0, 0, 0.1); + color: rgba(255, 255, 255, 0.9); + width: 100%; + height: 20px; + padding: 5px 0px; + position: absolute; + bottom: 0px; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.circleStatsItemBox .footer .count { + font-size: 10px; +} +.circleStatsItemBox .footer .value { + font-weight: bold; +} +.circleStatsItemBox .percent { + font-size: 12px; + position: absolute; + top: 110px; + width: 100%; + left: 0px; + text-align: center; + color: rgba(255, 255, 255, 0.9); +} +.circleStatsItemBox input { + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + border: none; + height: auto; + position: absolute; + top: 30px; + padding: 5px 0px !important; + border-color: rgba(0, 0, 0, 0.8); +} +.circleStatsItemBox input:focus { + outline: 0; + outline: thin dotted 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +/* Masonry Gallery +=================================================================== */ +.masonry-thumb { + display: inline-block; + vertical-align: top; + margin-bottom: 6px; +} +/* Star Rating +=================================================================== */ +.rating { + unicode-bidi: bidi-override; + direction: rtl; + font-size: 30px; +} +.rating span.star, +.rating span.star { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + display: inline-block; +} +.rating span.star:hover, +.rating span.star:hover { + cursor: pointer; +} +.rating span.star:before, +.rating span.star:before { + content: "\f006"; + padding-right: 5px; + color: #999999; +} +.rating span.star:hover:before, +.rating span.star:hover:before, +.rating span.star:hover ~ span.star:before, +.rating span.star:hover ~ span.star:before { + content: "\f005"; + color: #e3cf7a; +} +/* Icons +=================================================================== */ +.glyphicons-icon-list div { + margin: 10px 0; +} +.glyphicons-icon-list div span, +.glyphicons-icon-list div strong { + font-size: 10px; +} +.glyphicons-icon-list div strong { + margin-top: -5px; + display: block; +} +.fontawesome-icon-list div { + margin: 5px 0; +} +.fontawesome-icon-list .fa { + width: 20px; + text-align: center; + margin-right: 10px; +} +/* File manager +=================================================================== */ +.elfinder .elfinder-button { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +/* Text with HR Line +=================================================================== */ +.text-with-hr { + text-align: center; + position: relative; + z-index: 2; +} +.text-with-hr:before { + position: absolute; + content: ''; + top: 20px; + left: 0px; + width: 100%; + border-bottom: 1px solid #e9ebec; + z-index: -1; +} +.text-with-hr span { + display: inline-block; + background: white; + padding: 10px; +} +/* + * Copyright (c) 2013 Thibaut Courouble + * http://www.cssflow.com + * + * Licensed under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + */ +.switch { + position: relative; + display: inline-block; + vertical-align: top; + width: 56px; + height: 20px; + padding: 3px; + background-color: white; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + box-shadow: inset 0 -1px #ffffff, inset 0 1px 1px rgba(0, 0, 0, 0.05); + cursor: pointer; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.switch-input { + position: absolute; + top: 0; + left: 0; + opacity: 0; +} +.switch-label { + position: relative; + display: block; + height: inherit; + font-size: 10px; + text-transform: uppercase; + background: #f9f9f9; + border-radius: inherit; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.15); + -webkit-transition: 0.15s ease-out; + -moz-transition: 0.15s ease-out; + -o-transition: 0.15s ease-out; + transition: 0.15s ease-out; + -webkit-transition-property: opacity background; + -moz-transition-property: opacity background; + -o-transition-property: opacity background; + transition-property: opacity background; +} +.switch-label:before, +.switch-label:after { + position: absolute; + top: 50%; + margin-top: -0.5em; + line-height: 1; + -webkit-transition: inherit; + -moz-transition: inherit; + -o-transition: inherit; + transition: inherit; +} +.switch-label:before { + content: attr(data-off); + right: 11px; + color: #aaa; + text-shadow: 0 1px rgba(255, 255, 255, 0.5); +} +.switch-label:after { + content: attr(data-on); + left: 11px; + color: white; + text-shadow: 0 1px rgba(0, 0, 0, 0.2); + opacity: 0; +} +.switch-input:checked ~ .switch-label { + background: #b2b8bd; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15), inset 0 0 3px rgba(0, 0, 0, 0.2); +} +.switch-input:checked ~ .switch-label:before { + opacity: 0; +} +.switch-input:checked ~ .switch-label:after { + opacity: 1; +} +.switch-handle { + position: absolute; + top: 4px; + left: 4px; + width: 18px; + height: 18px; + background: white; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2); + background-image: -webkit-linear-gradient(top, #ffffff 40%, #f0f0f0); + background-image: -moz-linear-gradient(top, #ffffff 40%, #f0f0f0); + background-image: -o-linear-gradient(top, #ffffff 40%, #f0f0f0); + background-image: linear-gradient(to bottom, #ffffff 40%, #f0f0f0); + -webkit-transition: left 0.15s ease-out; + -moz-transition: left 0.15s ease-out; + -o-transition: left 0.15s ease-out; + transition: left 0.15s ease-out; +} +.switch-handle:before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + margin: -6px 0 0 -6px; + width: 12px; + height: 12px; + background: #f9f9f9; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + box-shadow: inset 0 1px rgba(0, 0, 0, 0.02); + background-image: -webkit-linear-gradient(top, #eeeeee, #ffffff); + background-image: -moz-linear-gradient(top, #eeeeee, #ffffff); + background-image: -o-linear-gradient(top, #eeeeee, #ffffff); + background-image: linear-gradient(to bottom, #eeeeee, #ffffff); +} +.switch-input:checked ~ .switch-handle { + left: 40px; + box-shadow: -1px 1px 5px rgba(0, 0, 0, 0.2); +} +.switch-primary > .switch-input:checked ~ .switch-label { + background: #36a9e1; +} +.switch-success > .switch-input:checked ~ .switch-label { + background: #78cd51; +} +.switch-warning > .switch-input:checked ~ .switch-label { + background: #fabb3d; +} +.switch-important > .switch-input:checked ~ .switch-label { + background: #ff5454; +} +.switch-info > .switch-input:checked ~ .switch-label { + background: #67c2ef; +} +.switch-danger > .switch-input:checked ~ .switch-label { + background: #d9534f; +} +table tr td.left, +table tr th.left { + text-align: left; +} +table tr td.center, +table tr th.center { + text-align: center; +} +table tr td.right, +table tr th.right { + text-align: right; +} +table tr td .progress { + margin: 3px 0 0 0; +} +table.table-clear tr, +table.table-clear td { + border: none !important; +} +table.small-font { + font-size: 12px; +} +.table thead > tr > th, +.table tbody > tr > th, +.table tfoot > tr > th, +.table thead > tr > td, +.table tbody > tr > td, +.table tfoot > tr > td { + padding: 8px; + line-height: 1.428571429; + vertical-align: top; + border-top: 1px solid #e9ebec; +} +.table thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #e9ebec; +} +.table-bordered { + border: 1px solid #e9ebec; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #e9ebec; +} +/* Skill Bars +=================================================================== */ +ul.skill-bar { + padding: 0px; +} +ul.skill-bar h5 { + margin-bottom: 6px; +} +ul.skill-bar li { + margin-bottom: 12px; + list-style: none; + padding-left: 0px; +} +ul.skill-bar li .meter { + height: 20px; + position: relative; + background: #e9ebec; +} +ul.skill-bar li .meter span { + display: block; + height: 100%; + position: relative; + overflow: hidden; + color: white; + background: #b2b8bd; + text-align: right; + padding-right: 10px; + margin: 0; +} +ul.skill-bar li .meter span.blue { + background: #36a9e1; +} +ul.skill-bar li .meter span.lightBlue { + background: #67c2ef; +} +ul.skill-bar li .meter span.green { + background: #bdea74; +} +ul.skill-bar li .meter span.darkGreen { + background: #78cd51; +} +ul.skill-bar li .meter span.pink { + background: #e84c8a; +} +ul.skill-bar li .meter span.orange { + background: #fa603d; +} +ul.skill-bar li .meter span.lightOrange { + background: #fabb3d; +} +ul.skill-bar li .meter span.red { + background: #ff5454; +} +ul.skill-bar li .meter span.yellow { + background: #eae874; +} +ul.skill-bar li .meter span.white { + background: white; +} +ul.skill-bar li .meter span.grey { + background: #b2b8bd; +} +div.dataTables_length label { + font-weight: normal; + float: left; + text-align: left; +} +div.dataTables_length select { + width: 75px; +} +div.dataTables_filter label { + font-weight: normal; + float: right; +} +div.dataTables_info { + padding-top: 8px; +} +div.dataTables_paginate { + float: right; + margin: 0; +} +div.dataTables_paginate ul.pagination { + margin: 2px; +} +table.table { + clear: both; + margin-top: 6px !important; + margin-bottom: 6px !important; + max-width: none !important; +} +table.table .btn { + margin: 1px 0; +} +table.table thead .sorting, +table.table thead .sorting_asc, +table.table thead .sorting_desc, +table.table thead .sorting_asc_disabled, +table.table thead .sorting_desc_disabled { + cursor: pointer; +} +table.table thead .sorting { + background: url('../img/sort_both.png') no-repeat center right; +} +table.table thead .sorting_asc { + background: url('../img/sort_asc.png') no-repeat center right; +} +table.table thead .sorting_desc { + background: url('../img/sort_desc.png') no-repeat center right; +} +table.table thead .sorting_asc_disabled { + background: url('../img/sort_asc_disabled.png') no-repeat center right; +} +table.table thead .sorting_desc_disabled { + background: url('../img/sort_desc_disabled.png') no-repeat center right; +} +table.dataTable th:active { + outline: none; +} +/* Scrolling */ +div.dataTables_scrollHead table { + margin-bottom: 0 !important; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +div.dataTables_scrollHead table thead tr:last-child th:first-child, +div.dataTables_scrollHead table thead tr:last-child td:first-child { + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} +div.dataTables_scrollBody table { + border-top: none; + margin-bottom: 0 !important; +} +div.dataTables_scrollBody tbody tr:first-child th, +div.dataTables_scrollBody tbody tr:first-child td { + border-top: none; +} +div.dataTables_scrollFoot table { + border-top: none; +} +/* + * TableTools styles + */ +.table tbody tr.active td, +.table tbody tr.active th { + background-color: #08C; + color: white; +} +.table tbody tr.active:hover td, +.table tbody tr.active:hover th { + background-color: #0075b0 !important; +} +.table-striped tbody tr.active:nth-child(odd) td, +.table-striped tbody tr.active:nth-child(odd) th { + background-color: #017ebc; +} +table.DTTT_selectable tbody tr { + cursor: pointer; +} +div.DTTT .btn { + color: #333 !important; + font-size: 12px; +} +div.DTTT .btn:hover { + text-decoration: none !important; +} +ul.DTTT_dropdown.dropdown-menu { + z-index: 2003; +} +ul.DTTT_dropdown.dropdown-menu a { + color: #333 !important; + /* needed only when demo_page.css is included */ + +} +ul.DTTT_dropdown.dropdown-menu li { + position: relative; +} +ul.DTTT_dropdown.dropdown-menu li:hover a { + background-color: #0088cc; + color: white !important; +} +/* TableTools information display */ +div.DTTT_print_info.modal { + height: 150px; + margin-top: -75px; + text-align: center; +} +div.DTTT_print_info h6 { + font-weight: normal; + font-size: 28px; + line-height: 28px; + margin: 1em; +} +div.DTTT_print_info p { + font-size: 14px; + line-height: 20px; +} +/* + * FixedColumns styles + */ +div.DTFC_LeftHeadWrapper table, +div.DTFC_LeftFootWrapper table, +div.DTFC_RightHeadWrapper table, +div.DTFC_RightFootWrapper table, +table.DTFC_Cloned tr.even { + background-color: white; +} +div.DTFC_RightHeadWrapper table, +div.DTFC_LeftHeadWrapper table { + margin-bottom: 0 !important; + border-top-right-radius: 0 !important; + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} +div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child, +div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child, +div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child, +div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child { + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} +div.DTFC_RightBodyWrapper table, +div.DTFC_LeftBodyWrapper table { + border-top: none; + margin-bottom: 0 !important; +} +div.DTFC_RightBodyWrapper tbody tr:first-child th, +div.DTFC_RightBodyWrapper tbody tr:first-child td, +div.DTFC_LeftBodyWrapper tbody tr:first-child th, +div.DTFC_LeftBodyWrapper tbody tr:first-child td { + border-top: none; +} +div.DTFC_RightFootWrapper table, +div.DTFC_LeftFootWrapper table { + border-top: none; +} +/* Retina Display Hack +=================================================================== */ +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { + table.table thead .sorting { + background: url('../img/sort_both@2x.png') no-repeat center right; + background-size: 19px 19px; + } + table.table thead .sorting_asc { + background: url('../img/sort_asc@2x.png') no-repeat center right; + background-size: 19px 19px; + } + table.table thead .sorting_desc { + background: url('../img/sort_desc@2x.png') no-repeat center right; + background-size: 19px 19px; + } + table.table thead .sorting_asc_disabled { + background: url('../img/sort_asc_disabled@2x.png') no-repeat center right; + background-size: 19px 19px; + } + table.table thead .sorting_desc_disabled { + background: url('../img/sort_desc_disabled@2x.png') no-repeat center right; + background-size: 19px 19px; + } +} +/* Just Gage - Demo Charts +=================================================================== */ +.sz1 { + width: 200px; + height: 160px; +} +.sz0 { + margin: 2em 0 0 0; +} +.sz0 { + width: 100px; + height: 80px; +} +/** + * Nestable + */ +.dd { + position: relative; + display: block; + margin: 0; + padding: 0; + list-style: none; + font-size: 13px; + line-height: 20px; +} +.dd-list { + display: block; + position: relative; + margin: 0; + padding: 0; + list-style: none; +} +.dd-list .dd-list { + padding-left: 30px; +} +.dd-collapsed .dd-list { + display: none; +} +.dd-item, +.dd-empty, +.dd-placeholder { + display: block; + position: relative; + margin: 0; + padding: 0; + min-height: 20px; + font-size: 13px; + line-height: 20px; +} +.dd-handle { + display: block; + height: 30px; + margin: 5px 0; + padding: 4px 10px; + text-decoration: none; + border: 1px solid #dbdee0; + background: #e9ebec; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.dd-handle:hover { + color: #36a9e1; + background: white; +} +.dd-handle .icon { + float: right; + font-size: 16px; + margin-left: 10px; +} +.dd-handle .icon:hover { + text-decoration: none; +} +.dd-item > button { + display: block; + position: relative; + cursor: pointer; + float: left; + width: 25px; + height: 20px; + margin: 5px 0; + padding: 0; + text-indent: 100%; + white-space: nowrap; + overflow: hidden; + border: 0; + background: transparent; + font-size: 12px; + line-height: 1; + text-align: center; + font-weight: bold; +} +.dd-item > button:before { + content: '+'; + display: block; + position: absolute; + width: 100%; + text-align: center; + text-indent: 0; +} +.dd-item > button[data-action="collapse"]:before { + content: '-'; +} +.dd-placeholder, +.dd-empty { + margin: 5px 0; + padding: 0; + min-height: 30px; + background: #f2fbff; + border: 1px dashed #b6bcbf; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.dd-empty { + border: 1px dashed #bbb; + min-height: 100px; + background-color: #e5e5e5; + background-size: 60px 60px; + background-position: 0 0, 30px 30px; +} +.dd-dragel { + position: absolute; + pointer-events: none; + z-index: 9999; +} +.dd-dragel > .dd-item .dd-handle { + margin-top: 0; +} +.dd-dragel .dd-handle { + -webkit-box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1); + box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1); +} +/** + * Nestable Extras + */ +.nestable-lists { + display: block; + clear: both; + padding: 30px 0; + width: 100%; + border: 0; + border-top: 2px solid #ddd; + border-bottom: 2px solid #ddd; +} +#nestable-menu { + padding: 0; + margin: 20px 0; +} +#nestable-output, +#nestable2-output { + width: 100%; + height: 7em; + font-size: 0.75em; + line-height: 1.333333em; + font-family: Consolas, monospace; + padding: 5px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +#nestable2 .dd-handle { + color: white; + border: 1px solid #b2b8bd; + background: #b2b8bd; +} +#nestable2 .dd-handle:hover { + border: 1px solid #34383c; + background: #34383c; +} +#nestable2 .dd-item > button:before { + color: #fff; +} +@media only screen and (min-width: 700px) { + .dd { + float: left; + width: 48%; + } + .dd + .dd { + margin-left: 2%; + } +} +.dd-hover > .dd-handle { + background: #2ea8e5 !important; +} +/** + * Nestable Draggable Handles + */ +.dd3-content { + display: block; + height: 30px; + margin: 5px 0; + padding: 5px 10px 5px 40px; + text-decoration: none; + font-weight: bold; + border: 1px solid #dbdee0; + background: #e9ebec; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.dd3-content:hover { + color: #36a9e1; + background: #fff; +} +.dd-dragel > .dd3-item > .dd3-content { + margin: 0; +} +.dd3-item > button { + margin-left: 30px; +} +.dd3-handle { + position: absolute; + margin: 0; + left: 0; + top: 0; + cursor: pointer; + width: 30px; + white-space: nowrap; + overflow: hidden; + border: 1px solid #dbdee0; + background: #dbdee0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + color: white; +} +.dd3-handle:hover { + background: #b2b8bd; + color: white; +} +/* FuelUX Wizard +=================================================================== */ +.wizard { + *zoom: 1; + position: relative; + overflow: hidden; + margin-bottom: 20px; +} +.wizard:before, +.wizard:after { + display: table; + content: ""; + line-height: 0; +} +.wizard:after { + clear: both; +} +.wizard ul { + list-style: none outside none; + padding: 0; + margin: 0; + width: 4000px; +} +.wizard ul li { + float: left; + margin: 0; + padding: 0 20px 0 30px; + height: 40px; + line-height: 40px; + position: relative; + background: #f7f7f8; + color: #b2b8bd; + font-size: 16px; + cursor: default; +} +.wizard ul li:first-child { + -webkit-border-radius: 2px 0 0 2px; + -moz-border-radius: 2px 0 0 2px; + border-radius: 2px 0 0 2px; +} +.wizard ul li:last-child { + -webkit-border-radius: 0 2px 2px 0; + -moz-border-radius: 0 2px 2px 0; + border-radius: 0 2px 2px 0; +} +.wizard ul li .chevron { + border: 48px solid transparent; + border-left: 28px solid white; + border-right: 0; + display: block; + position: absolute; + right: -14px; + top: -28px; + z-index: 1; +} +.wizard ul li .chevron:before { + border: 48px solid transparent; + border-left: 28px solid #f7f7f8; + border-right: 0; + content: ""; + display: block; + position: absolute; + right: 5px; + top: -48px; +} +.wizard ul li.complete { + background: #bdea74; + color: white; +} +.wizard ul li.complete:hover { + background: #e7eff8; + cursor: pointer; +} +.wizard ul li.complete:hover .chevron:before { + border-left: 28px solid #e7eff8; +} +.wizard ul li.complete .chevron:before { + border-left: 28px solid #bdea74; +} +.wizard ul li.active { + background: #b2b8bd; + color: white; +} +.wizard ul li.active .chevron:before { + border-left: 28px solid #b2b8bd; +} +.wizard ul li .badge { + margin-right: 8px; +} +.wizard ul li:first-child { + border-radius: 4px 0 0 4px; + padding-left: 20px; +} +.wizard .actions { + z-index: 1000; + position: absolute; + right: 0; + line-height: 46px; + float: right; + padding-left: 15px; + padding-right: 15px; + vertical-align: middle; +} +.wizard .actions a { + line-height: 45px; + font-size: 12px; + margin-right: 8px; +} +.wizard .actions .btn-prev i { + margin-right: 5px; +} +.wizard .actions .btn-next i { + margin-left: 5px; +} +.step-content .step-pane { + display: none; +} +.step-content .active { + display: block; +} +.step-content .active .btn-group .active { + display: inline-block; +} +/* + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.datepicker { + padding: 4px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + direction: ltr; + /*.dow { + border-top: 1px solid #ddd !important; + }*/ + +} +.datepicker-inline { + width: 220px; +} +.datepicker.datepicker-rtl { + direction: rtl; +} +.datepicker.datepicker-rtl table tr td span { + float: right; +} +.datepicker-dropdown { + top: 0; + left: 0; +} +.datepicker-dropdown:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-top: 0; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; +} +.datepicker-dropdown:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid white; + border-top: 0; + position: absolute; +} +.datepicker-dropdown.datepicker-orient-left:before { + left: 6px; +} +.datepicker-dropdown.datepicker-orient-left:after { + left: 7px; +} +.datepicker-dropdown.datepicker-orient-right:before { + right: 6px; +} +.datepicker-dropdown.datepicker-orient-right:after { + right: 7px; +} +.datepicker-dropdown.datepicker-orient-top:before { + top: -7px; +} +.datepicker-dropdown.datepicker-orient-top:after { + top: -6px; +} +.datepicker-dropdown.datepicker-orient-bottom:before { + bottom: -7px; + border-bottom: 0; + border-top: 7px solid #999; +} +.datepicker-dropdown.datepicker-orient-bottom:after { + bottom: -6px; + border-bottom: 0; + border-top: 6px solid white; +} +.datepicker > div { + display: none; +} +.datepicker.days div.datepicker-days { + display: block; +} +.datepicker.months div.datepicker-months { + display: block; +} +.datepicker.years div.datepicker-years { + display: block; +} +.datepicker table { + margin: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.datepicker td, +.datepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border: none; +} +.table-striped .datepicker table tr td, +.table-striped .datepicker table tr th { + background-color: transparent; +} +.datepicker table tr td.day:hover { + background: #eee; + cursor: pointer; +} +.datepicker table tr td.old, +.datepicker table tr td.new { + color: #34383c; +} +.datepicker table tr td.disabled, +.datepicker table tr td.disabled:hover { + background: none; + color: #f9f9f9; + cursor: default; +} +.datepicker table tr td.today, +.datepicker table tr td.today:hover, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today.disabled:hover { + background: #36a9e1; + color: #000; +} +.datepicker table tr td.today:hover:hover { + color: #000; +} +.datepicker table tr td.today.active:hover { + color: #fff; +} +.datepicker table tr td.range, +.datepicker table tr td.range:hover, +.datepicker table tr td.range.disabled, +.datepicker table tr td.range.disabled:hover { + background: #eee; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.datepicker table tr td.range.today, +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today.disabled:hover { + background: #f3c17a; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.datepicker table tr td.selected, +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected.disabled:hover { + background: #f9f9f9; + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.active, +.datepicker table tr td.active:hover, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active.disabled:hover { + background: #36a9e1; + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.datepicker table tr td span:hover { + background: #eee; +} +.datepicker table tr td span.disabled, +.datepicker table tr td span.disabled:hover { + background: none; + color: #f9f9f9; + cursor: default; +} +.datepicker table tr td span.active, +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active.disabled:hover { + background: #36a9e1; + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td span.old, +.datepicker table tr td span.new { + color: #f9f9f9; +} +.datepicker th.datepicker-switch { + width: 145px; +} +.datepicker thead tr:first-child th, +.datepicker tfoot tr th { + cursor: pointer; +} +.datepicker thead tr:first-child th:hover, +.datepicker tfoot tr th:hover { + background: #eee; +} +.datepicker .cw { + font-size: 10px; + width: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; +} +.datepicker thead tr:first-child th.cw { + cursor: default; + background-color: transparent; +} +.input-append.date .add-on i, +.input-prepend.date .add-on i { + display: block; + cursor: pointer; + width: 16px; + height: 16px; +} +.input-daterange input { + text-align: center; +} +.input-daterange input:first-child { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-daterange input:last-child { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-daterange .add-on { + display: inline-block; + width: auto; + min-width: 16px; + height: 18px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + text-align: center; + text-shadow: 0 1px 0 white; + vertical-align: middle; + background-color: #eee; + border: 1px solid #ccc; + margin-left: -5px; + margin-right: -5px; +} +/* + * Timepicker Component for Twitter Bootstrap + * + * Copyright 2013 Joris de Wit + * + * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +.bootstrap-timepicker { + position: relative; +} +.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu { + left: auto; + right: 0; +} +.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before { + left: auto; + right: 12px; +} +.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after { + left: auto; + right: 13px; +} +.bootstrap-timepicker .input-group-addon { + cursor: pointer; + -webkit-border-radius: 4px 0px 0px 4px !important; + border-radius: 4px 0px 0px 4px !important; + border-right: 0px; +} +.bootstrap-timepicker-widget.dropdown-menu { + padding: 2px 3px 2px 2px; + margin-left: 54px; +} +.bootstrap-timepicker-widget.dropdown-menu.open { + display: inline-block; +} +.bootstrap-timepicker-widget.dropdown-menu:before { + border-bottom: 7px solid rgba(0, 0, 0, 0.2); + border-left: 7px solid transparent; + border-right: 7px solid transparent; + content: ""; + display: inline-block; + left: 9px; + position: absolute; + top: -7px; +} +.bootstrap-timepicker-widget.dropdown-menu:after { + border-bottom: 6px solid #FFFFFF; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + content: ""; + display: inline-block; + left: 10px; + position: absolute; + top: -6px; +} +.bootstrap-timepicker-widget a.btn, +.bootstrap-timepicker-widget input { + border-radius: 4px; +} +.bootstrap-timepicker-widget table { + width: 100%; + margin: 0; +} +.bootstrap-timepicker-widget table td { + text-align: center; + height: 30px; + margin: 0; + padding: 2px; +} +.bootstrap-timepicker-widget table td:not(.separator) { + min-width: 30px; +} +.bootstrap-timepicker-widget table td span { + width: 100%; +} +.bootstrap-timepicker-widget table td a { + border: 1px transparent solid; + width: 100%; + display: inline-block; + margin: 0; + padding: 8px 0; + outline: 0; + color: #333; +} +.bootstrap-timepicker-widget table td a:hover { + text-decoration: none; + background-color: #eee; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border-color: #ddd; +} +.bootstrap-timepicker-widget table td a i { + margin-top: 2px; +} +.bootstrap-timepicker-widget table td input { + width: 25px; + margin: 0; + text-align: center; + border: 1px solid #b2b8bd; +} +.bootstrap-timepicker-widget .modal-content { + padding: 4px; +} +@media (min-width: 767px) { + .bootstrap-timepicker-widget.modal { + width: 200px; + margin-left: -100px; + } +} +@media (max-width: 767px) { + .bootstrap-timepicker { + width: 100%; + } + .bootstrap-timepicker .dropdown-menu { + width: 100%; + } +} +/* + * Stylesheet for the Date Range Picker, for use with Bootstrap 3.x + * + * Copyright 2013 Dan Grossman ( http://www.dangrossman.info ) + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Built for http://www.improvely.com + */ +.daterangepicker.dropdown-menu { + max-width: none; + z-index: 3000; +} +.daterangepicker.opensleft .ranges, +.daterangepicker.opensleft .calendar { + float: left; + margin: 4px; +} +.daterangepicker.opensright .ranges, +.daterangepicker.opensright .calendar { + float: right; + margin: 4px; +} +.daterangepicker .ranges { + width: 160px; + text-align: left; +} +.daterangepicker .ranges .range_inputs > div { + float: left; +} +.daterangepicker .ranges .range_inputs > div:nth-child(2) { + padding-left: 11px; +} +.daterangepicker .calendar { + display: none; + max-width: 270px; +} +.daterangepicker .calendar th, +.daterangepicker .calendar td { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + white-space: nowrap; + text-align: center; + min-width: 32px; +} +.daterangepicker .ranges label { + color: #333; + display: block; + font-size: 11px; + font-weight: normal; + height: 20px; + line-height: 20px; + margin-bottom: 2px; + text-shadow: #fff 1px 1px 0px; + text-transform: uppercase; + width: 74px; +} +.daterangepicker .ranges input { + font-size: 11px; +} +.daterangepicker .ranges .input-mini { + background-color: #eee; + border: 1px solid #ccc; + border-radius: 4px; + color: #555; + display: block; + font-size: 11px; + height: 30px; + line-height: 30px; + vertical-align: middle; + margin: 0 0 10px 0; + padding: 0 6px; + width: 74px; +} +.daterangepicker .ranges ul { + list-style: none; + margin: 0; + padding: 0; +} +.daterangepicker .ranges li { + font-size: 13px; + background: #f5f5f5; + border: 1px solid #f5f5f5; + color: #08c; + padding: 3px 12px; + margin-bottom: 8px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + cursor: pointer; +} +.daterangepicker .ranges li.active, +.daterangepicker .ranges li:hover { + background: #08c; + border: 1px solid #08c; + color: #fff; +} +.daterangepicker .calendar-date { + border: 1px solid #ddd; + padding: 4px; + border-radius: 4px; + background: #fff; +} +.daterangepicker .calendar-time { + text-align: center; + margin: 8px auto 0 auto; + line-height: 30px; +} +.daterangepicker { + position: absolute; + background: #fff; + top: 100px; + left: 20px; + padding: 4px; + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.daterangepicker.opensleft:before { + position: absolute; + top: -7px; + right: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} +.daterangepicker.opensleft:after { + position: absolute; + top: -6px; + right: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; + content: ''; +} +.daterangepicker.opensright:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} +.daterangepicker.opensright:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; + content: ''; +} +.daterangepicker table { + width: 100%; + margin: 0; +} +.daterangepicker td, +.daterangepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + cursor: pointer; + white-space: nowrap; +} +.daterangepicker td.off { + color: #999; +} +.daterangepicker td.disabled { + color: #999; +} +.daterangepicker td.available:hover, +.daterangepicker th.available:hover { + background: #eee; +} +.daterangepicker td.in-range { + background: #ebf4f8; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.daterangepicker td.active, +.daterangepicker td.active:hover { + background-color: #357ebd; + border-color: #3071a9; + color: #fff; +} +.daterangepicker td.week, +.daterangepicker th.week { + font-size: 80%; + color: #ccc; +} +.daterangepicker select.monthselect, +.daterangepicker select.yearselect { + font-size: 12px; + padding: 1px; + height: auto; + margin: 0; + cursor: default; +} +.daterangepicker select.monthselect { + margin-right: 2%; + width: 56%; +} +.daterangepicker select.yearselect { + width: 40%; +} +.daterangepicker select.hourselect, +.daterangepicker select.minuteselect, +.daterangepicker select.ampmselect { + width: 50px; + margin-bottom: 0; +} +/* + * Colorpicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.colorpicker-saturation { + width: 100px; + height: 100px; + background-image: url(../img/saturation.png); + cursor: crosshair; + float: left; +} +.colorpicker-saturation i { + display: block; + height: 5px; + width: 5px; + border: 1px solid #000; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + position: absolute; + top: 0; + left: 0; + margin: -4px 0 0 -4px; +} +.colorpicker-saturation i b { + display: block; + height: 5px; + width: 5px; + border: 1px solid #fff; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; +} +.colorpicker-hue, +.colorpicker-alpha { + width: 15px; + height: 100px; + float: left; + cursor: row-resize; + margin-left: 4px; + margin-bottom: 4px; +} +.colorpicker-hue i, +.colorpicker-alpha i { + display: block; + height: 1px; + background: #000; + border-top: 1px solid #fff; + position: absolute; + top: 0; + left: 0; + width: 100%; + margin-top: -1px; +} +.colorpicker-hue { + background-image: url(../img/hue.png); +} +.colorpicker-alpha { + background-image: url(../img/alpha.png); + display: none; +} +.colorpicker { + *zoom: 1; + top: 0; + left: 0; + padding: 4px; + min-width: 120px; + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.colorpicker:before, +.colorpicker:after { + display: table; + content: ""; + line-height: 0; +} +.colorpicker:after { + clear: both; +} +.colorpicker:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 6px; +} +.colorpicker:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid white; + position: absolute; + top: -6px; + left: 7px; +} +.colorpicker div { + position: relative; +} +.colorpicker.alpha { + min-width: 140px; +} +.colorpicker.alpha .colorpicker-alpha { + display: block; +} +.colorpicker-color { + height: 10px; + margin-top: 5px; + clear: both; + background-image: url(../img/alpha.png); + background-position: 0 100%; +} +.colorpicker-color div { + height: 10px; +} +.input-append.color .add-on i, +.input-prepend.color .add-on i { + display: block; + cursor: pointer; + width: 16px; + height: 16px; +} +.input-group.color .input-group-addon i { + display: block; + cursor: pointer; + width: 13px; +} +/* Page: Inbox +=================================================================== */ +.inbox .inbox-menu { + background: #e9ebec; + border-right: 1px solid #dbdee0; + padding-top: 30px; +} +.inbox .inbox-menu .btn { + width: 100%; +} +.inbox .inbox-menu ul { + margin-top: 30px; + padding: 0; + list-style: none; +} +.inbox .inbox-menu ul li { + height: 30px; + margin: 0 -15px; + padding: 5px 15px; + position: relative; +} +.inbox .inbox-menu ul li:hover, +.inbox .inbox-menu ul li.active { + background: #dbdee0; +} +.inbox .inbox-menu ul li.title { + margin: 20px -15px -10px -15px; + text-transform: uppercase; + font-size: 10px; + color: #b2b8bd; +} +.inbox .inbox-menu ul li.title:hover { + background: transparent; +} +.inbox .inbox-menu ul li a { + display: block; + width: 100%; + text-decoration: none; + color: #34383c; +} +.inbox .inbox-menu ul li a i { + margin-right: 10px; +} +.inbox .inbox-menu ul li a .label { + position: absolute; + top: 10px; + right: 15px; + display: block; + min-width: 14px; + height: 14px; + padding: 2px; +} +.inbox .buttons { + margin: 30px 0; +} +.inbox .buttons .btn, +.inbox .buttons .btn-group .btn { + border: 1px solid #dbdee0; +} +.inbox .buttons .btn-group .caret { + border-top-color: #7c848d; + margin-top: -4px; + margin-left: 5px; +} +.inbox .messages { + background: white; + margin: 0; + border-right: 1px solid #dbdee0; +} +.inbox ul.messages-list { + list-style: none; + padding: 0; +} +.inbox ul.messages-list li { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + cursor: pointer; + margin-bottom: 10px; + padding: 10px; +} +.inbox ul.messages-list li.unread .header, +.inbox ul.messages-list li.unread .title { + font-weight: bold; +} +.inbox ul.messages-list li.active { + background: #e9ebec; + border: 1px solid #dbdee0; + padding: 9px; +} +.inbox ul.messages-list li.active .action { + color: #c0c4c8; +} +.inbox ul.messages-list li .header { + margin: 0 0 5px 0; +} +.inbox ul.messages-list li .header .from { + width: 49.9%; + white-space: nowrap; + overflow: hidden !important; + text-overflow: ellipsis; +} +.inbox ul.messages-list li .header .date { + width: 50%; + text-align: right; + float: right; +} +.inbox ul.messages-list li .title { + margin: 0 0 5px 0; + white-space: nowrap; + overflow: hidden !important; + text-overflow: ellipsis; +} +.inbox ul.messages-list li .description { + font-size: 12px; + padding-left: 29px; +} +.inbox ul.messages-list li .action { + display: inline-block; + width: 16px; + text-align: center; + margin-right: 10px; + color: #dbdee0; +} +.inbox ul.messages-list li .action .fa-check-square-o { + margin: 0 -1px 0 1px; +} +.inbox ul.messages-list li .action .fa-square { + float: left; + margin-top: -16px; + margin-left: 4px; + font-size: 11px; + color: white; +} +.inbox ul.messages-list li .action .fa-star.bg { + float: left; + margin-top: -16px; + margin-left: 3px; + font-size: 12px; + color: white; +} +.inbox .message { + margin: 0; + background: white; + border-right: 1px solid #dbdee0; +} +.inbox .message textarea { + color: #34383c !important; +} +.inbox .message .message-title { + padding-top: 10px; + font-weight: bold; + font-size: 14px; +} +.inbox .message .header { + margin: 20px 0 30px 0; + padding: 10px 0 10px 0; + border-top: 1px solid #e9ebec; + border-bottom: 1px solid #e9ebec; +} +.inbox .message .header .avatar { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + height: 34px; + width: 34px; + float: left; + margin-right: 10px; +} +.inbox .message .header i { + margin-top: 1px; +} +.inbox .message .header .from { + display: inline-block; + width: 50%; + font-size: 12px; + margin-top: -2px; + color: #b2b8bd; +} +.inbox .message .header .from span { + display: block; + font-size: 14px; + font-weight: bold; + color: #34383c; +} +.inbox .message .header .date { + display: inline-block; + width: 29%; + text-align: right; + float: right; + font-size: 12px; + margin-top: 18px; +} +.inbox .message .attachments { + border-top: 3px solid #f9f9f9; + border-bottom: 3px solid #f9f9f9; + padding: 10px 0px; + margin-bottom: 20px; + font-size: 12px; +} +.inbox .message .attachments ul { + list-style: none; + margin: 0 0 0 -40px; +} +.inbox .message .attachments ul li { + margin: 10px 0; +} +.inbox .message .attachments ul li .label { + padding: 2px 4px; +} +.inbox .message .attachments ul li span.quickMenu { + float: right; + text-align: right; +} +.inbox .message .attachments ul li span.quickMenu .glyphicons { + padding: 5px 0 5px 25px; +} +.inbox .message .attachments ul li span.quickMenu .glyphicons:before { + font-size: 14px; + margin: -2px 0px 0px 5px; + color: #b2b8bd; +} +.inbox .contacts { + background: #e9ebec; + padding-top: 30px; +} +.inbox .contacts .btn { + width: 100%; + margin-bottom: 30px; +} +.inbox .contacts ul { + padding: 0; + list-style: none; +} +.inbox .contacts ul li { + height: 30px; + margin: 0 -15px; + padding: 5px 15px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis !important; + position: relative; + cursor: pointer; +} +.inbox .contacts ul li .label { + display: inline-block; + width: 6px; + height: 6px; + padding: 0; + margin: 0 5px 2px 0px; +} +.inbox .contacts ul li:hover { + background: #dbdee0; +} +/* Page: Invoice +=================================================================== */ +.invoice .header .well p { + padding: 0; + margin: 0px 0; +} +.invoice table { + margin-bottom: 20px !important; +} +/* Page: Tasks +=================================================================== */ +.page-todo .tasks { + background: white; + padding: 0; + border-right: 1px solid #dbdee0; + margin: -30px 15px -30px -15px; +} +.page-todo .task-list { + padding: 30px 15px; + height: 100%; +} +.page-todo .graph { + height: 100%; +} +.page-todo .priority.high { + background: #ffeded; + margin-bottom: 1px; +} +.page-todo .priority.high span { + background: #ff5454; + padding: 2px 10px; + color: white; + display: inline-block; + font-size: 12px; +} +.page-todo .priority.medium { + background: #fef8eb; + margin-bottom: 1px; +} +.page-todo .priority.medium span { + background: #fabb3d; + padding: 2px 10px; + color: white; + display: inline-block; + font-size: 12px; +} +.page-todo .priority.low { + background: #e4f5dc; + margin-bottom: 1px; +} +.page-todo .priority.low span { + background: #78cd51; + padding: 2px 10px; + color: white; + display: inline-block; + font-size: 12px; +} +.page-todo .task { + border-bottom: 1px solid #f9f9f9; + margin-bottom: 1px; + position: relative; +} +.page-todo .task .desc { + display: inline-block; + width: 75%; + padding: 10px 10px; + font-size: 12px; +} +.page-todo .task .desc .title { + font-size: 18px; + margin-bottom: 5px; +} +.page-todo .task .time { + display: inline-block; + width: 15%; + padding: 10px 10px 10px 0px; + font-size: 12px; + text-align: right; + position: absolute; + top: 0px; + right: 0px; +} +.page-todo .task .time .date { + font-size: 18px; + margin-bottom: 5px; +} +.page-todo .task.last { + border-bottom: 1px solid transparent; +} +.page-todo .task.high { + border-left: 2px solid #ff5454; +} +.page-todo .task.medium { + border-left: 2px solid #fabb3d; +} +.page-todo .task.low { + border-left: 2px solid #78cd51; +} +.page-todo .timeline { + width: auto; + height: 100%; + margin: 20px auto; + position: relative; +} +.page-todo .timeline:before { + position: absolute; + content: ''; + height: 100%; + width: 4px; + background: #e9ebec; + left: 50%; + margin-left: -2px; +} +.page-todo .timeslot { + display: inline-block; + position: relative; + width: 100%; + margin: 5px 0px; +} +.page-todo .timeslot .task { + position: absolute; + width: 42%; + padding-right: 18px; + display: block; + height: auto; + border: none; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.page-todo .timeslot .task span { + border: 2px solid #67c2ef; + background: #f1fafe; + padding: 5px; + display: block; + font-size: 11px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.page-todo .timeslot .task span span.details { + font-size: 16px; + margin-bottom: 10px; +} +.page-todo .timeslot .task span span.remaining { + font-size: 14px; +} +.page-todo .timeslot .task span span { + border: 0px; + background: transparent; + padding: 0px; +} +.page-todo .timeslot .task .arrow { + position: absolute; + top: 6px; + right: 0px; + height: 20px; + width: 20px; + background: url(../img/timeline-left-arrow.png) no-repeat; +} +.page-todo .timeslot .icon { + position: absolute; + border: 2px solid #b2b8bd; + background: #34383c; + -webkit-border-radius: 50em; + -moz-border-radius: 50em; + border-radius: 50em; + height: 30px; + width: 30px; + left: 50%; + margin-left: -16px; + color: white; + font-size: 14px; + line-height: 30px; + text-align: center; + text-shadow: none; + z-index: 2; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.page-todo .timeslot .time { + background: #e9ebec; + position: absolute; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + top: 1px; + left: 50%; + padding: 5px 10px 5px 40px; + z-index: 1; + margin-top: 1px; +} +.page-todo .timeslot.alt .task { + left: auto; + right: -20px; + padding-left: 18px; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.page-todo .timeslot.alt .task .arrow { + position: absolute; + top: 6px; + left: 0px; + height: 20px; + width: 20px; + background: url(../img/timeline-right-arrow.png) no-repeat; +} +.page-todo .timeslot.alt .time { + top: 1px; + left: auto; + right: 50%; + padding: 5px 40px 5px 10px; +} +/* Higher than 992 (desktop devices) +====================================================================== */ +@media only screen and (min-width: 992px) and (max-width: 1199px) { + .page-todo task .desc { + display: inline-block; + width: 70%; + padding: 10px 10px; + font-size: 12px; + } + .page-todo task .desc .title { + font-size: 16px; + margin-bottom: 5px; + } + .page-todo task .time { + display: inline-block; + float: right; + width: 20%; + padding: 10px 10px; + font-size: 12px; + text-align: right; + } + .page-todo task .time .date { + font-size: 16px; + margin-bottom: 5px; + } +} +/* Tablet Portrait (devices and browsers) +====================================================================== */ +@media only screen and (min-width: 768px) and (max-width: 991px) { + .page-todo .task { + border-bottom: 1px solid #f9f9f9; + margin-bottom: 1px; + } + .page-todo .task .desc { + display: inline-block; + width: 65%; + padding: 10px 10px; + font-size: 10px; + margin-right: -20px; + } + .page-todo .task .desc .title { + font-size: 14px; + margin-bottom: 5px; + } + .page-todo .task .time { + display: inline-block; + float: right; + width: 25%; + padding: 10px 10px; + font-size: 10px; + text-align: right; + } + .page-todo .task .time .date { + font-size: 14px; + margin-bottom: 5px; + } + .page-todo .timeslot .task span { + border: 2px solid #67c2ef; + background: rgba(103, 194, 239, 0.1); + padding: 5px; + display: block; + font-size: 10px; + } + .page-todo .timeslot .task span span { + border: 0px; + background: transparent; + padding: 0px; + } + .page-todo .timeslot .task span span.details { + font-size: 14px; + margin-bottom: 0px; + } + .page-todo .timeslot .task span span.remaining { + font-size: 12px; + } +} +/* All Mobile Sizes (devices and browser) +====================================================================== */ +@media only screen and (max-width: 767px) { + .page-todo .tasks { + position: relative; + margin: 0px !important; + } + .page-todo .graph { + position: relative; + margin: 0px !important; + } + .page-todo .task { + border-bottom: 1px solid #f9f9f9; + margin-bottom: 1px; + } + .page-todo .task .desc { + display: inline-block; + width: 65%; + padding: 10px 10px; + font-size: 10px; + margin-right: -20px; + } + .page-todo .task .desc .title { + font-size: 14px; + margin-bottom: 5px; + } + .page-todo .task .time { + display: inline-block; + float: right; + width: 25%; + padding: 10px 10px; + font-size: 10px; + text-align: right; + } + .page-todo .task .time .date { + font-size: 14px; + margin-bottom: 5px; + } + .page-todo .timeslot .task span { + padding: 5px; + display: block; + font-size: 10px; + } + .page-todo .timeslot .task span span { + border: 0px; + background: transparent; + padding: 0px; + } + .page-todo .timeslot .task span span.details { + font-size: 14px; + margin-bottom: 0px; + } + .page-todo .timeslot .task span span.remaining { + font-size: 12px; + } +} +/* Page: Invoice +=================================================================== */ +.profile-image { + width: 100%; + border: 5px solid white; + outline: 1px solid #dbdee0; +} +.profile h3 { + padding: 0 5px; +} +ul.profile-details { + margin-top: 10px; + padding: 0 5px; + list-style: none; + color: #7c848d; +} +ul.profile-details li { + position: relative; + margin: 0 0 20px 0; + padding-left: 22px; +} +ul.profile-details li div { + color: #b2b8bd; +} +ul.profile-details li div i { + position: absolute; + top: 4px; + left: -5px; + color: #ced1d4; + width: 20px; + text-align: center; +} +ul.profile-details li input[type="text"] { + color: black !important; +} +ul.friends-list { + padding: 0; + list-style: none; +} +ul.friends-list li { + width: auto; + min-width: 170px; + margin-bottom: 20px; + border: 1px solid #e9ebec; + background: #f7f7f8; + float: left; + padding: 5px; + margin: 0px 0px 5px 5px; + white-space: nowrap; + overflow: hidden; +} +ul.friends-list li:last-child { + margin-bottom: 0; +} +ul.friends-list li .avatar { + float: left; + margin-right: 10px; + width: 40px; +} +ul.friends-list li .avatar img { + width: 40px; +} +ul.friends-list li a { + display: inline-block; + font-size: 22px; + line-height: 8px; + text-decoration: none; + color: #b2b8bd; +} +/* Login Box & Register Box +=================================================================== */ +.login-box, +.register-box { + width: 400px; + padding: 20px; + margin: 100px auto; + background: #fff; +} +.login-box .header, +.register-box .header { + background: #34383c; + color: white; + text-align: center; + margin: -20px -20px 20px -20px; + padding: 15px; + text-transform: uppercase; +} +.login-box form.login input[type="text"], +.register-box form.login input[type="text"], +.login-box form.login input[type="password"], +.register-box form.login input[type="password"] { + border-right: none !important; + -webkit-border-radius: 2px 0 0 2px; + -moz-border-radius: 2px 0 0 2px; + border-radius: 2px 0 0 2px; +} +.login-box form.login .input-group-addon, +.register-box form.login .input-group-addon { + height: 0px !important; + border: 1px solid #e9ebec !important; + background: white; + -webkit-border-radius: 0 2px 2px 0; + -moz-border-radius: 0 2px 2px 0; + border-radius: 0 2px 2px 0; + border-left: 1px none !important; + margin-left: -1px !important; +} +.login-box label, +.register-box label { + margin: 10px 5px -10px 5px; +} +.login-box input[type="text"], +.register-box input[type="text"], +.login-box input[type="password"], +.register-box input[type="password"] { + border: 1px solid #e9ebec; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; + padding: 0px 10px; + height: 40px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.login-box input[type="text"]:focus, +.register-box input[type="text"]:focus, +.login-box input[type="password"]:focus, +.register-box input[type="password"]:focus { + outline: none; +} +.login-box .confirm, +.register-box .confirm { + position: relative; + margin: 20px 0 10px -15px; +} +.login-box .confirm label, +.register-box .confirm label { + position: absolute; + top: -9px; + left: 30px; +} +.login-box form.register .input-group-addon, +.register-box form.register .input-group-addon { + height: 0px !important; + width: 35%; + border: 1px solid #e9ebec !important; + background: #e9ebec !important; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + border-radius: 0px; +} +.login-box button, +.register-box button { + margin: 15px 0px !important; +} +/* Price Tables +=================================================================== */ +.price-table.type1 { + margin-top: 22px; + padding-left: 1px; +} +.price-table.type1 ul { + position: relative; + z-index: 1; + list-style: none; + float: left; + margin: 0px -1px 0px -1px; + padding: 0px; + text-align: center; + border: 1px solid #dbdee0; + background: #f3f3f3; +} +.price-table.type1 ul li:nth-child(2n+1) { + background: #e9ebec; +} +.price-table.type1 ul li.price { + background: #34383c; + color: white; + font-size: 18px; + font-weight: bold; + text-shadow: none; + padding: 20px 0px; + height: 58px; +} +.price-table.type1 ul li.strike { + text-decoration: line-through; +} +.price-table.type1 ul li { + font-size: 12px; + text-shadow: none; + padding: 10px 0px; +} +.price-table.type1 ul li span { + font-weight: bold; +} +.price-table.type1 ul.best-option { + border: 3px solid #36a9e1; + margin: -27px -3px 0px -3px; + z-index: 2; +} +.price-table.type1 ul.best-option li.header { + font-size: 16px; + font-weight: bold; + padding: 20px 0px; + position: relative; + overflow: hidden; +} +.price-table.type1 ul.best-option li.header span { + font-size: 10px; + line-height: 12px; + position: absolute; + top: -20px; + left: -141px; + background: #36a9e1; + color: white; + padding: 30px 130px 5px 130px; + -webkit-transform: rotate(315deg); + -moz-transform: rotate(315deg); + -ms-transform: rotate(315deg); + -o-transform: rotate(315deg); +} +.price-table.type1 ul.best-option li.price { + font-size: 24px; + font-weight: bold; + padding: 20px 0px; + background: #36a9e1; +} +.price-table.type2 { + margin-top: 22px; + padding-left: 1px; +} +.price-table.type2 ul { + position: relative; + z-index: 1; + list-style: none; + float: left; + margin: 0px -1px 0px -1px; + padding: 0px; + text-align: center; + border: 1px solid #ced1d4; + background: white; +} +.price-table.type2 ul li.header { + background: #b2b8bd; + color: white; + font-size: 20px; + padding-bottom: 70px; + margin-bottom: 60px; +} +.price-table.type2 ul li.price { + background: #b2b8bd; + color: white; + font-size: 40px; + font-weight: bold; + padding: 26px 0px; + border: 4px solid #e9ebec; + -webkit-border-radius: 50em; + -moz-border-radius: 50em; + border-radius: 50em; + display: inline-block; + height: 116px; + width: 116px; + top: 45px; + left: 50%; + margin-left: -54px; + position: absolute; +} +.price-table.type2 ul li.price span { + font-size: 20px; +} +.price-table.type2 ul li.strike { + text-decoration: line-through; +} +.price-table.type2 ul li { + font-size: 12px; + padding: 10px 0px; + border-bottom: 1px solid #e9ebec; + background: white; +} +.price-table.type2 ul li span { + font-weight: bold; +} +.price-table.type2 ul li.select { + position: relative; + background: #b2b8bd; + padding: 0px; +} +.price-table.type2 ul li.select a { + color: white; + font-weight: 700; + font-size: 14px; + text-decoration: none; + display: block; + width: 100%; + height: 100%; + padding: 10px 0px; +} +.price-table.type2 ul li.select:before { + content: ''; + position: absolute; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-bottom: 10px solid #b2b8bd; + top: -10px; + left: 50%; + margin-left: -5px; +} +.price-table.type2 ul li.select:hover { + background: #b2b8bd; +} +.price-table.type2 ul li.select:hover:before { + border-bottom: 10px solid #b2b8bd; +} +.price-table.type2 ul.best-option li.header { + font-weight: bold; + position: relative; + background: #92d721; +} +.price-table.type2 ul.best-option li.price { + font-weight: bold; + background: #bdea74; + border: 4px solid #a8e348; +} +.price-table.type2 ul.best-option li.select { + position: relative; + background: #92d721; +} +.price-table.type2 ul.best-option li.select:before { + border-bottom: 10px solid #92d721; +} +.price-table.type2 ul.best-option li.select:hover { + background: #74ab1a; +} +.price-table.type2 ul.best-option li.select:hover:before { + border-bottom: 10px solid #74ab1a; +} +.price-table.five ul { + width: 20%; +} +.price-table.four ul { + width: 25%; +} +.price-table.three ul { + width: 33.333%; +} +.price-table.two ul { + width: 50%; +} +.price-table.one ul { + width: 100%; +} +/* Page 404 & Page 500 +=================================================================== */ +.box-error { + margin-top: 200px; +} +.box-error h1 { + float: left; + font-size: 48px; + margin-right: 20px; +} +.box-error p { + margin-top: -8px; + font-weight: 300; +} +/* Page LockScreen +=================================================================== */ +.login-box-locked { + position: relative; + z-index: 9999; + background: rgba(255, 255, 255, 0.9); + padding: 30px; + border: 1px solid #e9ebec; + margin-top: 250px; +} +.login-box-locked.type2 { + background: rgba(255, 255, 255, 0.7); +} +.login-box-locked img.avatar { + float: left; + width: 120px; + margin-right: 20px; +} +.login-box-locked p { + margin-top: -8px; + font-weight: 300; +} +.login-box-locked a { + display: block; + font-weight: 300; + margin-top: 5px; + font-size: 12px; +} +/* Higher than 1200 (desktop devices) +====================================================================== */ +@media (min-width: 1200px) { + .hidden-xs, + .hidden-sm, + .hidden-md, + .hidden-lg { + display: inline-block !important; + } + a.navbar-brand { + position: absolute; + width: 14.422%; + left: 15px; + } + .navbar-collapse { + max-height: 100%; + } + .container { + width: 100% !important; + } + .container #content { + padding: 30px; + margin: 0; + height: 100%; + width: 85.578%; + } + .container #sidebar-left { + width: 14.422%; + } + .container .breadcrumb { + margin: -30px -30px 30px -30px; + padding: 10px 30px; + } +} +/* Higher than 992 (desktop devices) +====================================================================== */ +@media only screen and (min-width: 992px) and (max-width: 1199px) { + .hidden-xs, + .hidden-sm, + .hidden-md, + .hidden-lg { + display: inline-block !important; + } + a.navbar-brand { + position: absolute; + width: 14.422%; + left: 15px; + } + .navbar-collapse { + max-height: 100%; + } + .container { + width: 100% !important; + } + .container #content { + padding: 30px; + margin: 0; + height: 100%; + width: 85.578%; + } + .container #sidebar-left { + width: 14.422%; + } + .container .breadcrumb { + margin: -30px -30px 30px -30px; + padding: 10px 30px; + } +} +/* Tablet Portrait (devices and browsers) +====================================================================== */ +@media only screen and (min-width: 768px) and (max-width: 991px) { + a#main-menu-toggle { + margin-left: 8.334%; + } + a.navbar-brand { + width: 8.334%; + padding: 8px 0px !important; + position: absolute; + left: 15px; + } + a.navbar-brand span { + font-size: 12px; + } + .navbar-collapse { + max-height: 100%; + } + .container { + width: 100% !important; + } + .container #content { + padding: 30px; + } + .container #sidebar-left { + margin-left: 0px !important; + width: 8.334% !important; + } + .container .breadcrumb { + margin: -30px -30px 30px -30px; + padding: 10px 30px; + } + .sidebar-nav > ul { + margin: -9px -10px; + border: none; + padding-bottom: 1px; + font-size: 18px; + } + .nav.main-menu > li > ul > li, + .nav.main-menu > li > ul > li > ul > li, + .nav.main-menu > li > ul > li > ul > li > ul > li { + width: 100%; + } + .nav.main-menu > li > a > i, + .nav.main-menu > li > ul > li > a > i, + .nav.main-menu > li > ul > li > ul > li > a > i, + .nav.main-menu > li > ul > li > ul > li > ul > li > a > i { + height: 38px; + width: 100%; + padding: 11px 0px; + display: inline-block; + text-align: center; + border-right: 1px solid #dbdee0; + } + .btn-navbar { + display: none !important; + } + .nav-collapse, + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + margin-left: -20px !important; + } + .sidebar-nav { + padding: 0; + margin-bottom: 0; + } +} +/* All Mobile Sizes (devices and browser) +====================================================================== */ +@media only screen and (max-width: 767px) { + body:after, + body:before { + display: none; + } + a.navbar-brand { + margin-bottom: 0px; + } + #search { + margin-left: 10px !important; + } + .hidden-sm { + display: inline-block !important; + } + .navbar-toggle { + position: absolute; + top: -3px; + right: -10px; + z-index: 100; + background: transparent !important; + text-shadow: none !important; + border: none !important; + } + .navbar-toggle .icon-bar { + background: white; + } + .navbar-collapse { + max-height: 300px; + border-top: none; + box-shadow: none; + overflow-x: hidden; + padding-right: 0px; + padding-left: 0px; + } + .header-nav { + display: none; + } + .header-nav li { + float: left; + } + .pull-right { + width: 100%; + margin: 10px auto; + text-align: center; + } + #content { + overflow: hidden; + } + #content .breadcrumb { + margin: -4px -5px 30px -5px; + } + #sidebar-left { + min-height: 0px; + padding: 0 !important; + } + .sidebar-nav { + border-bottom: 1px solid #dbdee0; + } + .sidebar-nav > ul { + margin: 0 0px; + background: #f3f3f3; + } + /* Page: Messages + =================================================================== */ + .message-view { + margin: 0; + } + .price-table-overlay { + width: 100% !important; + overflow-x: scroll; + } + .price-table.five { + width: 1000px; + } + .price-table.four { + width: 800px; + } + .price-table.three { + width: 900px; + } + .price-table.five ul { + width: 200px; + } + .price-table.four ul { + width: 200px; + } + .price-table.three ul { + width: 300px; + } + .price-table.two ul { + width: 50%; + } + .price-table.one ul { + width: 100%; + } +} +/* Mobile Landscape Size to Tablet Portrait (devices and browsers) +====================================================================== */ +@media only screen and (min-width: 480px) and (max-width: 767px) { + body { + padding: 0px; + } + #content { + padding: 5px; + } +} +/* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) +=================================================================== */ +@media only screen and (max-width: 479px) { + body { + padding: 0px; + } + .col-xxs-12 { + width: 100%; + } + a.navbar-brand { + background: transparent; + } + a.navbar-brand:hover { + background: transparent; + } + #search select { + display: none; + } + #search input { + margin-top: 5px; + margin-left: -10px !important; + width: 100% !important; + } + #content { + padding: 5px; + } + .quick-button, + .quick-button-small { + margin-bottom: 20px; + } + .discussions ul li .date { + display: none; + } +} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/style.less b/gridplatform/bootstrap/static/bootstrap/genius/css/style.less new file mode 100644 index 0000000..77a1609 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/style.less @@ -0,0 +1,76 @@ +/*! +* Author: Łukasz Holeczek +* Template: Genius Dashboard - Bootstrap Admin Template +* Version: 1.0.3 +* Bootstrap version: 3.0.3 +* Copyright 2014 creativeLabs +* www: http://bootstrapmaster.com +* mail: lukasz@bootstrapmaster.com +* You can buy this theme on WrapBootstrap: https://wrapbootstrap.com/theme/genius-bootstrap-admin-template-WB0JM6RMD +* You can find our other themes on: https://bootstrapmaster.com +*/ + +// Import External CSS Files +//=================================================================== +@import "less/import.less"; + +// Import LESS Files +//=================================================================== +@import "less/main.less"; +@import "less/colors.less"; +@import "less/mixins.less"; +@import "less/header.less"; +@import "less/navigation.less"; +@import "less/buttons.less"; +@import "less/tabs.less"; +@import "less/forms.less"; +@import "less/notifications_labels.less"; +@import "less/modal.less"; +@import "less/collapse.less"; +@import "less/footer.less"; + +// My Custom Styles +//=================================================================== +@import "less/charts.less"; +@import "less/smallstats.less"; +@import "less/discussions.less"; +@import "less/chat.less"; +@import "less/calendar.less"; +@import "less/dashboard-list.less"; +@import "less/users-list.less"; +@import "less/comments-list.less"; +@import "less/todo.less"; +@import "less/feed.less"; +@import "less/sliders_progress_bars.less"; +@import "less/quick-buttons.less"; +@import "less/circle-stats.less"; +@import "less/others.less"; +@import "less/switch-input.less"; +@import "less/table.less"; +@import "less/skill-bars.less"; + +// Components +//=================================================================== +@import "less/datatables.less"; +@import "less/justgage.less"; +@import "less/nestable.less"; +@import "less/wizard.less"; +@import "less/datepicker.less"; +@import "less/timepicker.less"; +@import "less/daterangepicker.less"; +@import "less/colorpicker.less"; + +// Example Pages +//=================================================================== +@import "less/page-inbox.less"; +@import "less/page-invoice.less"; +@import "less/page-todo.less"; +@import "less/page-profile.less"; +@import "less/page-login-register.less"; +@import "less/page-pricing-tables.less"; +@import "less/page-error.less"; +@import "less/page-lockscreen.less"; + +// Responsive +//=================================================================== +@import "less/responsive.less"; \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/style.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/style.min.css new file mode 100644 index 0000000..988fc03 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/style.min.css @@ -0,0 +1,11 @@ +@import "jquery-ui-1.10.3.custom.css";@import "fullcalendar.css";@import "chosen.css";@import "select2.css";@import "jquery.cleditor.css";@import "jquery.noty.css";@import "noty_theme_default.css";@import "elfinder.min.css";@import "elfinder.theme.css";@import "uploadify.css";@import "jquery.gritter.css";@import "font-awesome.min.css";@import "font-awesome-ie7.min.css";@import "glyphicons.css";@import "halflings.css";@import "dropzone.css";@import "filetypes.css";@import "social.css";@import "xcharts.min.css";@import "jquery.easy-pie-chart.css";@import "icheck/all.css";@import "bootstrap-editable.css";@import url(https://fonts.googleapis.com/css?family=Lato:300);@import url(https://fonts.googleapis.com/css?family=Lato:400);@import url(https://fonts.googleapis.com/css?family=Kaushan+Script);/*! +* Author: Łukasz Holeczek +* Template: Genius Dashboard - Bootstrap Admin Template +* Version: 1.0.3 +* Bootstrap version: 3.0.3 +* Copyright 2014 creativeLabs +* www: http://bootstrapmaster.com +* mail: lukasz@bootstrapmaster.com +* You can buy this theme on WrapBootstrap: https://wrapbootstrap.com/theme/genius-bootstrap-admin-template-WB0JM6RMD +* You can find our other themes on: https://bootstrapmaster.com +*/.no-space [class*="span"]{margin-left:0}.noMarginLeft{margin-left:0!important}.noPadding{padding:0!important}body{background:#e9ebec;color:#34383c;border:0;font-family:'Lato',sans-serif;font-weight:400;margin:0;padding:0;position:relative}body:after{top:0;left:14.422%;margin-left:-1px;position:absolute;content:'';height:100%;width:85.578%;background:#f3f3f3;border-left:1px solid #dbdee0;z-index:0}body:before{content:'';position:absolute;background:#f3f3f3;width:50%;height:100%;top:0;right:0;z-index:0}body.sidebar-minified:after{top:0;left:40px!important;margin-left:-1px;margin-right:40px;position:absolute;content:'';height:100%;background:#f3f3f3;border-left:1px solid #dbdee0;z-index:0}a{color:#34383c}h1{font-size:32px;line-height:32px;font-weight:300}h2{font-size:16px;line-height:16px;font-weight:300}h3{font-size:15px;line-height:15px}h4{font-size:14px;line-height:14px}h5{font-size:13px;line-height:13px}h6{font-size:12px;line-height:12px}#content{padding:20px;position:relative;background:#f3f3f3;z-index:1}#content:before{position:absolute;content:'';height:100%;width:1px;border-left:1px solid #dbdee0;z-index:1;top:0;left:-1px}#content.sidebar-minified{width:100%!important;border-left:40px solid #e9ebec;margin-right:1px!important}#content.full{width:100%!important;margin-left:0!important;margin-right:0!important;border:none!important}.well{border:1px solid #ddd;background-color:#f6f6f6;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.breadcrumb{background:#e9ebec;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;height:40px;position:relative;border-bottom:1px solid #dbdee0}.breadcrumb .choose-date{position:absolute;top:0;right:0;height:40px;width:254px;border:0;border-left:1px solid #dbdee0;padding:3px 10px}.breadcrumb .choose-date .input-group-addon,.breadcrumb .choose-date input{background:transparent;border:0}.breadcrumb .choose-date .input-group-addon{font-size:12px}.breadcrumb .choose-date input{padding:0;font-weight:300}.breadcrumb .choose-date input:focus{outline:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.box{border:1px solid #dbdee0;margin:0 0 30px 0}.box.noOverflow{overflow:hidden}.box .box-header{background:white;color:#34383c;font-size:16px;overflow:hidden;background:#f7f7f8;border-bottom:1px solid #dbdee0;height:40px}.box .box-header h2{float:left;padding:10px 0;margin:0 0 0 20px}.box .box-header h2 i{border-right:1px solid #dbdee0;color:#ced1d4;padding:12px 0;height:40px;width:40px;display:inline-block;text-align:center;margin:-10px 20px -10px -20px;font-size:16px}.box .box-header .box-icon{float:right}.box .box-header .box-icon i{display:inline-block;color:#ced1d4;text-align:center;height:40px;width:40px;padding:12px 0;-webkit-transition:all .1s ease-in-out;-moz-transition:all .1s ease-in-out;-ms-transition:all .1s ease-in-out;-o-transition:all .1s ease-in-out;transition:all .1s ease-in-out;border-left:1px solid #ced1d4;text-decoration:none}.box .box-header .box-icon a{margin-left:-3px!important}.box .box-content{padding:10px;background:white}.box .box-content.no-padding{background:white;padding:1px 0}blockquote{background:url(../img/quote.png) no-repeat 0 10px;font-style:italic;border-left:none;padding:0 0 0 30px}.alert{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.blue{color:#36a9e1}.lightBlue{color:#67c2ef}.green{color:#bdea74}.darkGreen{color:#78cd51}.pink{color:#e84c8a}.orange{color:#fa603d}.lightOrange{color:#fabb3d}.red{color:#ff5454}.yellow{color:#eae874}.white{color:white}.grey{color:#b2b8bd}.backgroundColor.blue{background:#36a9e1}.backgroundColor.lightBlue{background:#67c2ef}.backgroundColor.green{background:#bdea74}.backgroundColor.darkGreen{background:#78cd51}.backgroundColor.pink{background:#e84c8a}.backgroundColor.orange{background:#fa603d}.backgroundColor.lightOrange{background:#fabb3d}.backgroundColor.red{background:#ff5454}.backgroundColor.yellow{background:#eae874}.backgroundColor.white{background:white}.backgroundColor.grey{background:#b2b8bd}.backgroundColorTitle.blue .title{background:#36a9e1}.backgroundColorTitle.lightBlue .title{background:#67c2ef}.backgroundColorTitle.green .title{background:#bdea74}.backgroundColorTitle.darkGreen .title{background:#78cd51}.backgroundColorTitle.pink .title{background:#e84c8a}.backgroundColorTitle.orange .title{background:#fa603d}.backgroundColorTitle.lightOrange .title{background:#fabb3d}.backgroundColorTitle.red .title{background:#ff5454}.backgroundColorTitle.yellow .title{background:#eae874}.backgroundColorTitle.white .title{background:white}.backgroundColorTitle.grey .title{background:#b2b8bd}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}.navbar{margin:0;min-height:40px;border:0;background:#34383c;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;z-index:2}.navbar a{color:#7b7b7b}.navbar a i{margin-top:2px}.navbar a:hover i{opacity:.8;filter:alpha(opacity=80);-ms-filter:"alpha(opacity=80)"}.navbar #search{position:relative;background:#282b2e;height:30px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;margin:5px 0 5px 16%}.navbar #search select{margin:4px 0 0 -11px;height:22px;line-height:22px;background:#585e65;border:0;color:white;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;text-align:center;text-align:-moz-center;text-align:-webkit-center;text-align:-khtml-center;font-size:12px;cursor:pointer;width:30%;-webkit-appearance:none;-moz-appearance:none;text-indent:.01px;text-overflow:'';padding:2px 0}@media screen and (-webkit-min-device-pixel-ratio:0){.navbar #search select{padding:0 15px}}.navbar #search input{margin-left:5px;width:70%;background:transparent;border:0;font-size:12px;color:white}.navbar #search i{position:absolute;top:8px;right:10px;color:white}a.navbar-brand{background:#282b2e;text-align:center;padding:9px 0 10px 0!important}a.navbar-brand span{font-family:'Kaushan Script',cursive;color:#fff;text-shadow:none}a.navbar-brand.noBg{background:#34383c;border-bottom:0}a.navbar-brand:hover{background:#282b2e}.header-nav{position:relative;padding:0;color:#fff!important;background:#000!important}.header-nav .btn{display:inline-block;margin:0;font-size:15px;text-align:center;background:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.header-nav a.btn{position:relative;height:30px;width:40px;background:#40454a;color:#fff!important;text-shadow:none!important;padding:5px 0!important;margin:5px 3px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;font-size:12px}.header-nav a.btn .number{position:absolute;font-size:8px;top:-3px;right:3px}.header-nav a.btn.account{background:transparent;height:40px;width:auto;padding:8px 0 5px 10px!important;margin:0 -15px 0 3px}.header-nav a.btn.account .avatar{width:60px;float:right}.header-nav a.btn.account .avatar img{margin:-13px -10px -14px 10px;height:40px;width:40px}.header-nav a.btn:hover{background:#282b2e}.header-nav .user{display:inline-block;text-align:left;margin-top:-5px;padding:0}.header-nav .user .hello{display:block;font-size:11px;font-weight:bold}.header-nav .user .name{display:block;margin-top:-6px!important;font-size:13px}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:white;background-color:#282b2e;outline:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.dropdown-menu:after,.dropdown-menu:before{display:none!important}.dropdown-menu{position:absolute;top:90%;left:0;z-index:1000;display:none;float:left;min-width:166px;max-width:300px;padding:0;margin:0;list-style:none;text-shadow:none;background:white;border:1px solid #dbdee0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{margin:0 1px}.dropdown-menu li a{display:block;padding:5px 10px!important;clear:both;font-weight:normal;line-height:20px;color:#34383c;white-space:normal!important}.dropdown-menu li{border-bottom:1px solid #e9ebec}.dropdown-menu li:last-child{border-bottom:0!important}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background:#62bce8}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#0077b3;background-image:-webkit-gradient(linear,left top,left bottom,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:-ms-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(top,#08c,#0077b3)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.dropdown-menu-title{background:#e9ebec;color:#34383c;padding:5px 10px;display:block}.dropdown-menu-sub-footer{text-align:center;background:#e9ebec;cursor:pointer}.dropdown-menu ul,.dropdown-menu ul li{padding:0!important;margin:0!important}ul.notifications li,ul.tasks li,ul.messages li{min-width:260px}ul.notifications li .avatar img,ul.tasks li .avatar img,ul.messages li .avatar img{float:left!important;height:40px;width:40px;margin-top:5px;margin-right:10px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}ul.messages li .header{display:block}ul.messages li .header .from{font-size:12px;font-weight:bold}ul.notifications li .icon{margin:-5px 10px -5px -10px!important;padding:7px 10px 9px 10px;color:white;width:40px;display:inline-block;text-align:center}ul.notifications li .icon.blue{background:#36a9e1}ul.notifications li .icon.lightBlue{background:#67c2ef}ul.notifications li .icon.green{background:#bdea74}ul.notifications li .icon.darkGreen{background:#78cd51}ul.notifications li .icon.pink{background:#e84c8a}ul.notifications li .icon.orange{background:#fa603d}ul.notifications li .icon.lightOrange{background:#fabb3d}ul.notifications li .icon.red{background:#ff5454}ul.notifications li .icon.yellow{background:#eae874}ul.notifications li .icon.white{background:white}ul.notifications li .icon.grey{background:#b2b8bd}ul.notifications li .time,ul.tasks li .header .percent,ul.messages li .header .time{font-size:11px;font-weight:bold;font-style:italic;position:absolute;right:5px}ul.tasks li .title,ul.notifications li .message{font-size:12px}ul.notifications li.warning a{color:#fa603d}ul.messages li .message{font-size:11px}a#main-menu-toggle{background:#1c1e21;width:40px;height:40px;color:white;position:absolute;z-index:1000;top:0;left:0;padding:8px 13px;font-size:16px;text-shadow:none;text-decoration:none;cursor:pointer}a#main-menu-toggle.close{opacity:1;background:#282b2e!important;padding:10px 13px!important}a#main-menu-min{display:block;border-bottom:1px solid #dbdee0;width:100%;margin:30px 0;position:relative;text-decoration:none}a#main-menu-min i{position:absolute;bottom:-10px;left:50%;margin-left:-10px;width:20px;height:20px;background:#dbdee0;font-size:14px;padding:3px 0;color:#7c848d;text-align:center}a#main-menu-min i:hover{background:#ced1d4;color:#6f7880}#sidebar-left{padding:10px!important;z-index:2}.sidebar-nav>ul{margin:-9px -25px;border:0;padding-bottom:1px;font-size:14px;white-space:nowrap}.sidebar-nav>ul>li>ul,.sidebar-nav>ul>li>ul>li>ul,.sidebar-nav>ul>li>ul>li>ul>li>ul{list-style:none;display:none;margin:0;padding:0}.nav.main-menu>li{margin-top:-1px}.nav.main-menu>li>a,.nav.main-menu>li>ul>li>a,.nav.main-menu>li>ul>li>ul>li>a,.nav.main-menu>li>ul>li>ul>li>ul>li>a{margin:0;height:40px;padding:1px 0 0 0;color:#7c848d;border:0;border-bottom:1px solid #dbdee0;background:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;text-decoration:none;display:block;position:relative}.nav.main-menu>li>a .chevron,.nav.main-menu>li>ul>li>a .chevron,.nav.main-menu>li>ul>li>ul>li>a .chevron,.nav.main-menu>li>ul>li>ul>li>ul>li>a .chevron{font-family:'FontAwesome';position:absolute;top:2px;right:-5px;height:40px;width:40px;padding:12px 0;display:inline-block;text-align:center;font-size:10px;color:#b2b8bd!important}.nav.main-menu>li>a .chevron.opened:after,.nav.main-menu>li>ul>li>a .chevron.opened:after,.nav.main-menu>li>ul>li>ul>li>a .chevron.opened:after,.nav.main-menu>li>ul>li>ul>li>ul>li>a .chevron.opened:after{height:100%;width:100%;content:"\f078";text-shadow:none}.nav.main-menu>li>a .chevron.closed:after,.nav.main-menu>li>ul>li>a .chevron.closed:after,.nav.main-menu>li>ul>li>ul>li>a .chevron.closed:after,.nav.main-menu>li>ul>li>ul>li>ul>li>a .chevron.closed:after{height:100%;width:100%;content:"\f053";text-shadow:none;color:#b2b8bd!important}.nav.main-menu>li>a>i,.nav.main-menu>li>ul>li>a>i{margin-right:10px;height:38px;width:40px;padding:13px 0;display:inline-block;text-align:center;border-right:1px solid #dbdee0}.nav.main-menu>li>ul>li>a>i,.nav.main-menu>li>ul>li>ul>li>a>i,.nav.main-menu>li>ul>li>ul>li>ul>li>a>i{margin-right:10px;height:38px;width:40px;padding:13px 0;display:inline-block;text-align:center;font-size:13px;border-right:1px solid #dbdee0}.nav.main-menu>li>ul>li>a{background:#e4e5e7}.nav.main-menu>li>ul>li>ul>li>a{background:#e1e3e5}.nav.main-menu>li>ul>li>ul>li>ul>li>a{background:#dee0e2}.nav.main-menu>li>a:hover,.nav.main-menu>li>ul>li>a:hover,.nav.main-menu>li>ul>li>ul>li>a:hover,.nav.main-menu>li>ul>li>ul>li>ul>li>a:hover{background:#ced1d4;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav.main-menu>li>a:hover>i,.nav.main-menu>li>ul>li>a:hover>i,.nav.main-menu>li>ul>li>ul>li>a:hover>i,.nav.main-menu>li>ul>li>ul>li>ul>li>a:hover>i{border-right:1px solid #c8ccd0}.nav.main-menu>li>a:hover,.nav.main-menu>li>ul>li>a:hover{background:#ced1d4;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav.main-menu>li.active>a,.nav.main-menu>li>ul>li.active>a,.nav.main-menu>li>ul>li>ul>li.active>a,.nav.main-menu>li>ul>li>ul>li>ul>li.active>a{background:#ced1d4}.nav.main-menu>li.active>a>i,.nav.main-menu>li>ul>li.active>a>i,.nav.main-menu>li>ul>li>ul>li.active>a>i,.nav.main-menu>li>ul>li>ul>li>ul>li.active>a>i{border-right:1px solid #c8ccd0}.nav.main-menu>li.active>a:hover,.nav.main-menu>li>ul>li.active>a:hover{border:0;color:white}.nav.main-menu>li.active>ul{padding:5px 0;background:#dbdee0}.nav.main-menu>li:first-child>a{margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav.main-menu>li:last-child>a{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}#sidebar-left.minified{width:40px!important;margin-right:-40px}#sidebar-left.minified .sidebar-nav>ul>li{position:relative}#sidebar-left.minified .sidebar-nav>ul>li>a{width:40px;position:relative}#sidebar-left.minified .sidebar-nav>ul>li>a.open{cursor:default}#sidebar-left.minified .sidebar-nav>ul>li>a .chevron{display:none;position:absolute;left:178px;z-index:1000}#sidebar-left.minified .sidebar-nav>ul>li>a .text{position:absolute;z-index:1000;background:#e9ebec;min-height:40px;width:150px;padding:8px 15px;border:1px solid #dbdee0;top:0;left:39px;display:none!important}#sidebar-left.minified .sidebar-nav>ul>li>ul{display:none!important}#sidebar-left.minified .sidebar-nav>ul>li:hover>a{position:relative}#sidebar-left.minified .sidebar-nav>ul>li:hover>a .chevron{display:inline-block}#sidebar-left.minified .sidebar-nav>ul>li:hover>a .text{position:absolute;z-index:1000;background:#e9ebec;min-height:40px;width:180px;padding:8px 15px;border:1px solid #dbdee0;top:0;left:39px;display:block!important}#sidebar-left.minified .sidebar-nav>ul>li:hover>ul{display:block!important;position:absolute;top:39px;left:39px;z-index:1000;width:180px;background:#e9ebec;border:1px solid #dbdee0;border-bottom:0}.btn{border:0;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;text-shadow:none;background:#e9ebec;color:#7c848d}.btn i{margin-top:2px}.btn-primary{color:#fff;background:#36a9e1}.btn-primary:hover,.btn-primary.disabled,.btn-primary[disabled]{background-color:#1e8fc6}.btn-primary:active,.btn-primary.active{background-color:#1c89be}.btn-warning{color:#fff;background:#fabb3d}.btn-warning:hover,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f9aa0b}.btn-warning:active,.btn-warning.active{background-color:#f4a406}.btn-danger{color:#fff;background:#ff5454}.btn-danger:hover,.btn-danger.disabled,.btn-danger[disabled]{background-color:#ff2121}.btn-danger:active,.btn-danger.active{background-color:#ff1717}.btn-success{color:#fff;background:#78cd51}.btn-success:hover,.btn-success.disabled,.btn-success[disabled]{background-color:#5db734}.btn-success:active,.btn-success.active{background-color:#59af32}.btn-info{color:#fff;background:#67c2ef}.btn-info:hover,.btn-info.disabled,.btn-info[disabled]{background-color:#39afea}.btn-info:active,.btn-info.active{background-color:#30ace9}.btn-inverse{color:#fff;background:#444}.btn-inverse:hover,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#2b2b2b;color:#fff}.btn-inverse:active,.btn-inverse.active{background-color:#252525}.btn-facebook,.btn-twitter,.btn-linkedin{color:white;position:relative;text-align:center;height:40px;width:100%;font-family:'FontAwesome';font-weight:bold;padding:10px 0}.btn-facebook:before,.btn-twitter:before,.btn-linkedin:before{position:absolute;display:block;height:40px;width:40px;top:0;left:0;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;font-size:20px;padding:6px 0}.btn-facebook span,.btn-twitter span,.btn-linkedin span{margin-left:40px}.btn-facebook:hover,.btn-twitter:hover,.btn-linkedin:hover{color:white}.btn-facebook{background:#3b5998}.btn-facebook:before{content:"\f09a";background:#344e86}.btn-facebook:hover{background:#344e86}.btn-facebook:hover:before{background:#2d4373}.btn-twitter{background:#00aced}.btn-twitter:before{content:"\f099";background:#0099d4}.btn-twitter:hover{background:#0099d4}.btn-twitter:hover:before{background:#0087ba}.btn-linkedin{background:#4875b4}.btn-linkedin:before{content:"\f0e1";background:#4169a2}.btn-linkedin:hover{background:#4169a2}.btn-linkedin:hover:before{background:#395d90}.nav-tabs li a{border-color:#dbdee0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;background:#e9ebec;margin:6px -1px -6px 0;line-height:1}.nav-tabs li a:hover{border-color:#dbdee0;background:#dbdee0}.nav-tabs li.active>a{line-height:1.428571429;margin:0 -1px 0 0}.tab-content{background:white;border:1px solid #dbdee0;border-top:0;padding:10px}.box-header .nav-tabs{border:0;float:right}.box-header .nav-tabs li a{background:transparent;border:0;border-left:1px solid #ced1d4;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;margin:0;font-size:14px;line-height:16px;font-weight:300;padding:11px 15px;height:40px}.box-header .nav-tabs li.active>a{background:white;border:0;border-left:1px solid #ced1d4}.box-header .nav-tabs li:hover{border:0}.box-header .nav-tabs li:last-child{margin-right:3px}.box-content .tab-content{background:transparent;border:0;padding:0}.form-horizontal .form-group{margin-right:0;margin-left:0}.input-group-addon,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],input[type="file"],.uneditable-input{border-color:#e9ebec;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}textarea{border:1px solid #e9ebec;-webkit-border-radius:2px!important;-moz-border-radius:2px!important;border-radius:2px!important}.input-group-addon.clear{background:white;margin:0 -1px;color:#b2b8bd}.limiterBox{border:1px solid #b2b8bd;border-top:0;background-color:#b2b8bd;padding:3px 6px;font-size:10px;color:white;opacity:.9;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.editor{max-height:250px;height:250px;background-color:white;border-collapse:separate;border:1px solid #ced1d4!important;padding:4px;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;overflow:scroll;outline:0;margin-top:20px}div[data-role="editor-toolbar"]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.dropdown-menu a{cursor:pointer}.twitter-typeahead .tt-query,.twitter-typeahead .tt-hint{margin-bottom:0}.tt-dropdown-menu{min-width:160px;margin-top:2px;padding:5px 0;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.tt-suggestion{display:block;padding:3px 20px}.tt-suggestion.tt-is-under-cursor{color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.tt-suggestion.tt-is-under-cursor a{color:#fff}.tt-suggestion p{margin:0}.notification{position:absolute;top:-12px;right:-12px;line-height:16px;height:16px;padding:6px 10px;color:white!important;-webkit-border-radius:50em;-moz-border-radius:50em;border-radius:50em;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.notification.small{padding:2px 7px;color:white!important;border-width:1px;border-style:solid;-webkit-border-radius:50em;-moz-border-radius:50em;border-radius:50em}.notification.small.blue,.notification.blue{background:#36a9e1}.notification.small.yellow,.notification.yellow{background:#eae874}.notification.small.red,.notification.red{background:#ff5454}.notification.small.green,.notification.green{background:#78cd51}.notification.small.orange,.notification.orange{background:#fabb3d}.notification.small.red,.notification.red{background:#ff5454}.label,.badge{font-weight:300;font-size:10px;padding:4px 6px;border:0;text-shadow:none}.label{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.label-important,.badge-important,.label-important[href],.badge-important[href]{background:#ff5454}.label-warning,.badge-warning,.label-warning[href],.badge-warning[href]{background:#fabb3d}.label-success,.badge-success,.label-success[href],.badge-success[href]{background:#78cd51}.label-info,.badge-info,.label-info[href],.badge-info[href]{background:#67c2ef}body.modal-open,.modal-open .navbar-fixed-top,.modal-open .navbar-fixed-bottom{margin-right:0}.panel-group .panel{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border:1px solid #dbdee0}.panel-group .panel .panel-heading{background:#f7f7f8}footer{background:#34383c;color:white;height:40px;padding:12px 20px 20px 20px!important;margin:0!important;position:relative;z-index:1;font-size:12px}footer a{color:white;font-weight:bold}.verticalChart{margin:10px}.verticalChart .singleBar{width:6%;display:block;margin:0 2% 0 2%;float:left}.verticalChart .singleBar .bar{position:relative;height:120px;background:#f9f9f9;overflow:hidden;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.verticalChart .singleBar .bar .value{position:absolute;bottom:0;width:100%;background:#bdea74;color:white;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.verticalChart .singleBar .bar .value span{position:absolute;font-size:12px;bottom:0;width:100%;height:20px;color:white;text-shadow:0 -1px 0 #bdea74,0px 1px 0 #bdea74,1px 0 0 #bdea74,-1px 0 0 #bdea74,-1px -1px 0 #bdea74,-1px 1px 0 #bdea74,1px 1px 0 #bdea74,1px -1px 0 #bdea74;display:none;text-align:center}.verticalChart .singleBar .title{margin-top:5px;text-align:center;color:#34383c}.browserStat.big{display:inline-block;width:49%;text-align:center;margin-bottom:20px;padding:0}.browserStat{display:inline-block;width:32%;text-align:center;margin:0;padding:0}.browserStat span{display:block;text-align:center;margin-top:10px}.smallchart{background:white;text-align:center}.smallchart .title{padding:10px;color:white;background:#dbdee0}.smallchart .content{padding:40px 0;background:#dbdee0}.smallchart .content i{font-size:40px;color:white}.smallchart .value{color:#34383c;padding:10px}.smallchart.blue .title{background:#36a9e1}.smallchart.lightBlue .title{background:#67c2ef}.smallchart.green .title{background:#bdea74}.smallchart.darkGreen .title{background:#78cd51}.smallchart.pink .title{background:#e84c8a}.smallchart.orange .title{background:#fa603d}.smallchart.lightOrange .title{background:#fabb3d}.smallchart.red .title{background:#ff5454}.smallchart.yellow .title{background:#eae874}.smallchart.white .title{background:white}.smallchart.grey .title{background:#b2b8bd}.sparkLineStats{position:relative;margin-bottom:-4px}.sparkLineStats ul{margin:0 0 0 -40px;list-style:none}.sparkLineStats ul li{margin-bottom:0;line-height:32px;padding-top:3px;font-size:12px}.sparkLineStats ul li div{float:left}.sparkLineStats ul li div:first-child{margin-right:5px}.sparkLineStats ul li .number{font-size:17px;font-weight:700;padding:0 0 0 2px;color:#fa603d}.sparkLineStats ul li h4{position:relative;border-bottom:1px solid #c4c4c4;padding-bottom:0;margin-bottom:10px;line-height:37px;-webkit-box-shadow:0 1px 0 #fff;-moz-box-shadow:0 1px 0 #fff;box-shadow:0 1px 0 #fff}canvas.chartjs{width:100%!important;max-width:2000px;height:auto!important}.jqstooltip{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.smallstat{background:white;padding:10px;position:relative;text-align:right}.smallstat .linechart-overlay,.smallstat .boxchart-overlay{width:84px;padding:10px;text-align:center;margin-right:10px;float:left;overflow:hidden}.smallstat .linechart-overlay.blue,.smallstat .boxchart-overlay.blue{background:#36a9e1}.smallstat .linechart-overlay.lightBlue,.smallstat .boxchart-overlay.lightBlue{background:#67c2ef}.smallstat .linechart-overlay.green,.smallstat .boxchart-overlay.green{background:#bdea74}.smallstat .linechart-overlay.darkGreen,.smallstat .boxchart-overlay.darkGreen{background:#78cd51}.smallstat .linechart-overlay.pink,.smallstat .boxchart-overlay.pink{background:#e84c8a}.smallstat .linechart-overlay.orange,.smallstat .boxchart-overlay.orange{background:#fa603d}.smallstat .linechart-overlay.lightOrange,.smallstat .boxchart-overlay.lightOrange{background:#fabb3d}.smallstat .linechart-overlay.red,.smallstat .boxchart-overlay.red{background:#ff5454}.smallstat .linechart-overlay.yellow,.smallstat .boxchart-overlay.yellow{background:#eae874}.smallstat .linechart-overlay.white,.smallstat .boxchart-overlay.white{background:white}.smallstat .linechart-overlay.grey,.smallstat .boxchart-overlay.grey{background:#b2b8bd}.smallstat .piechart-overlay{padding:5px;text-align:center;margin-right:10px;float:left;overflow:hidden}.smallstat .piechart-overlay.blue{background:#36a9e1}.smallstat .piechart-overlay.lightBlue{background:#67c2ef}.smallstat .piechart-overlay.green{background:#bdea74}.smallstat .piechart-overlay.darkGreen{background:#78cd51}.smallstat .piechart-overlay.pink{background:#e84c8a}.smallstat .piechart-overlay.orange{background:#fa603d}.smallstat .piechart-overlay.lightOrange{background:#fabb3d}.smallstat .piechart-overlay.red{background:#ff5454}.smallstat .piechart-overlay.yellow{background:#eae874}.smallstat .piechart-overlay.white{background:white}.smallstat .piechart-overlay.grey{background:#b2b8bd}.smallstat .piechart{color:white;font-size:10px}.smallstat i{text-align:center;display:block;color:white;width:50px;font-size:22px;padding:14px 0;float:left;margin-right:10px}.smallstat i.blue{background:#36a9e1}.smallstat i.lightBlue{background:#67c2ef}.smallstat i.green{background:#bdea74}.smallstat i.darkGreen{background:#78cd51}.smallstat i.pink{background:#e84c8a}.smallstat i.orange{background:#fa603d}.smallstat i.lightOrange{background:#fabb3d}.smallstat i.red{background:#ff5454}.smallstat i.yellow{background:#eae874}.smallstat i.white{background:white}.smallstat i.grey{background:#b2b8bd}.smallstat .title{top:12px;color:#b2b8bd;display:block;font-size:12px;margin-top:4px;font-weight:bold}.smallstat .value{font-size:20px}.smallstat .more{background:#e9ebec;border-top:1px solid #dbdee0;margin:12px -10px -10px -10px;padding:5px 10px;display:block;font-size:12px;text-align:left}.smallstat .more:hover{color:#34383c;text-decoration:none}.smallstat .more i{padding:0;margin:4px 0 0 0;display:inline;color:#34383c;font-size:10px;float:right;width:10px}ul.stats{list-style:none;padding:0;border-top:1px solid #e9ebec;margin:20px -10px -10px -10px;*zoom:1}ul.stats:before,ul.stats:after{display:table;content:"";line-height:0}ul.stats:after{clear:both}ul.stats li{position:relative;z-index:2;width:25%;border-right:1px solid #e9ebec;float:left;text-align:center;padding:20px 0;margin:0;overflow:hidden}ul.stats li:last-child{border:0}ul.stats li .bgchart{width:100%;height:100%;position:absolute;z-index:-1;top:0;left:0}.info-box .backgroundColor{color:white;padding:10px}.info-box .title,.info-box .value{font-weight:bold;font-size:12px;margin:0;padding:0}.info-box .date,.info-box .change{font-size:10px;margin:0;padding:0}.info-box .title,.info-box .date{float:left}.info-box .value,.info-box .change{float:right}.info-box .quarters{background:white;*zoom:1}.info-box .quarters:before,.info-box .quarters:after{display:table;content:"";line-height:0}.info-box .quarters:after{clear:both}.info-box .quarters .quarter{padding:10px}.info-box .quarters .quarter span{display:block;font-size:10px;color:#b2b8bd}.info-box .quarters .q1,.info-box .quarters .q2,.info-box .quarters .q3,.info-box .quarters .q4{width:50%;float:left}.info-box .quarters .q1,.info-box .quarters .q2{border-bottom:1px solid #e9ebec;height:60px}.info-box .quarters .q2{padding:0}.info-box .quarters .q2,.info-box .quarters .q4{text-align:right}.info-box .quarters .q4{border-left:1px solid #e9ebec}.info-box .quarters .verticalChart{float:right;text-align:center;margin:3px 0 0 0;width:100%;padding:6px}.info-box .quarters .verticalChart .singleBar{width:10.5%;margin:0 0 0 3px}.info-box .quarters .verticalChart .singleBar .bar{height:22px;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.info-box .quarters .verticalChart .singleBar .bar .value{background:#b2b8bd;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.info-box .quarters .verticalChart .singleBar .title{margin:2px auto 0 auto;text-align:center;color:#b2b8bd;font-size:8px;font-weight:400;width:100%}.discussions ul{list-style:none;margin:0;padding:0}.discussions ul li{font-size:12px;border:1px solid #dbdee0;position:relative;background:white;margin:0 40px 20px 80px;padding:10px}.discussions ul li:before{content:'';width:20px;height:20px;top:15px;left:-20px;position:absolute;background:url("../img/disc-arrow.png") no-repeat;background-size:20px 20px}.discussions ul li .author{position:absolute;z-index:1;width:60px;float:left;top:0;left:-70px}.discussions ul li .author img{height:50px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.discussions ul li .name{position:absolute;top:10px;left:10px;width:100%;background:#e9ebec;padding:5px 10px 5px 10px}.discussions ul li .date{position:absolute;top:10px;right:-1px;z-index:1;background:#dbdee0;padding:5px 20px 5px 10px}.discussions ul li .delete{position:absolute;background:#ced1d4;top:10px;right:-30px;padding:5px 10px;display:inline-block;cursor:pointer}.discussions ul li .message{border-bottom:1px solid #e9ebec;margin:20px -10px 0 -10px;padding:20px;font-size:12px}.discussions ul li ul{overflow:hidden}.discussions ul li ul li{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border:0;border-bottom:1px solid #e9ebec;margin:0 -10px;padding-left:70px}.discussions ul li ul li:before{display:none}.discussions ul li ul li:last-child{border-bottom:0}.discussions ul li ul li .author{top:10px;left:10px}.discussions ul li ul li .author img{height:40px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.discussions ul li ul li .name{left:70px}.discussions ul li ul li .date{background:transparent;right:30px}.discussions ul li ul li .delete{background:transparent;right:10px}.discussions ul li ul li .message{border-bottom:0}.discussions ul li ul li textarea{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;width:100%;font-size:12px;padding:5px}.chat{position:relative;background:white}.chat .contacts{position:absolute;height:100%;float:left;width:30%;background:#e9ebec;border-right:1px solid #dbdee0}.chat .contacts ul.list{list-style:none;margin:0;padding:0}.chat .contacts ul.list li{position:relative;padding:5px 10px;border-bottom:1px solid #dbdee0;cursor:pointer}.chat .contacts ul.list li:hover{background:#b2b8bd}.chat .contacts ul.list li img.avatar{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;width:40px;margin-right:10px}.chat .contacts ul.list li .status{display:block;position:absolute;top:42%;right:20px;width:8px;height:8px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.chat .contacts ul.list li .status.online{background:#bdea74}.chat .contacts ul.list li .status.offline{background:#b2b8bd}.chat .contacts ul.list li .status.busy{background:#fa603d}.chat .contacts ul.list li .important{font-size:11px;display:inline-block;position:absolute;top:1px;left:35px;font-size:10px;padding:3px 7px;color:white;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;background:#ff5454}.chat .conversation{width:70%;float:right}.chat .conversation .actions{background:#34383c;width:100%;height:50px}.chat .conversation .actions a{display:block;color:white;padding:16px;font-size:18px;width:18px;float:left}.chat .conversation .actions img.avatar{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;width:30px;margin:10px 0 10px 10px}.chat .conversation ul{height:516px;overflow-y:scroll;list-style:none;margin:0;padding:0}.chat .conversation ul li{position:relative;padding:15px 10px 10px 60px;border-bottom:1px solid #dbdee0}.chat .conversation ul li img.avatar{top:10px;left:10px;position:absolute;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;width:40px;margin-right:10px}.chat .conversation ul li .name{font-weight:bold;text-transform:uppercase}.chat .conversation ul li .time{font-weight:bold;right:10px;position:absolute;color:#b2b8bd;font-size:11px}.chat .conversation ul li .message{margin-top:10px;font-size:12px}.chat .conversation .form{border-top:2px solid #dbdee0;height:60px;padding:10px}.chat .conversation .form input{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:100%;height:100%}.chat.alt .contacts{width:60px}.chat.alt .contacts ul.list{list-style:none;margin:0;padding:0}.chat.alt .contacts ul.list li{text-align:center}.chat.alt .contacts ul.list li img.avatar{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;width:40px;margin:0 auto}.chat.alt .contacts ul.list li .name{display:none}.chat.alt .contacts ul.list li .status{top:70%;right:10px}.chat.alt .conversation{width:auto;margin-left:60px}.calendar{background:white}.calendar .calendar-details{background:#dbdee0;color:white;font-weight:300px;position:relative;padding:20px}.calendar .calendar-details .day{font-size:20px;text-transform:uppercase;float:left;margin:10px}.calendar .calendar-details .date{font-size:20px;margin:10px;text-transform:uppercase}.calendar .calendar-details ul.events{list-style:none;margin:0;padding:0}.calendar .calendar-details ul.events li{margin:0 10px}.calendar .calendar-details .add-event{display:block;bottom:10px;border-bottom:#b2b8bd;padding:13px 5px 0 5px}.calendar .calendar-details .add-event input{width:100%;color:white;border:0;font-size:12px;margin:0;padding:5px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;background:#ced1d4;z-index:9}.calendar .fc{padding:20px;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.calendar .fc-widget-header,.calendar .fc-widget-content{border-color:#e9ebec}.calendar .fc-state-default{background:white;border:0;color:#b2b8bd;text-shadow:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;margin-top:-5px;margin-left:-10px}.calendar .fc-state-hover,.calendar .fc-state-down,.calendar .fc-state-active,.calendar .fc-state-disabled{color:#34383c;background:white}.calendar .fc-day-number{margin:0 0 0 -30px;padding:5px!important;text-align:left;font-size:10px;font-weight:300}.calendar .fc-state-highlight{background:transparent}.calendar .fc-state-highlight .fc-day-number{color:#36a9e1;font-weight:700}.calendar .event{background:#36a9e1;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:white}.calendar .fc-grid .fc-day-number{float:none;padding:0 2px;text-align:center}.calendar .fc-grid .fc-other-month .fc-day-number{opacity:1;filter:alpha(opacity=1);color:#b2b8bd}.calendar .fc-event{border:0;height:1px;background:#b2b8bd}.calendar .fc-event .fc-event-inner{display:none}ul.dashboard-list{padding:0}ul.dashboard-list a:hover{text-decoration:none}ul.dashboard-list li:last-child{border-bottom:0}ul.dashboard-list li:first-child{border-top:0;border-bottom:1px solid #e9ebec}ul.dashboard-list li{padding:5px 0;list-style:none;border-bottom:1px solid #e9ebec;font-size:12px}ul.dashboard-list li a span{display:inline-block;font-size:18px;font-weight:bold;margin-right:10px;text-align:right;width:50px;zoom:1}ul.dashboard-list li a img.avatar{height:50px;width:50px;float:left;margin-top:3px;margin-right:15px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}ul.dashboard-list li i{font-size:18px;opacity:.7;filter:alpha(opacity=70);-ms-filter:"alpha(opacity=70)"}ul.users-list{padding:0}ul.users-list a:hover{text-decoration:none}ul.users-list li:last-child{border-bottom:0;min-height:51px}ul.users-list li:first-child{border-top:0;border-bottom:1px solid #e9ebec}ul.users-list li{min-height:60px;padding:5px 10px;list-style:none;border-bottom:1px solid #e9ebec;font-size:12px}ul.users-list li a img.avatar{height:40px;width:40px;float:left;margin-top:3px;margin-right:15px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}ul.users-list li .name{margin:5px 0 -2px 0;font-size:14px;font-weight:bold}ul.users-list li .name .dropdown{float:right;margin:-1px 0}ul.users-list li .name .dropdown a{color:#b2b8bd;font-size:11px;text-decoration:none}ul.users-list li .name .dropdown ul li{padding:0;min-height:10px}ul.users-list li .name .dropdown ul li i{display:inline-block;width:20px}ul.users-list li span{display:inline-block;margin-right:5px;font-size:10px;color:#b2b8bd}ul.users-list li .place{width:35%}ul.users-list li i{color:#b2b8bd;margin-right:2px;font-size:11px}ul.users-list.no-padding li{padding:5px 0}ul.comments-list{padding:0}ul.comments-list a:hover{text-decoration:none}ul.comments-list li:last-child{border-bottom:0}ul.comments-list li:first-child{border-top:0;border-bottom:1px solid #e9ebec}ul.comments-list li{padding:5px 10px;list-style:none;border-bottom:1px solid #e9ebec;font-size:12px}ul.comments-list li a img.avatar{height:50px;width:50px;float:left;margin-top:3px;margin-right:15px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}ul.comments-list li div{margin-left:65px}ul.comments-list li div.date{margin-top:5px;font-size:10px;font-weight:bold;color:#b2b8bd}ul.comments-list.no-padding li{padding:5px 0}.todo ul{list-style:none;padding:0;margin:-10px}.todo ul li{background:white;margin-left:0!important;padding:10px 10px 10px 35px;border-bottom:1px solid #e9ebec;font-size:12px;position:relative}.todo ul li:last-child{border-bottom:0}.todo ul li .label{position:absolute;right:10px}.todo ul li .todo-actions{position:absolute;left:0;margin-top:2px}.todo ul li .todo-actions a{text-decoration:none}.todo ul li .todo-actions i{font-size:14px;color:#dbdee0;margin:-1px 5px 0 10px;display:block}.todo ul li .todo-actions i.done{color:#ced1d4}.todo ul li .todo-actions i:hover{color:#b2b8bd}.todo ul li .remove{display:none;position:absolute;right:10px;color:#b2b8bd}.todo ul li:hover .label{position:absolute;right:30px}.todo ul li:hover .remove{display:inline}#feed{background:#e9ebec;top:0;right:0;position:absolute;height:100%;border-left:1px solid #dbdee0}#feed h2{background:#dbdee0;padding:12px;margin:0 -15px 10px -15px}#feed h2 a{float:right;color:#b2b8bd;text-decoration:none;cursor:pointer}#feed h2 a:hover{color:#34383c}#feed ul#filter{margin:0 0 10px -40px;list-style:none;*zoom:1}#feed ul#filter:before,#feed ul#filter:after{display:table;content:"";line-height:0}#feed ul#filter:after{clear:both}#feed ul#filter li{float:left;margin-right:20px;cursor:pointer}#feed ul#filter li a{text-decoration:none}#feed ul#filter li a.active{font-weight:bold}#feed ul#filter li a:hover{color:inherit}#feed ul#timeline{margin:0 0 0 10px;list-style:none;border-left:1px solid #dbdee0}#feed ul#timeline li{position:relative;margin:0 0 20px -20px;font-size:12px}#feed ul#timeline li i{position:absolute;top:-4px;left:-36px;background:#e9ebec;padding:5px 0;font-size:15px;width:30px;text-align:center}#feed ul#timeline li.tasks i{color:#bdea74}#feed ul#timeline li.comments i{color:#ff5454}#feed ul#timeline li.messages i{color:#36a9e1}#feed ul#timeline li .title{font-weight:bold}#feed ul#timeline li .desc{margin:5px 0}#feed ul#timeline li .date,#feed ul#timeline li .separator,#feed ul#timeline li .name{color:#b2b8bd}#feed ul#timeline li .separator{margin:0 5px}#feed #load-more{color:#dbdee0;margin:0 auto;display:block;text-align:center;text-decoration:none}#feed #load-more:hover{color:#34383c}.slider{background:#e9ebec;border:0;height:10px;position:relative;z-index:10;margin:5px 0!important}.slider .ui-slider-range{position:absolute;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.slider.small{height:6px}.ui-slider-handle{border:1px solid #ced1d4;outline:none!important}.ui-slider-horizontal .ui-slider-handle{background:url("../img/handle.png") no-repeat center center scroll #fff!important;background-position:50% 50%;background-size:8px 8px!important}.ui-slider-horizontal.small .ui-slider-handle{background:url("../img/handle.png") no-repeat center center scroll #fff!important;background-position:50% 50%;background-size:8px 8px!important;width:14px!important;height:14px!important}.sliderVertical{background:#e9ebec;border:0;top:auto;bottom:auto;width:10px!important;position:relative;float:left;height:100px;margin:10px 20px;width:5px}.sliderVertical .ui-slider-range{height:100%;width:100%;top:auto;bottom:auto;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.sliderVertical .ui-slider-handle{background:url("../img/handlev.png") no-repeat center center scroll #fff!important;background-position:50% 50%;background-size:8px 8px!important;left:50%;margin:9px 0 -9px -9px!important}.sliderVertical .ui-slider-range-max{top:0}.sliderVertical .ui-slider-range-min{bottom:0}.sliderVertical.small{width:6px!important;position:relative;float:left;height:100px;margin:10px 20px;width:5px}.sliderVertical.small .ui-slider-handle{background:url("../img/handlev.png") no-repeat center center scroll #fff!important;background-position:50% 50%;background-size:8px 8px!important;width:14px;height:14px;margin:0 0 -7px -7px!important}.sliderBlue .ui-slider-range,.progressBlue .ui-progressbar-value{background:#36a9e1}.sliderGreen .ui-slider-range,.progressGreen .ui-progressbar-value{background:#bdea74}.sliderDarkGreen .ui-slider-range,.progressDarkGreen .ui-progressbar-value{background:#78cd51}.sliderPink .ui-slider-range,.progressPink .ui-progressbar-value{background:#e84c8a}.sliderOrange .ui-slider-range,.progressOrange .ui-progressbar-value{background:#fa603d}.sliderLightOrange .ui-slider-range,.progressLightOrange .ui-progressbar-value{background:#fabb3d}.sliderRed .ui-slider-range,.progressRed .ui-progressbar-value{background:#ff5454}.sliderYellow .ui-slider-range,.progressYellow .ui-progressbar-value{background:#eae874}.progress{background:#e9ebec;color:#e9ebec;border:0;height:14px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;position:relative;margin-top:-2px}.progress .ui-progressbar-value{border:0;height:100%;top:1px;position:absolute;left:1px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.progress.slim{height:10px}.progressBarValue span{font-size:12px}.progressBarValue span.progressCustomValueVal{font-size:18px;font-weight:700;padding:0 5px;color:#fa603d}.progressSlim{background:#ced1d4;border:0;height:10px;position:relative;margin-top:-2px}.progressSlim .ui-progressbar-value{border-color:transparent;height:100%;top:0;position:absolute;left:0;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.tasks .progressSlim{overflow:hidden;border:none!important;height:8px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;margin-top:0}.tasks .progressSlim .ui-progressbar-value{overflow:hidden;margin:0;border:none!important}.quick-button{border:1px solid #dbdee0;background:#e9ebec;margin-bottom:-1px;padding:30px 0 10px 0;font-size:14px;display:block;text-align:center;cursor:pointer;position:relative;-webkit-transition:all .3s ease;-moz-transition:all .3s ease;-ms-transition:all .3s ease;-o-transition:all .3s ease;transition:all .3s ease;color:#b2b8bd;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.quick-button:hover{color:#34383c;text-decoration:none;background:#dbdee0}.quick-button .notification{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;top:-1px;right:-1px;font-size:10px}.quick-button i{font-size:32px}.quick-button.small{padding:15px 0 0 0;font-size:10px}.quick-button.small i{font-size:20px}.quick-button.small .notification{top:-1px;right:-1px;font-size:7px;padding:4px 5px}.tempStats{text-align:center!important}.tempStatBox{width:120px;padding:25px 0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;margin:0 auto}.tempStatBox .tempStat{position:relative;font-size:34px;line-height:100px;-webkit-border-radius:50em;-moz-border-radius:50em;border-radius:50em;border:10px solid #FFF;background:#f9f9f9;height:100px;width:100px;text-align:center;margin:0 auto;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.tempStatBox .tempStat:before{content:"";top:-10px;left:-10px;height:120px;width:120px;position:absolute;-webkit-border-radius:50em;-moz-border-radius:50em;border-radius:50em;background:transparent;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.3),0px 1px 0 #fff;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.3),0px 1px 0 #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.3),0px 1px 0 #fff;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.tempStatBox .tempStat:after{content:"";top:0;left:0;height:98px;width:98px;position:absolute;-webkit-border-radius:50em;-moz-border-radius:50em;border-radius:50em;border:1px solid #fff;background:transparent;-webkit-box-shadow:0 0 1px rgba(0,0,0,0.4);-moz-box-shadow:0 0 1px rgba(0,0,0,0.4);box-shadow:0 0 1px rgba(0,0,0,0.4);-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.tempStatBox .tempStat.t0{border-color:#67c2ef}.tempStatBox .tempStat.t20{border-color:#bdea74}.tempStatBox .tempStat.t40{border-color:#eae874}.tempStatBox .tempStat.t60{border-color:#fabb3d}.tempStatBox .tempStat.t80{border-color:#fa603d}.tempStatBox .tempStat.t100{border-color:#ff5454}.tempStatBox span{width:100%;text-align:center;display:block;margin-top:10px;text-shadow:0 1px 0 #fff}.circleStats{text-align:center;position:relative}.circleStatsItem{position:relative;background:rgba(255,255,255,0.7);-webkit-box-shadow:inset 0 0 0 2px rgba(0,0,0,0.2),0 0 0 4px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 0 0 2px rgba(0,0,0,0.2),0 0 0 4px rgba(0,0,0,0.1);box-shadow:inset 0 0 0 2px rgba(0,0,0,0.2),0 0 0 4px rgba(0,0,0,0.1);-webkit-border-radius:50em;-moz-border-radius:50em;border-radius:50em;width:120px;height:120px;margin:10px auto}.circleStatsItem i{font-size:30px;position:absolute;top:30%;margin-top:0;width:100%;text-align:center}.circleStatsItem input{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border:0;height:auto;position:absolute;top:15px;left:120px;padding:5px 0!important;border-color:rgba(0,0,0,0.8)}.circleStatsItem input:focus{outline:0;outline:thin dotted 0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.circleStatsItem .plus{font-size:16px;position:absolute;top:55%;margin-left:30px}.circleStatsItem .percent{font-size:14px;position:absolute;top:57%;margin-left:78px}.circleStatsItem.orange,.circleStatsItem.orange i{color:#fa603d}.circleStatsItem.lightorange,.circleStatsItem.lightorange i{color:#fabb3d}.circleStatsItem.blue,.circleStatsItem.blue i{color:#36a9e1}.circleStatsItem.green,.circleStatsItem.green i{color:#bdea74}.circleStatsItem.yellow,.circleStatsItem.yellow i{color:#eae874}.circleStatsItem.pink,.circleStatsItem.pink i{color:#e84c8a}.circleStatsItemBox{position:relative;background:#67c2ef;width:100%;min-width:130px;height:160px;margin:10px auto;padding-top:40px;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.circleStatsItemBox .header{background:rgba(255,255,255,0.2);color:rgba(255,255,255,0.9);width:100%;height:20px;padding:5px 0;position:absolute;top:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.circleStatsItemBox .footer{background:rgba(0,0,0,0.1);color:rgba(255,255,255,0.9);width:100%;height:20px;padding:5px 0;position:absolute;bottom:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.circleStatsItemBox .footer .count{font-size:10px}.circleStatsItemBox .footer .value{font-weight:bold}.circleStatsItemBox .percent{font-size:12px;position:absolute;top:110px;width:100%;left:0;text-align:center;color:rgba(255,255,255,0.9)}.circleStatsItemBox input{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border:0;height:auto;position:absolute;top:30px;padding:5px 0!important;border-color:rgba(0,0,0,0.8)}.circleStatsItemBox input:focus{outline:0;outline:thin dotted 0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.masonry-thumb{display:inline-block;vertical-align:top;margin-bottom:6px}.rating{unicode-bidi:bidi-override;direction:rtl;font-size:30px}.rating span.star,.rating span.star{font-family:FontAwesome;font-weight:normal;font-style:normal;display:inline-block}.rating span.star:hover,.rating span.star:hover{cursor:pointer}.rating span.star:before,.rating span.star:before{content:"\f006";padding-right:5px;color:#999}.rating span.star:hover:before,.rating span.star:hover:before,.rating span.star:hover ~ span.star:before,.rating span.star:hover ~ span.star:before{content:"\f005";color:#e3cf7a}.glyphicons-icon-list div{margin:10px 0}.glyphicons-icon-list div span,.glyphicons-icon-list div strong{font-size:10px}.glyphicons-icon-list div strong{margin-top:-5px;display:block}.fontawesome-icon-list div{margin:5px 0}.fontawesome-icon-list .fa{width:20px;text-align:center;margin-right:10px}.elfinder .elfinder-button{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.text-with-hr{text-align:center;position:relative;z-index:2}.text-with-hr:before{position:absolute;content:'';top:20px;left:0;width:100%;border-bottom:1px solid #e9ebec;z-index:-1}.text-with-hr span{display:inline-block;background:white;padding:10px}.switch{position:relative;display:inline-block;vertical-align:top;width:56px;height:20px;padding:3px;background-color:white;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;box-shadow:inset 0 -1px #fff,inset 0 1px 1px rgba(0,0,0,0.05);cursor:pointer;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.switch-input{position:absolute;top:0;left:0;opacity:0}.switch-label{position:relative;display:block;height:inherit;font-size:10px;text-transform:uppercase;background:#f9f9f9;border-radius:inherit;box-shadow:inset 0 1px 2px rgba(0,0,0,0.12),inset 0 0 2px rgba(0,0,0,0.15);-webkit-transition:.15s ease-out;-moz-transition:.15s ease-out;-o-transition:.15s ease-out;transition:.15s ease-out;-webkit-transition-property:opacity background;-moz-transition-property:opacity background;-o-transition-property:opacity background;transition-property:opacity background}.switch-label:before,.switch-label:after{position:absolute;top:50%;margin-top:-0.5em;line-height:1;-webkit-transition:inherit;-moz-transition:inherit;-o-transition:inherit;transition:inherit}.switch-label:before{content:attr(data-off);right:11px;color:#aaa;text-shadow:0 1px rgba(255,255,255,0.5)}.switch-label:after{content:attr(data-on);left:11px;color:white;text-shadow:0 1px rgba(0,0,0,0.2);opacity:0}.switch-input:checked ~ .switch-label{background:#b2b8bd;box-shadow:inset 0 1px 2px rgba(0,0,0,0.15),inset 0 0 3px rgba(0,0,0,0.2)}.switch-input:checked ~ .switch-label:before{opacity:0}.switch-input:checked ~ .switch-label:after{opacity:1}.switch-handle{position:absolute;top:4px;left:4px;width:18px;height:18px;background:white;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;box-shadow:1px 1px 5px rgba(0,0,0,0.2);background-image:-webkit-linear-gradient(top,#fff 40%,#f0f0f0);background-image:-moz-linear-gradient(top,#fff 40%,#f0f0f0);background-image:-o-linear-gradient(top,#fff 40%,#f0f0f0);background-image:linear-gradient(to bottom,#fff 40%,#f0f0f0);-webkit-transition:left .15s ease-out;-moz-transition:left .15s ease-out;-o-transition:left .15s ease-out;transition:left .15s ease-out}.switch-handle:before{content:'';position:absolute;top:50%;left:50%;margin:-6px 0 0 -6px;width:12px;height:12px;background:#f9f9f9;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;box-shadow:inset 0 1px rgba(0,0,0,0.02);background-image:-webkit-linear-gradient(top,#eee,#fff);background-image:-moz-linear-gradient(top,#eee,#fff);background-image:-o-linear-gradient(top,#eee,#fff);background-image:linear-gradient(to bottom,#eee,#fff)}.switch-input:checked ~ .switch-handle{left:40px;box-shadow:-1px 1px 5px rgba(0,0,0,0.2)}.switch-primary>.switch-input:checked ~ .switch-label{background:#36a9e1}.switch-success>.switch-input:checked ~ .switch-label{background:#78cd51}.switch-warning>.switch-input:checked ~ .switch-label{background:#fabb3d}.switch-important>.switch-input:checked ~ .switch-label{background:#ff5454}.switch-info>.switch-input:checked ~ .switch-label{background:#67c2ef}.switch-danger>.switch-input:checked ~ .switch-label{background:#d9534f}table tr td.left,table tr th.left{text-align:left}table tr td.center,table tr th.center{text-align:center}table tr td.right,table tr th.right{text-align:right}table tr td .progress{margin:3px 0 0 0}table.table-clear tr,table.table-clear td{border:none!important}table.small-font{font-size:12px}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #e9ebec}.table thead>tr>th{vertical-align:bottom;border-bottom:2px solid #e9ebec}.table-bordered{border:1px solid #e9ebec}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #e9ebec}ul.skill-bar{padding:0}ul.skill-bar h5{margin-bottom:6px}ul.skill-bar li{margin-bottom:12px;list-style:none;padding-left:0}ul.skill-bar li .meter{height:20px;position:relative;background:#e9ebec}ul.skill-bar li .meter span{display:block;height:100%;position:relative;overflow:hidden;color:white;background:#b2b8bd;text-align:right;padding-right:10px;margin:0}ul.skill-bar li .meter span.blue{background:#36a9e1}ul.skill-bar li .meter span.lightBlue{background:#67c2ef}ul.skill-bar li .meter span.green{background:#bdea74}ul.skill-bar li .meter span.darkGreen{background:#78cd51}ul.skill-bar li .meter span.pink{background:#e84c8a}ul.skill-bar li .meter span.orange{background:#fa603d}ul.skill-bar li .meter span.lightOrange{background:#fabb3d}ul.skill-bar li .meter span.red{background:#ff5454}ul.skill-bar li .meter span.yellow{background:#eae874}ul.skill-bar li .meter span.white{background:white}ul.skill-bar li .meter span.grey{background:#b2b8bd}div.dataTables_length label{font-weight:normal;float:left;text-align:left}div.dataTables_length select{width:75px}div.dataTables_filter label{font-weight:normal;float:right}div.dataTables_info{padding-top:8px}div.dataTables_paginate{float:right;margin:0}div.dataTables_paginate ul.pagination{margin:2px}table.table{clear:both;margin-top:6px!important;margin-bottom:6px!important;max-width:none!important}table.table .btn{margin:1px 0}table.table thead .sorting,table.table thead .sorting_asc,table.table thead .sorting_desc,table.table thead .sorting_asc_disabled,table.table thead .sorting_desc_disabled{cursor:pointer}table.table thead .sorting{background:url('../img/sort_both.png') no-repeat center right}table.table thead .sorting_asc{background:url('../img/sort_asc.png') no-repeat center right}table.table thead .sorting_desc{background:url('../img/sort_desc.png') no-repeat center right}table.table thead .sorting_asc_disabled{background:url('../img/sort_asc_disabled.png') no-repeat center right}table.table thead .sorting_desc_disabled{background:url('../img/sort_desc_disabled.png') no-repeat center right}table.dataTable th:active{outline:0}div.dataTables_scrollHead table{margin-bottom:0!important;border-bottom-left-radius:0;border-bottom-right-radius:0}div.dataTables_scrollHead table thead tr:last-child th:first-child,div.dataTables_scrollHead table thead tr:last-child td:first-child{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}div.dataTables_scrollBody table{border-top:0;margin-bottom:0!important}div.dataTables_scrollBody tbody tr:first-child th,div.dataTables_scrollBody tbody tr:first-child td{border-top:0}div.dataTables_scrollFoot table{border-top:0}.table tbody tr.active td,.table tbody tr.active th{background-color:#08C;color:white}.table tbody tr.active:hover td,.table tbody tr.active:hover th{background-color:#0075b0!important}.table-striped tbody tr.active:nth-child(odd) td,.table-striped tbody tr.active:nth-child(odd) th{background-color:#017ebc}table.DTTT_selectable tbody tr{cursor:pointer}div.DTTT .btn{color:#333!important;font-size:12px}div.DTTT .btn:hover{text-decoration:none!important}ul.DTTT_dropdown.dropdown-menu{z-index:2003}ul.DTTT_dropdown.dropdown-menu a{color:#333!important}ul.DTTT_dropdown.dropdown-menu li{position:relative}ul.DTTT_dropdown.dropdown-menu li:hover a{background-color:#08c;color:white!important}div.DTTT_print_info.modal{height:150px;margin-top:-75px;text-align:center}div.DTTT_print_info h6{font-weight:normal;font-size:28px;line-height:28px;margin:1em}div.DTTT_print_info p{font-size:14px;line-height:20px}div.DTFC_LeftHeadWrapper table,div.DTFC_LeftFootWrapper table,div.DTFC_RightHeadWrapper table,div.DTFC_RightFootWrapper table,table.DTFC_Cloned tr.even{background-color:white}div.DTFC_RightHeadWrapper table,div.DTFC_LeftHeadWrapper table{margin-bottom:0!important;border-top-right-radius:0!important;border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}div.DTFC_RightBodyWrapper table,div.DTFC_LeftBodyWrapper table{border-top:0;margin-bottom:0!important}div.DTFC_RightBodyWrapper tbody tr:first-child th,div.DTFC_RightBodyWrapper tbody tr:first-child td,div.DTFC_LeftBodyWrapper tbody tr:first-child th,div.DTFC_LeftBodyWrapper tbody tr:first-child td{border-top:0}div.DTFC_RightFootWrapper table,div.DTFC_LeftFootWrapper table{border-top:0}@media(-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){table.table thead .sorting{background:url('../img/sort_both@2x.png') no-repeat center right;background-size:19px 19px}table.table thead .sorting_asc{background:url('../img/sort_asc@2x.png') no-repeat center right;background-size:19px 19px}table.table thead .sorting_desc{background:url('../img/sort_desc@2x.png') no-repeat center right;background-size:19px 19px}table.table thead .sorting_asc_disabled{background:url('../img/sort_asc_disabled@2x.png') no-repeat center right;background-size:19px 19px}table.table thead .sorting_desc_disabled{background:url('../img/sort_desc_disabled@2x.png') no-repeat center right;background-size:19px 19px}}.sz1{width:200px;height:160px}.sz0{margin:2em 0 0 0}.sz0{width:100px;height:80px}.dd{position:relative;display:block;margin:0;padding:0;list-style:none;font-size:13px;line-height:20px}.dd-list{display:block;position:relative;margin:0;padding:0;list-style:none}.dd-list .dd-list{padding-left:30px}.dd-collapsed .dd-list{display:none}.dd-item,.dd-empty,.dd-placeholder{display:block;position:relative;margin:0;padding:0;min-height:20px;font-size:13px;line-height:20px}.dd-handle{display:block;height:30px;margin:5px 0;padding:4px 10px;text-decoration:none;border:1px solid #dbdee0;background:#e9ebec;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.dd-handle:hover{color:#36a9e1;background:white}.dd-handle .icon{float:right;font-size:16px;margin-left:10px}.dd-handle .icon:hover{text-decoration:none}.dd-item>button{display:block;position:relative;cursor:pointer;float:left;width:25px;height:20px;margin:5px 0;padding:0;text-indent:100%;white-space:nowrap;overflow:hidden;border:0;background:transparent;font-size:12px;line-height:1;text-align:center;font-weight:bold}.dd-item>button:before{content:'+';display:block;position:absolute;width:100%;text-align:center;text-indent:0}.dd-item>button[data-action="collapse"]:before{content:'-'}.dd-placeholder,.dd-empty{margin:5px 0;padding:0;min-height:30px;background:#f2fbff;border:1px dashed #b6bcbf;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.dd-empty{border:1px dashed #bbb;min-height:100px;background-color:#e5e5e5;background-size:60px 60px;background-position:0 0,30px 30px}.dd-dragel{position:absolute;pointer-events:none;z-index:9999}.dd-dragel>.dd-item .dd-handle{margin-top:0}.dd-dragel .dd-handle{-webkit-box-shadow:2px 4px 6px 0 rgba(0,0,0,0.1);-moz-box-shadow:2px 4px 6px 0 rgba(0,0,0,0.1);box-shadow:2px 4px 6px 0 rgba(0,0,0,0.1)}.nestable-lists{display:block;clear:both;padding:30px 0;width:100%;border:0;border-top:2px solid #ddd;border-bottom:2px solid #ddd}#nestable-menu{padding:0;margin:20px 0}#nestable-output,#nestable2-output{width:100%;height:7em;font-size:.75em;line-height:1.333333em;font-family:Consolas,monospace;padding:5px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#nestable2 .dd-handle{color:white;border:1px solid #b2b8bd;background:#b2b8bd}#nestable2 .dd-handle:hover{border:1px solid #34383c;background:#34383c}#nestable2 .dd-item>button:before{color:#fff}@media only screen and (min-width:700px){.dd{float:left;width:48%}.dd+.dd{margin-left:2%}}.dd-hover>.dd-handle{background:#2ea8e5!important}.dd3-content{display:block;height:30px;margin:5px 0;padding:5px 10px 5px 40px;text-decoration:none;font-weight:bold;border:1px solid #dbdee0;background:#e9ebec;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.dd3-content:hover{color:#36a9e1;background:#fff}.dd-dragel>.dd3-item>.dd3-content{margin:0}.dd3-item>button{margin-left:30px}.dd3-handle{position:absolute;margin:0;left:0;top:0;cursor:pointer;width:30px;white-space:nowrap;overflow:hidden;border:1px solid #dbdee0;background:#dbdee0;border-top-right-radius:0;border-bottom-right-radius:0;color:white}.dd3-handle:hover{background:#b2b8bd;color:white}.wizard{*zoom:1;position:relative;overflow:hidden;margin-bottom:20px}.wizard:before,.wizard:after{display:table;content:"";line-height:0}.wizard:after{clear:both}.wizard ul{list-style:none outside none;padding:0;margin:0;width:4000px}.wizard ul li{float:left;margin:0;padding:0 20px 0 30px;height:40px;line-height:40px;position:relative;background:#f7f7f8;color:#b2b8bd;font-size:16px;cursor:default}.wizard ul li:first-child{-webkit-border-radius:2px 0 0 2px;-moz-border-radius:2px 0 0 2px;border-radius:2px 0 0 2px}.wizard ul li:last-child{-webkit-border-radius:0 2px 2px 0;-moz-border-radius:0 2px 2px 0;border-radius:0 2px 2px 0}.wizard ul li .chevron{border:48px solid transparent;border-left:28px solid white;border-right:0;display:block;position:absolute;right:-14px;top:-28px;z-index:1}.wizard ul li .chevron:before{border:48px solid transparent;border-left:28px solid #f7f7f8;border-right:0;content:"";display:block;position:absolute;right:5px;top:-48px}.wizard ul li.complete{background:#bdea74;color:white}.wizard ul li.complete:hover{background:#e7eff8;cursor:pointer}.wizard ul li.complete:hover .chevron:before{border-left:28px solid #e7eff8}.wizard ul li.complete .chevron:before{border-left:28px solid #bdea74}.wizard ul li.active{background:#b2b8bd;color:white}.wizard ul li.active .chevron:before{border-left:28px solid #b2b8bd}.wizard ul li .badge{margin-right:8px}.wizard ul li:first-child{border-radius:4px 0 0 4px;padding-left:20px}.wizard .actions{z-index:1000;position:absolute;right:0;line-height:46px;float:right;padding-left:15px;padding-right:15px;vertical-align:middle}.wizard .actions a{line-height:45px;font-size:12px;margin-right:8px}.wizard .actions .btn-prev i{margin-right:5px}.wizard .actions .btn-next i{margin-left:5px}.step-content .step-pane{display:none}.step-content .active{display:block}.step-content .active .btn-group .active{display:inline-block}.datepicker{padding:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;direction:ltr}.datepicker-inline{width:220px}.datepicker.datepicker-rtl{direction:rtl}.datepicker.datepicker-rtl table tr td span{float:right}.datepicker-dropdown{top:0;left:0}.datepicker-dropdown:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-top:0;border-bottom-color:rgba(0,0,0,0.2);position:absolute}.datepicker-dropdown:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;border-top:0;position:absolute}.datepicker-dropdown.datepicker-orient-left:before{left:6px}.datepicker-dropdown.datepicker-orient-left:after{left:7px}.datepicker-dropdown.datepicker-orient-right:before{right:6px}.datepicker-dropdown.datepicker-orient-right:after{right:7px}.datepicker-dropdown.datepicker-orient-top:before{top:-7px}.datepicker-dropdown.datepicker-orient-top:after{top:-6px}.datepicker-dropdown.datepicker-orient-bottom:before{bottom:-7px;border-bottom:0;border-top:7px solid #999}.datepicker-dropdown.datepicker-orient-bottom:after{bottom:-6px;border-bottom:0;border-top:6px solid white}.datepicker>div{display:none}.datepicker.days div.datepicker-days{display:block}.datepicker.months div.datepicker-months{display:block}.datepicker.years div.datepicker-years{display:block}.datepicker table{margin:0;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.datepicker td,.datepicker th{text-align:center;width:20px;height:20px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0}.table-striped .datepicker table tr td,.table-striped .datepicker table tr th{background-color:transparent}.datepicker table tr td.day:hover{background:#eee;cursor:pointer}.datepicker table tr td.old,.datepicker table tr td.new{color:#34383c}.datepicker table tr td.disabled,.datepicker table tr td.disabled:hover{background:0;color:#f9f9f9;cursor:default}.datepicker table tr td.today,.datepicker table tr td.today:hover,.datepicker table tr td.today.disabled,.datepicker table tr td.today.disabled:hover{background:#36a9e1;color:#000}.datepicker table tr td.today:hover:hover{color:#000}.datepicker table tr td.today.active:hover{color:#fff}.datepicker table tr td.range,.datepicker table tr td.range:hover,.datepicker table tr td.range.disabled,.datepicker table tr td.range.disabled:hover{background:#eee;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.datepicker table tr td.range.today,.datepicker table tr td.range.today:hover,.datepicker table tr td.range.today.disabled,.datepicker table tr td.range.today.disabled:hover{background:#f3c17a;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.datepicker table tr td.selected,.datepicker table tr td.selected:hover,.datepicker table tr td.selected.disabled,.datepicker table tr td.selected.disabled:hover{background:#f9f9f9;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.datepicker table tr td.active,.datepicker table tr td.active:hover,.datepicker table tr td.active.disabled,.datepicker table tr td.active.disabled:hover{background:#36a9e1;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.datepicker table tr td span{display:block;width:23%;height:54px;line-height:54px;float:left;margin:1%;cursor:pointer;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.datepicker table tr td span:hover{background:#eee}.datepicker table tr td span.disabled,.datepicker table tr td span.disabled:hover{background:0;color:#f9f9f9;cursor:default}.datepicker table tr td span.active,.datepicker table tr td span.active:hover,.datepicker table tr td span.active.disabled,.datepicker table tr td span.active.disabled:hover{background:#36a9e1;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.datepicker table tr td span.old,.datepicker table tr td span.new{color:#f9f9f9}.datepicker th.datepicker-switch{width:145px}.datepicker thead tr:first-child th,.datepicker tfoot tr th{cursor:pointer}.datepicker thead tr:first-child th:hover,.datepicker tfoot tr th:hover{background:#eee}.datepicker .cw{font-size:10px;width:12px;padding:0 2px 0 5px;vertical-align:middle}.datepicker thead tr:first-child th.cw{cursor:default;background-color:transparent}.input-append.date .add-on i,.input-prepend.date .add-on i{display:block;cursor:pointer;width:16px;height:16px}.input-daterange input{text-align:center}.input-daterange input:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-daterange input:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-daterange .add-on{display:inline-block;width:auto;min-width:16px;height:18px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 white;vertical-align:middle;background-color:#eee;border:1px solid #ccc;margin-left:-5px;margin-right:-5px}.bootstrap-timepicker{position:relative}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu{left:auto;right:0}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before{left:auto;right:12px}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after{left:auto;right:13px}.bootstrap-timepicker .input-group-addon{cursor:pointer;-webkit-border-radius:4px 0 0 4px!important;border-radius:4px 0 0 4px!important;border-right:0}.bootstrap-timepicker-widget.dropdown-menu{padding:2px 3px 2px 2px;margin-left:54px}.bootstrap-timepicker-widget.dropdown-menu.open{display:inline-block}.bootstrap-timepicker-widget.dropdown-menu:before{border-bottom:7px solid rgba(0,0,0,0.2);border-left:7px solid transparent;border-right:7px solid transparent;content:"";display:inline-block;left:9px;position:absolute;top:-7px}.bootstrap-timepicker-widget.dropdown-menu:after{border-bottom:6px solid #fff;border-left:6px solid transparent;border-right:6px solid transparent;content:"";display:inline-block;left:10px;position:absolute;top:-6px}.bootstrap-timepicker-widget a.btn,.bootstrap-timepicker-widget input{border-radius:4px}.bootstrap-timepicker-widget table{width:100%;margin:0}.bootstrap-timepicker-widget table td{text-align:center;height:30px;margin:0;padding:2px}.bootstrap-timepicker-widget table td:not(.separator){min-width:30px}.bootstrap-timepicker-widget table td span{width:100%}.bootstrap-timepicker-widget table td a{border:1px transparent solid;width:100%;display:inline-block;margin:0;padding:8px 0;outline:0;color:#333}.bootstrap-timepicker-widget table td a:hover{text-decoration:none;background-color:#eee;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border-color:#ddd}.bootstrap-timepicker-widget table td a i{margin-top:2px}.bootstrap-timepicker-widget table td input{width:25px;margin:0;text-align:center;border:1px solid #b2b8bd}.bootstrap-timepicker-widget .modal-content{padding:4px}@media(min-width:767px){.bootstrap-timepicker-widget.modal{width:200px;margin-left:-100px}}@media(max-width:767px){.bootstrap-timepicker{width:100%}.bootstrap-timepicker .dropdown-menu{width:100%}}.daterangepicker.dropdown-menu{max-width:none;z-index:3000}.daterangepicker.opensleft .ranges,.daterangepicker.opensleft .calendar{float:left;margin:4px}.daterangepicker.opensright .ranges,.daterangepicker.opensright .calendar{float:right;margin:4px}.daterangepicker .ranges{width:160px;text-align:left}.daterangepicker .ranges .range_inputs>div{float:left}.daterangepicker .ranges .range_inputs>div:nth-child(2){padding-left:11px}.daterangepicker .calendar{display:none;max-width:270px}.daterangepicker .calendar th,.daterangepicker .calendar td{font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;white-space:nowrap;text-align:center;min-width:32px}.daterangepicker .ranges label{color:#333;display:block;font-size:11px;font-weight:normal;height:20px;line-height:20px;margin-bottom:2px;text-shadow:#fff 1px 1px 0;text-transform:uppercase;width:74px}.daterangepicker .ranges input{font-size:11px}.daterangepicker .ranges .input-mini{background-color:#eee;border:1px solid #ccc;border-radius:4px;color:#555;display:block;font-size:11px;height:30px;line-height:30px;vertical-align:middle;margin:0 0 10px 0;padding:0 6px;width:74px}.daterangepicker .ranges ul{list-style:none;margin:0;padding:0}.daterangepicker .ranges li{font-size:13px;background:#f5f5f5;border:1px solid #f5f5f5;color:#08c;padding:3px 12px;margin-bottom:8px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;cursor:pointer}.daterangepicker .ranges li.active,.daterangepicker .ranges li:hover{background:#08c;border:1px solid #08c;color:#fff}.daterangepicker .calendar-date{border:1px solid #ddd;padding:4px;border-radius:4px;background:#fff}.daterangepicker .calendar-time{text-align:center;margin:8px auto 0 auto;line-height:30px}.daterangepicker{position:absolute;background:#fff;top:100px;left:20px;padding:4px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.daterangepicker.opensleft:before{position:absolute;top:-7px;right:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.daterangepicker.opensleft:after{position:absolute;top:-6px;right:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.daterangepicker.opensright:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.daterangepicker.opensright:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.daterangepicker table{width:100%;margin:0}.daterangepicker td,.daterangepicker th{text-align:center;width:20px;height:20px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;cursor:pointer;white-space:nowrap}.daterangepicker td.off{color:#999}.daterangepicker td.disabled{color:#999}.daterangepicker td.available:hover,.daterangepicker th.available:hover{background:#eee}.daterangepicker td.in-range{background:#ebf4f8;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.daterangepicker td.active,.daterangepicker td.active:hover{background-color:#357ebd;border-color:#3071a9;color:#fff}.daterangepicker td.week,.daterangepicker th.week{font-size:80%;color:#ccc}.daterangepicker select.monthselect,.daterangepicker select.yearselect{font-size:12px;padding:1px;height:auto;margin:0;cursor:default}.daterangepicker select.monthselect{margin-right:2%;width:56%}.daterangepicker select.yearselect{width:40%}.daterangepicker select.hourselect,.daterangepicker select.minuteselect,.daterangepicker select.ampmselect{width:50px;margin-bottom:0}.colorpicker-saturation{width:100px;height:100px;background-image:url(../img/saturation.png);cursor:crosshair;float:left}.colorpicker-saturation i{display:block;height:5px;width:5px;border:1px solid #000;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;position:absolute;top:0;left:0;margin:-4px 0 0 -4px}.colorpicker-saturation i b{display:block;height:5px;width:5px;border:1px solid #fff;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.colorpicker-hue,.colorpicker-alpha{width:15px;height:100px;float:left;cursor:row-resize;margin-left:4px;margin-bottom:4px}.colorpicker-hue i,.colorpicker-alpha i{display:block;height:1px;background:#000;border-top:1px solid #fff;position:absolute;top:0;left:0;width:100%;margin-top:-1px}.colorpicker-hue{background-image:url(../img/hue.png)}.colorpicker-alpha{background-image:url(../img/alpha.png);display:none}.colorpicker{*zoom:1;top:0;left:0;padding:4px;min-width:120px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.colorpicker:before,.colorpicker:after{display:table;content:"";line-height:0}.colorpicker:after{clear:both}.colorpicker:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:6px}.colorpicker:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;top:-6px;left:7px}.colorpicker div{position:relative}.colorpicker.alpha{min-width:140px}.colorpicker.alpha .colorpicker-alpha{display:block}.colorpicker-color{height:10px;margin-top:5px;clear:both;background-image:url(../img/alpha.png);background-position:0 100%}.colorpicker-color div{height:10px}.input-append.color .add-on i,.input-prepend.color .add-on i{display:block;cursor:pointer;width:16px;height:16px}.input-group.color .input-group-addon i{display:block;cursor:pointer;width:13px}.inbox .inbox-menu{background:#e9ebec;border-right:1px solid #dbdee0;padding-top:30px}.inbox .inbox-menu .btn{width:100%}.inbox .inbox-menu ul{margin-top:30px;padding:0;list-style:none}.inbox .inbox-menu ul li{height:30px;margin:0 -15px;padding:5px 15px;position:relative}.inbox .inbox-menu ul li:hover,.inbox .inbox-menu ul li.active{background:#dbdee0}.inbox .inbox-menu ul li.title{margin:20px -15px -10px -15px;text-transform:uppercase;font-size:10px;color:#b2b8bd}.inbox .inbox-menu ul li.title:hover{background:transparent}.inbox .inbox-menu ul li a{display:block;width:100%;text-decoration:none;color:#34383c}.inbox .inbox-menu ul li a i{margin-right:10px}.inbox .inbox-menu ul li a .label{position:absolute;top:10px;right:15px;display:block;min-width:14px;height:14px;padding:2px}.inbox .buttons{margin:30px 0}.inbox .buttons .btn,.inbox .buttons .btn-group .btn{border:1px solid #dbdee0}.inbox .buttons .btn-group .caret{border-top-color:#7c848d;margin-top:-4px;margin-left:5px}.inbox .messages{background:white;margin:0;border-right:1px solid #dbdee0}.inbox ul.messages-list{list-style:none;padding:0}.inbox ul.messages-list li{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;cursor:pointer;margin-bottom:10px;padding:10px}.inbox ul.messages-list li.unread .header,.inbox ul.messages-list li.unread .title{font-weight:bold}.inbox ul.messages-list li.active{background:#e9ebec;border:1px solid #dbdee0;padding:9px}.inbox ul.messages-list li.active .action{color:#c0c4c8}.inbox ul.messages-list li .header{margin:0 0 5px 0}.inbox ul.messages-list li .header .from{width:49.9%;white-space:nowrap;overflow:hidden!important;text-overflow:ellipsis}.inbox ul.messages-list li .header .date{width:50%;text-align:right;float:right}.inbox ul.messages-list li .title{margin:0 0 5px 0;white-space:nowrap;overflow:hidden!important;text-overflow:ellipsis}.inbox ul.messages-list li .description{font-size:12px;padding-left:29px}.inbox ul.messages-list li .action{display:inline-block;width:16px;text-align:center;margin-right:10px;color:#dbdee0}.inbox ul.messages-list li .action .fa-check-square-o{margin:0 -1px 0 1px}.inbox ul.messages-list li .action .fa-square{float:left;margin-top:-16px;margin-left:4px;font-size:11px;color:white}.inbox ul.messages-list li .action .fa-star.bg{float:left;margin-top:-16px;margin-left:3px;font-size:12px;color:white}.inbox .message{margin:0;background:white;border-right:1px solid #dbdee0}.inbox .message textarea{color:#34383c!important}.inbox .message .message-title{padding-top:10px;font-weight:bold;font-size:14px}.inbox .message .header{margin:20px 0 30px 0;padding:10px 0 10px 0;border-top:1px solid #e9ebec;border-bottom:1px solid #e9ebec}.inbox .message .header .avatar{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;height:34px;width:34px;float:left;margin-right:10px}.inbox .message .header i{margin-top:1px}.inbox .message .header .from{display:inline-block;width:50%;font-size:12px;margin-top:-2px;color:#b2b8bd}.inbox .message .header .from span{display:block;font-size:14px;font-weight:bold;color:#34383c}.inbox .message .header .date{display:inline-block;width:29%;text-align:right;float:right;font-size:12px;margin-top:18px}.inbox .message .attachments{border-top:3px solid #f9f9f9;border-bottom:3px solid #f9f9f9;padding:10px 0;margin-bottom:20px;font-size:12px}.inbox .message .attachments ul{list-style:none;margin:0 0 0 -40px}.inbox .message .attachments ul li{margin:10px 0}.inbox .message .attachments ul li .label{padding:2px 4px}.inbox .message .attachments ul li span.quickMenu{float:right;text-align:right}.inbox .message .attachments ul li span.quickMenu .glyphicons{padding:5px 0 5px 25px}.inbox .message .attachments ul li span.quickMenu .glyphicons:before{font-size:14px;margin:-2px 0 0 5px;color:#b2b8bd}.inbox .contacts{background:#e9ebec;padding-top:30px}.inbox .contacts .btn{width:100%;margin-bottom:30px}.inbox .contacts ul{padding:0;list-style:none}.inbox .contacts ul li{height:30px;margin:0 -15px;padding:5px 15px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis!important;position:relative;cursor:pointer}.inbox .contacts ul li .label{display:inline-block;width:6px;height:6px;padding:0;margin:0 5px 2px 0}.inbox .contacts ul li:hover{background:#dbdee0}.invoice .header .well p{padding:0;margin:0}.invoice table{margin-bottom:20px!important}.page-todo .tasks{background:white;padding:0;border-right:1px solid #dbdee0;margin:-30px 15px -30px -15px}.page-todo .task-list{padding:30px 15px;height:100%}.page-todo .graph{height:100%}.page-todo .priority.high{background:#ffeded;margin-bottom:1px}.page-todo .priority.high span{background:#ff5454;padding:2px 10px;color:white;display:inline-block;font-size:12px}.page-todo .priority.medium{background:#fef8eb;margin-bottom:1px}.page-todo .priority.medium span{background:#fabb3d;padding:2px 10px;color:white;display:inline-block;font-size:12px}.page-todo .priority.low{background:#e4f5dc;margin-bottom:1px}.page-todo .priority.low span{background:#78cd51;padding:2px 10px;color:white;display:inline-block;font-size:12px}.page-todo .task{border-bottom:1px solid #f9f9f9;margin-bottom:1px;position:relative}.page-todo .task .desc{display:inline-block;width:75%;padding:10px 10px;font-size:12px}.page-todo .task .desc .title{font-size:18px;margin-bottom:5px}.page-todo .task .time{display:inline-block;width:15%;padding:10px 10px 10px 0;font-size:12px;text-align:right;position:absolute;top:0;right:0}.page-todo .task .time .date{font-size:18px;margin-bottom:5px}.page-todo .task.last{border-bottom:1px solid transparent}.page-todo .task.high{border-left:2px solid #ff5454}.page-todo .task.medium{border-left:2px solid #fabb3d}.page-todo .task.low{border-left:2px solid #78cd51}.page-todo .timeline{width:auto;height:100%;margin:20px auto;position:relative}.page-todo .timeline:before{position:absolute;content:'';height:100%;width:4px;background:#e9ebec;left:50%;margin-left:-2px}.page-todo .timeslot{display:inline-block;position:relative;width:100%;margin:5px 0}.page-todo .timeslot .task{position:absolute;width:42%;padding-right:18px;display:block;height:auto;border:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.page-todo .timeslot .task span{border:2px solid #67c2ef;background:#f1fafe;padding:5px;display:block;font-size:11px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.page-todo .timeslot .task span span.details{font-size:16px;margin-bottom:10px}.page-todo .timeslot .task span span.remaining{font-size:14px}.page-todo .timeslot .task span span{border:0;background:transparent;padding:0}.page-todo .timeslot .task .arrow{position:absolute;top:6px;right:0;height:20px;width:20px;background:url(../img/timeline-left-arrow.png) no-repeat}.page-todo .timeslot .icon{position:absolute;border:2px solid #b2b8bd;background:#34383c;-webkit-border-radius:50em;-moz-border-radius:50em;border-radius:50em;height:30px;width:30px;left:50%;margin-left:-16px;color:white;font-size:14px;line-height:30px;text-align:center;text-shadow:none;z-index:2;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.page-todo .timeslot .time{background:#e9ebec;position:absolute;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;top:1px;left:50%;padding:5px 10px 5px 40px;z-index:1;margin-top:1px}.page-todo .timeslot.alt .task{left:auto;right:-20px;padding-left:18px;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.page-todo .timeslot.alt .task .arrow{position:absolute;top:6px;left:0;height:20px;width:20px;background:url(../img/timeline-right-arrow.png) no-repeat}.page-todo .timeslot.alt .time{top:1px;left:auto;right:50%;padding:5px 40px 5px 10px}@media only screen and (min-width:992px) and (max-width:1199px){.page-todo task .desc{display:inline-block;width:70%;padding:10px 10px;font-size:12px}.page-todo task .desc .title{font-size:16px;margin-bottom:5px}.page-todo task .time{display:inline-block;float:right;width:20%;padding:10px 10px;font-size:12px;text-align:right}.page-todo task .time .date{font-size:16px;margin-bottom:5px}}@media only screen and (min-width:768px) and (max-width:991px){.page-todo .task{border-bottom:1px solid #f9f9f9;margin-bottom:1px}.page-todo .task .desc{display:inline-block;width:65%;padding:10px 10px;font-size:10px;margin-right:-20px}.page-todo .task .desc .title{font-size:14px;margin-bottom:5px}.page-todo .task .time{display:inline-block;float:right;width:25%;padding:10px 10px;font-size:10px;text-align:right}.page-todo .task .time .date{font-size:14px;margin-bottom:5px}.page-todo .timeslot .task span{border:2px solid #67c2ef;background:rgba(103,194,239,0.1);padding:5px;display:block;font-size:10px}.page-todo .timeslot .task span span{border:0;background:transparent;padding:0}.page-todo .timeslot .task span span.details{font-size:14px;margin-bottom:0}.page-todo .timeslot .task span span.remaining{font-size:12px}}@media only screen and (max-width:767px){.page-todo .tasks{position:relative;margin:0!important}.page-todo .graph{position:relative;margin:0!important}.page-todo .task{border-bottom:1px solid #f9f9f9;margin-bottom:1px}.page-todo .task .desc{display:inline-block;width:65%;padding:10px 10px;font-size:10px;margin-right:-20px}.page-todo .task .desc .title{font-size:14px;margin-bottom:5px}.page-todo .task .time{display:inline-block;float:right;width:25%;padding:10px 10px;font-size:10px;text-align:right}.page-todo .task .time .date{font-size:14px;margin-bottom:5px}.page-todo .timeslot .task span{padding:5px;display:block;font-size:10px}.page-todo .timeslot .task span span{border:0;background:transparent;padding:0}.page-todo .timeslot .task span span.details{font-size:14px;margin-bottom:0}.page-todo .timeslot .task span span.remaining{font-size:12px}}.profile-image{width:100%;border:5px solid white;outline:1px solid #dbdee0}.profile h3{padding:0 5px}ul.profile-details{margin-top:10px;padding:0 5px;list-style:none;color:#7c848d}ul.profile-details li{position:relative;margin:0 0 20px 0;padding-left:22px}ul.profile-details li div{color:#b2b8bd}ul.profile-details li div i{position:absolute;top:4px;left:-5px;color:#ced1d4;width:20px;text-align:center}ul.profile-details li input[type="text"]{color:black!important}ul.friends-list{padding:0;list-style:none}ul.friends-list li{width:auto;min-width:170px;margin-bottom:20px;border:1px solid #e9ebec;background:#f7f7f8;float:left;padding:5px;margin:0 0 5px 5px;white-space:nowrap;overflow:hidden}ul.friends-list li:last-child{margin-bottom:0}ul.friends-list li .avatar{float:left;margin-right:10px;width:40px}ul.friends-list li .avatar img{width:40px}ul.friends-list li a{display:inline-block;font-size:22px;line-height:8px;text-decoration:none;color:#b2b8bd}.login-box,.register-box{width:400px;padding:20px;margin:100px auto;background:#fff}.login-box .header,.register-box .header{background:#34383c;color:white;text-align:center;margin:-20px -20px 20px -20px;padding:15px;text-transform:uppercase}.login-box form.login input[type="text"],.register-box form.login input[type="text"],.login-box form.login input[type="password"],.register-box form.login input[type="password"]{border-right:none!important;-webkit-border-radius:2px 0 0 2px;-moz-border-radius:2px 0 0 2px;border-radius:2px 0 0 2px}.login-box form.login .input-group-addon,.register-box form.login .input-group-addon{height:0!important;border:1px solid #e9ebec!important;background:white;-webkit-border-radius:0 2px 2px 0;-moz-border-radius:0 2px 2px 0;border-radius:0 2px 2px 0;border-left:1px none!important;margin-left:-1px!important}.login-box label,.register-box label{margin:10px 5px -10px 5px}.login-box input[type="text"],.register-box input[type="text"],.login-box input[type="password"],.register-box input[type="password"]{border:1px solid #e9ebec;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;padding:0 10px;height:40px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.login-box input[type="text"]:focus,.register-box input[type="text"]:focus,.login-box input[type="password"]:focus,.register-box input[type="password"]:focus{outline:0}.login-box .confirm,.register-box .confirm{position:relative;margin:20px 0 10px -15px}.login-box .confirm label,.register-box .confirm label{position:absolute;top:-9px;left:30px}.login-box form.register .input-group-addon,.register-box form.register .input-group-addon{height:0!important;width:35%;border:1px solid #e9ebec!important;background:#e9ebec!important;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.login-box button,.register-box button{margin:15px 0!important}.price-table.type1{margin-top:22px;padding-left:1px}.price-table.type1 ul{position:relative;z-index:1;list-style:none;float:left;margin:0 -1px 0 -1px;padding:0;text-align:center;border:1px solid #dbdee0;background:#f3f3f3}.price-table.type1 ul li:nth-child(2n+1){background:#e9ebec}.price-table.type1 ul li.price{background:#34383c;color:white;font-size:18px;font-weight:bold;text-shadow:none;padding:20px 0;height:58px}.price-table.type1 ul li.strike{text-decoration:line-through}.price-table.type1 ul li{font-size:12px;text-shadow:none;padding:10px 0}.price-table.type1 ul li span{font-weight:bold}.price-table.type1 ul.best-option{border:3px solid #36a9e1;margin:-27px -3px 0 -3px;z-index:2}.price-table.type1 ul.best-option li.header{font-size:16px;font-weight:bold;padding:20px 0;position:relative;overflow:hidden}.price-table.type1 ul.best-option li.header span{font-size:10px;line-height:12px;position:absolute;top:-20px;left:-141px;background:#36a9e1;color:white;padding:30px 130px 5px 130px;-webkit-transform:rotate(315deg);-moz-transform:rotate(315deg);-ms-transform:rotate(315deg);-o-transform:rotate(315deg)}.price-table.type1 ul.best-option li.price{font-size:24px;font-weight:bold;padding:20px 0;background:#36a9e1}.price-table.type2{margin-top:22px;padding-left:1px}.price-table.type2 ul{position:relative;z-index:1;list-style:none;float:left;margin:0 -1px 0 -1px;padding:0;text-align:center;border:1px solid #ced1d4;background:white}.price-table.type2 ul li.header{background:#b2b8bd;color:white;font-size:20px;padding-bottom:70px;margin-bottom:60px}.price-table.type2 ul li.price{background:#b2b8bd;color:white;font-size:40px;font-weight:bold;padding:26px 0;border:4px solid #e9ebec;-webkit-border-radius:50em;-moz-border-radius:50em;border-radius:50em;display:inline-block;height:116px;width:116px;top:45px;left:50%;margin-left:-54px;position:absolute}.price-table.type2 ul li.price span{font-size:20px}.price-table.type2 ul li.strike{text-decoration:line-through}.price-table.type2 ul li{font-size:12px;padding:10px 0;border-bottom:1px solid #e9ebec;background:white}.price-table.type2 ul li span{font-weight:bold}.price-table.type2 ul li.select{position:relative;background:#b2b8bd;padding:0}.price-table.type2 ul li.select a{color:white;font-weight:700;font-size:14px;text-decoration:none;display:block;width:100%;height:100%;padding:10px 0}.price-table.type2 ul li.select:before{content:'';position:absolute;border-left:10px solid transparent;border-right:10px solid transparent;border-bottom:10px solid #b2b8bd;top:-10px;left:50%;margin-left:-5px}.price-table.type2 ul li.select:hover{background:#b2b8bd}.price-table.type2 ul li.select:hover:before{border-bottom:10px solid #b2b8bd}.price-table.type2 ul.best-option li.header{font-weight:bold;position:relative;background:#92d721}.price-table.type2 ul.best-option li.price{font-weight:bold;background:#bdea74;border:4px solid #a8e348}.price-table.type2 ul.best-option li.select{position:relative;background:#92d721}.price-table.type2 ul.best-option li.select:before{border-bottom:10px solid #92d721}.price-table.type2 ul.best-option li.select:hover{background:#74ab1a}.price-table.type2 ul.best-option li.select:hover:before{border-bottom:10px solid #74ab1a}.price-table.five ul{width:20%}.price-table.four ul{width:25%}.price-table.three ul{width:33.333%}.price-table.two ul{width:50%}.price-table.one ul{width:100%}.box-error{margin-top:200px}.box-error h1{float:left;font-size:48px;margin-right:20px}.box-error p{margin-top:-8px;font-weight:300}.login-box-locked{position:relative;z-index:9999;background:rgba(255,255,255,0.9);padding:30px;border:1px solid #e9ebec;margin-top:250px}.login-box-locked.type2{background:rgba(255,255,255,0.7)}.login-box-locked img.avatar{float:left;width:120px;margin-right:20px}.login-box-locked p{margin-top:-8px;font-weight:300}.login-box-locked a{display:block;font-weight:300;margin-top:5px;font-size:12px}@media(min-width:1200px){.hidden-xs,.hidden-sm,.hidden-md,.hidden-lg{display:inline-block!important}a.navbar-brand{position:absolute;width:14.422%;left:15px}.navbar-collapse{max-height:100%}.container{width:100%!important}.container #content{padding:30px;margin:0;height:100%;width:85.578%}.container #sidebar-left{width:14.422%}.container .breadcrumb{margin:-30px -30px 30px -30px;padding:10px 30px}}@media only screen and (min-width:992px) and (max-width:1199px){.hidden-xs,.hidden-sm,.hidden-md,.hidden-lg{display:inline-block!important}a.navbar-brand{position:absolute;width:14.422%;left:15px}.navbar-collapse{max-height:100%}.container{width:100%!important}.container #content{padding:30px;margin:0;height:100%;width:85.578%}.container #sidebar-left{width:14.422%}.container .breadcrumb{margin:-30px -30px 30px -30px;padding:10px 30px}}@media only screen and (min-width:768px) and (max-width:991px){a#main-menu-toggle{margin-left:8.334%}a.navbar-brand{width:8.334%;padding:8px 0!important;position:absolute;left:15px}a.navbar-brand span{font-size:12px}.navbar-collapse{max-height:100%}.container{width:100%!important}.container #content{padding:30px}.container #sidebar-left{margin-left:0!important;width:8.334%!important}.container .breadcrumb{margin:-30px -30px 30px -30px;padding:10px 30px}.sidebar-nav>ul{margin:-9px -10px;border:0;padding-bottom:1px;font-size:18px}.nav.main-menu>li>ul>li,.nav.main-menu>li>ul>li>ul>li,.nav.main-menu>li>ul>li>ul>li>ul>li{width:100%}.nav.main-menu>li>a>i,.nav.main-menu>li>ul>li>a>i,.nav.main-menu>li>ul>li>ul>li>a>i,.nav.main-menu>li>ul>li>ul>li>ul>li>a>i{height:38px;width:100%;padding:11px 0;display:inline-block;text-align:center;border-right:1px solid #dbdee0}.btn-navbar{display:none!important}.nav-collapse,.nav-collapse.collapse{height:auto!important;overflow:visible!important;margin-left:-20px!important}.sidebar-nav{padding:0;margin-bottom:0}}@media only screen and (max-width:767px){body:after,body:before{display:none}a.navbar-brand{margin-bottom:0}#search{margin-left:10px!important}.hidden-sm{display:inline-block!important}.navbar-toggle{position:absolute;top:-3px;right:-10px;z-index:100;background:transparent!important;text-shadow:none!important;border:none!important}.navbar-toggle .icon-bar{background:white}.navbar-collapse{max-height:300px;border-top:0;box-shadow:none;overflow-x:hidden;padding-right:0;padding-left:0}.header-nav{display:none}.header-nav li{float:left}.pull-right{width:100%;margin:10px auto;text-align:center}#content{overflow:hidden}#content .breadcrumb{margin:-4px -5px 30px -5px}#sidebar-left{min-height:0;padding:0!important}.sidebar-nav{border-bottom:1px solid #dbdee0}.sidebar-nav>ul{margin:0;background:#f3f3f3}.message-view{margin:0}.price-table-overlay{width:100%!important;overflow-x:scroll}.price-table.five{width:1000px}.price-table.four{width:800px}.price-table.three{width:900px}.price-table.five ul{width:200px}.price-table.four ul{width:200px}.price-table.three ul{width:300px}.price-table.two ul{width:50%}.price-table.one ul{width:100%}}@media only screen and (min-width:480px) and (max-width:767px){body{padding:0}#content{padding:5px}}@media only screen and (max-width:479px){body{padding:0}.col-xxs-12{width:100%}a.navbar-brand{background:transparent}a.navbar-brand:hover{background:transparent}#search select{display:none}#search input{margin-top:5px;margin-left:-10px!important;width:100%!important}#content{padding:5px}.quick-button,.quick-button-small{margin-bottom:20px}.discussions ul li .date{display:none}} diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/style.min.less b/gridplatform/bootstrap/static/bootstrap/genius/css/style.min.less new file mode 100644 index 0000000..a108660 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/style.min.less @@ -0,0 +1 @@ +@import "style.less"; \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/uploadify.css b/gridplatform/bootstrap/static/bootstrap/genius/css/uploadify.css new file mode 100755 index 0000000..1df3e3e --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/uploadify.css @@ -0,0 +1,92 @@ +/* +Uploadify +Copyright (c) 2012 Reactive Apps, Ronnie Garcia +Released under the MIT License +*/ + +.uploadify { + position: relative; + margin-bottom: 1em; +} +.uploadify-button { + background-color: #505050; + background-image: linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -o-linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -moz-linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -webkit-linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -ms-linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -webkit-gradient( + linear, + left bottom, + left top, + color-stop(0, #505050), + color-stop(1, #707070) + ); + background-position: center top; + background-repeat: no-repeat; + -webkit-border-radius: 30px; + -moz-border-radius: 30px; + border-radius: 30px; + border: 2px solid #808080; + color: #FFF; + font: bold 12px Arial, Helvetica, sans-serif; + text-align: center; + text-shadow: 0 -1px 0 rgba(0,0,0,0.25); + width: 100%; +} +.uploadify:hover .uploadify-button { + background-color: #606060; + background-image: linear-gradient(top, #606060 0%, #808080 100%); + background-image: -o-linear-gradient(top, #606060 0%, #808080 100%); + background-image: -moz-linear-gradient(top, #606060 0%, #808080 100%); + background-image: -webkit-linear-gradient(top, #606060 0%, #808080 100%); + background-image: -ms-linear-gradient(top, #606060 0%, #808080 100%); + background-image: -webkit-gradient( + linear, + left bottom, + left top, + color-stop(0, #606060), + color-stop(1, #808080) + ); + background-position: center bottom; +} +.uploadify-button.disabled { + background-color: #D0D0D0; + color: #808080; +} +.uploadify-queue { + margin-bottom: 1em; +} +.uploadify-queue-item { + background-color: #F5F5F5; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + font: 11px Verdana, Geneva, sans-serif; + margin-top: 5px; + max-width: 350px; + padding: 10px; +} +.uploadify-error { + background-color: #FDE5DD !important; +} +.uploadify-queue-item .cancel a { + background: url('../img/uploadify-cancel.png') 0 0 no-repeat; + float: right; + height: 16px; + text-indent: -9999px; + width: 16px; +} +.uploadify-queue-item.completed { + background-color: #E5E5E5; +} +.uploadify-progress { + background-color: #E5E5E5; + margin-top: 10px; + width: 100%; +} +.uploadify-progress-bar { + background-color: #0099FF; + height: 3px; + width: 1px; +} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/css/xcharts.min.css b/gridplatform/bootstrap/static/bootstrap/genius/css/xcharts.min.css new file mode 100644 index 0000000..42f6f79 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/css/xcharts.min.css @@ -0,0 +1 @@ +.xchart .line{stroke-width:3px;fill:none}.xchart .fill{stroke-width:0}.xchart circle{stroke:#FFF;stroke-width:3px}.xchart .axis .domain{fill:none}.xchart .axis .tick line{stroke:#EEE;stroke-width:1px}.xchart .axis text{font-family:Helvetica,Arial,Verdana,sans-serif;fill:#666;font-size:12px}.xchart .color0 .line{stroke:#3880aa}.xchart .color0 .line .fill{pointer-events:none}.xchart .color0 rect,.xchart .color0 circle{fill:#3880aa}.xchart .color0 .fill{fill:rgba(56,128,170,0.1)}.xchart .color0.comp .line{stroke:#89bbd8}.xchart .color0.comp rect{fill:#89bbd8}.xchart .color0.comp .fill{display:none}.xchart .color0.comp circle,.xchart .color0.comp .pointer{fill:#89bbd8}.xchart .color1 .line{stroke:#4da944}.xchart .color1 .line .fill{pointer-events:none}.xchart .color1 rect,.xchart .color1 circle{fill:#4da944}.xchart .color1 .fill{fill:rgba(77,169,68,0.1)}.xchart .color1.comp .line{stroke:#9dd597}.xchart .color1.comp rect{fill:#9dd597}.xchart .color1.comp .fill{display:none}.xchart .color1.comp circle,.xchart .color1.comp .pointer{fill:#9dd597}.xchart .color2 .line{stroke:#f26522}.xchart .color2 .line .fill{pointer-events:none}.xchart .color2 rect,.xchart .color2 circle{fill:#f26522}.xchart .color2 .fill{fill:rgba(242,101,34,0.1)}.xchart .color2.comp .line{stroke:#f9b99a}.xchart .color2.comp rect{fill:#f9b99a}.xchart .color2.comp .fill{display:none}.xchart .color2.comp circle,.xchart .color2.comp .pointer{fill:#f9b99a}.xchart .color3 .line{stroke:#c6080d}.xchart .color3 .line .fill{pointer-events:none}.xchart .color3 rect,.xchart .color3 circle{fill:#c6080d}.xchart .color3 .fill{fill:rgba(198,8,13,0.1)}.xchart .color3.comp .line{stroke:#f8555a}.xchart .color3.comp rect{fill:#f8555a}.xchart .color3.comp .fill{display:none}.xchart .color3.comp circle,.xchart .color3.comp .pointer{fill:#f8555a}.xchart .color4 .line{stroke:#672d8b}.xchart .color4 .line .fill{pointer-events:none}.xchart .color4 rect,.xchart .color4 circle{fill:#672d8b}.xchart .color4 .fill{fill:rgba(103,45,139,0.1)}.xchart .color4.comp .line{stroke:#a869ce}.xchart .color4.comp rect{fill:#a869ce}.xchart .color4.comp .fill{display:none}.xchart .color4.comp circle,.xchart .color4.comp .pointer{fill:#a869ce}.xchart .color5 .line{stroke:#ce1797}.xchart .color5 .line .fill{pointer-events:none}.xchart .color5 rect,.xchart .color5 circle{fill:#ce1797}.xchart .color5 .fill{fill:rgba(206,23,151,0.1)}.xchart .color5.comp .line{stroke:#f075cb}.xchart .color5.comp rect{fill:#f075cb}.xchart .color5.comp .fill{display:none}.xchart .color5.comp circle,.xchart .color5.comp .pointer{fill:#f075cb}.xchart .color6 .line{stroke:#d9ce00}.xchart .color6 .line .fill{pointer-events:none}.xchart .color6 rect,.xchart .color6 circle{fill:#d9ce00}.xchart .color6 .fill{fill:rgba(217,206,0,0.1)}.xchart .color6.comp .line{stroke:#fff75a}.xchart .color6.comp rect{fill:#fff75a}.xchart .color6.comp .fill{display:none}.xchart .color6.comp circle,.xchart .color6.comp .pointer{fill:#fff75a}.xchart .color7 .line{stroke:#754c24}.xchart .color7 .line .fill{pointer-events:none}.xchart .color7 rect,.xchart .color7 circle{fill:#754c24}.xchart .color7 .fill{fill:rgba(117,76,36,0.1)}.xchart .color7.comp .line{stroke:#c98c50}.xchart .color7.comp rect{fill:#c98c50}.xchart .color7.comp .fill{display:none}.xchart .color7.comp circle,.xchart .color7.comp .pointer{fill:#c98c50}.xchart .color8 .line{stroke:#2eb9b4}.xchart .color8 .line .fill{pointer-events:none}.xchart .color8 rect,.xchart .color8 circle{fill:#2eb9b4}.xchart .color8 .fill{fill:rgba(46,185,180,0.1)}.xchart .color8.comp .line{stroke:#86e1de}.xchart .color8.comp rect{fill:#86e1de}.xchart .color8.comp .fill{display:none}.xchart .color8.comp circle,.xchart .color8.comp .pointer{fill:#86e1de}.xchart .color9 .line{stroke:#0e2e42}.xchart .color9 .line .fill{pointer-events:none}.xchart .color9 rect,.xchart .color9 circle{fill:#0e2e42}.xchart .color9 .fill{fill:rgba(14,46,66,0.1)}.xchart .color9.comp .line{stroke:#2477ab}.xchart .color9.comp rect{fill:#2477ab}.xchart .color9.comp .fill{display:none}.xchart .color9.comp circle,.xchart .color9.comp .pointer{fill:#2477ab} .xchart .errorLine path {stroke: #C6080D;stroke-width: 3px;}.ex-tooltip{position:absolute;background:#EEE;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;border-radius:3px;padding:5px;-webkit-box-shadow:0 1px 3px #000;-moz-box-shadow:0 1px 3px #000;-ms-box-shadow:0 1px 3px #000;-o-box-shadow:0 1px 3px #000;box-shadow:0 1px 3px #000;border-collapse:separate;display:none} \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/FontAwesome.otf b/gridplatform/bootstrap/static/bootstrap/genius/fonts/FontAwesome.otf new file mode 100644 index 0000000..8b0f54e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/FontAwesome.otf differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.eot b/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.eot new file mode 100755 index 0000000..7c79c6a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.eot differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.svg b/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.svg new file mode 100755 index 0000000..45fdf33 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.svg @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.ttf b/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.ttf new file mode 100755 index 0000000..e89738d Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.ttf differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.woff b/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.woff new file mode 100755 index 0000000..8c1748a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/fontawesome-webfont.woff differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-filetypes-regular.eot b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-filetypes-regular.eot new file mode 100755 index 0000000..8a5a310 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-filetypes-regular.eot differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-filetypes-regular.svg b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-filetypes-regular.svg new file mode 100755 index 0000000..aba8fd0 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-filetypes-regular.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-filetypes-regular.woff b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-filetypes-regular.woff new file mode 100755 index 0000000..d9c8035 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-filetypes-regular.woff differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.eot b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.eot new file mode 100755 index 0000000..87eaa43 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.eot differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.svg b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.svg new file mode 100755 index 0000000..5fee068 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.ttf b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.ttf new file mode 100755 index 0000000..be784dc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.ttf differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.woff b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.woff new file mode 100755 index 0000000..2cc3e48 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-halflings-regular.woff differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.eot b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.eot new file mode 100755 index 0000000..1a35ef8 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.eot differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.otf b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.otf new file mode 100644 index 0000000..b428a69 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.otf differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.svg b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.svg new file mode 100755 index 0000000..37a1f18 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.svg @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.ttf b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.ttf new file mode 100755 index 0000000..05d3daf Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.ttf differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.woff b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.woff new file mode 100755 index 0000000..c0114ce Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-regular.woff differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.eot b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.eot new file mode 100755 index 0000000..109f8e8 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.eot differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.svg b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.svg new file mode 100755 index 0000000..ab2e5e6 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.ttf b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.ttf new file mode 100755 index 0000000..21a05b6 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.ttf differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.woff b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.woff new file mode 100755 index 0000000..2ccc999 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphicons-social-regular.woff differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.eot b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.eot new file mode 100755 index 0000000..bd59ccd Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.eot differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.otf b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.otf new file mode 100644 index 0000000..b058f1c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.otf differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.svg b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.svg new file mode 100755 index 0000000..0fb4587 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.ttf b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.ttf new file mode 100755 index 0000000..c63c068 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.ttf differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.woff b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.woff new file mode 100755 index 0000000..4c778ff Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/fonts/glyphiconshalflings-regular.woff differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-114-precomposed.png b/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-114-precomposed.png new file mode 100644 index 0000000..8cdf1f3 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-114-precomposed.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-144-precomposed.png b/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-144-precomposed.png new file mode 100644 index 0000000..1a70c6b Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-144-precomposed.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-57-precomposed.png b/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-57-precomposed.png new file mode 100644 index 0000000..923aa5a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-57-precomposed.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-72-precomposed.png b/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-72-precomposed.png new file mode 100644 index 0000000..18cf8c8 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/ico/apple-touch-icon-72-precomposed.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/ico/favicon.png b/gridplatform/bootstrap/static/bootstrap/genius/ico/favicon.png new file mode 100644 index 0000000..5e2c0a9 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/ico/favicon.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/Sorting icons.psd b/gridplatform/bootstrap/static/bootstrap/genius/img/Sorting icons.psd new file mode 100644 index 0000000..53b2e06 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/Sorting icons.psd differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/alpha.png b/gridplatform/bootstrap/static/bootstrap/genius/img/alpha.png new file mode 100755 index 0000000..38043f1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/alpha.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/animated-overlay.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/animated-overlay.gif new file mode 100755 index 0000000..d441f75 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/animated-overlay.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/arrows-active.png b/gridplatform/bootstrap/static/bootstrap/genius/img/arrows-active.png new file mode 100755 index 0000000..2ad7109 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/arrows-active.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/arrows-normal.png b/gridplatform/bootstrap/static/bootstrap/genius/img/arrows-normal.png new file mode 100755 index 0000000..9d8b4d2 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/arrows-normal.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/avatar.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar.jpg new file mode 100644 index 0000000..2b40f0c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/avatar2.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar2.jpg new file mode 100644 index 0000000..0b08703 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar2.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/avatar3.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar3.jpg new file mode 100644 index 0000000..e736709 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar3.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/avatar4.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar4.jpg new file mode 100644 index 0000000..caf9a7e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar4.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/avatar5.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar5.jpg new file mode 100644 index 0000000..97f6769 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar5.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/avatar6.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar6.jpg new file mode 100644 index 0000000..82b025f Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar6.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/avatar7.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar7.jpg new file mode 100644 index 0000000..1d2b884 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar7.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/avatar8.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar8.jpg new file mode 100644 index 0000000..2903cd2 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar8.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/avatar9.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar9.jpg new file mode 100644 index 0000000..3a5eba9 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/avatar9.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/back_disabled.png b/gridplatform/bootstrap/static/bootstrap/genius/img/back_disabled.png new file mode 100644 index 0000000..881de79 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/back_disabled.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/back_enabled.png b/gridplatform/bootstrap/static/bootstrap/genius/img/back_enabled.png new file mode 100644 index 0000000..c608682 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/back_enabled.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/back_enabled_hover.png b/gridplatform/bootstrap/static/bootstrap/genius/img/back_enabled_hover.png new file mode 100644 index 0000000..d300f10 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/back_enabled_hover.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome-big.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome-big.png new file mode 100644 index 0000000..49ce366 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome-big.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome-big@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome-big@2x.png new file mode 100644 index 0000000..024a0ff Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome-big@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome.png new file mode 100644 index 0000000..30e7239 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome@2x.png new file mode 100644 index 0000000..49ce366 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-chrome@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox-big.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox-big.png new file mode 100644 index 0000000..6380286 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox-big.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox-big@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox-big@2x.png new file mode 100644 index 0000000..8b3bcb2 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox-big@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox.png new file mode 100644 index 0000000..f75fe82 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox@2x.png new file mode 100644 index 0000000..6380286 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-firefox@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie-big.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie-big.png new file mode 100644 index 0000000..9487089 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie-big.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie-big@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie-big@2x.png new file mode 100644 index 0000000..9796064 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie-big@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie.png new file mode 100644 index 0000000..d0bdb26 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie@2x.png new file mode 100644 index 0000000..9487089 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-ie@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera-big.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera-big.png new file mode 100644 index 0000000..99ad923 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera-big.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera-big@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera-big@2x.png new file mode 100644 index 0000000..fa7ffe9 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera-big@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera.png new file mode 100644 index 0000000..43526a2 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera@2x.png new file mode 100644 index 0000000..99ad923 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-opera@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari-big.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari-big.png new file mode 100644 index 0000000..d9b76f0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari-big.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari-big@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari-big@2x.png new file mode 100644 index 0000000..87f80d0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari-big@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari.png new file mode 100644 index 0000000..2cd36f1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari@2x.png new file mode 100644 index 0000000..d9b76f0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/browser-safari@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/buttons.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/buttons.gif new file mode 100755 index 0000000..2e464d0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/buttons.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/cancel-off.png b/gridplatform/bootstrap/static/bootstrap/genius/img/cancel-off.png new file mode 100755 index 0000000..a3031f0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/cancel-off.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/cancel-on.png b/gridplatform/bootstrap/static/bootstrap/genius/img/cancel-on.png new file mode 100755 index 0000000..08f2493 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/cancel-on.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/chat-left.png b/gridplatform/bootstrap/static/bootstrap/genius/img/chat-left.png new file mode 100644 index 0000000..c282dc0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/chat-left.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/chat-left@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/chat-left@2x.png new file mode 100644 index 0000000..43b1073 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/chat-left@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/chat-right.png b/gridplatform/bootstrap/static/bootstrap/genius/img/chat-right.png new file mode 100644 index 0000000..a2a3f8e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/chat-right.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/chat-right@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/chat-right@2x.png new file mode 100644 index 0000000..6ea183c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/chat-right@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/chosen-sprite.png b/gridplatform/bootstrap/static/bootstrap/genius/img/chosen-sprite.png new file mode 100755 index 0000000..113dc98 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/chosen-sprite.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/clear.png b/gridplatform/bootstrap/static/bootstrap/genius/img/clear.png new file mode 100755 index 0000000..580b52a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/clear.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/close-button-white.png b/gridplatform/bootstrap/static/bootstrap/genius/img/close-button-white.png new file mode 100644 index 0000000..31187a1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/close-button-white.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/close-button.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/close-button.gif new file mode 100644 index 0000000..6eed398 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/close-button.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/close-button.png b/gridplatform/bootstrap/static/bootstrap/genius/img/close-button.png new file mode 100644 index 0000000..03fa681 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/close-button.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/controls.png b/gridplatform/bootstrap/static/bootstrap/genius/img/controls.png new file mode 100755 index 0000000..65cfd1d Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/controls.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/crop.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/crop.gif new file mode 100755 index 0000000..72ea7cc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/crop.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/dialogs.png b/gridplatform/bootstrap/static/bootstrap/genius/img/dialogs.png new file mode 100755 index 0000000..2d09188 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/dialogs.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/disc-arrow.png b/gridplatform/bootstrap/static/bootstrap/genius/img/disc-arrow.png new file mode 100644 index 0000000..b07bec8 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/disc-arrow.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/error_bg.png b/gridplatform/bootstrap/static/bootstrap/genius/img/error_bg.png new file mode 100755 index 0000000..e9f8a43 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/error_bg.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/forward_disabled.png b/gridplatform/bootstrap/static/bootstrap/genius/img/forward_disabled.png new file mode 100644 index 0000000..6a6ded7 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/forward_disabled.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/forward_enabled.png b/gridplatform/bootstrap/static/bootstrap/genius/img/forward_enabled.png new file mode 100644 index 0000000..a4e6b53 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/forward_enabled.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/forward_enabled_hover.png b/gridplatform/bootstrap/static/bootstrap/genius/img/forward_enabled_hover.png new file mode 100644 index 0000000..fc46c5e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/forward_enabled_hover.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MS5qcGc1344290228.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MS5qcGc1344290228.png new file mode 100755 index 0000000..98990f4 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MS5qcGc1344290228.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MS5qcGc1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MS5qcGc1346725298.png new file mode 100644 index 0000000..16c5067 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MS5qcGc1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTAuanBn1344290212.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTAuanBn1344290212.png new file mode 100755 index 0000000..acbc9f7 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTAuanBn1344290212.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTAuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTAuanBn1346725298.png new file mode 100644 index 0000000..6424c1f Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTAuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTEuanBn1344290212.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTEuanBn1344290212.png new file mode 100755 index 0000000..f48e5ef Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTEuanBn1344290212.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTEuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTEuanBn1346725298.png new file mode 100644 index 0000000..34b36bb Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTEuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTIuanBn1344290216.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTIuanBn1344290216.png new file mode 100755 index 0000000..de579fb Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTIuanBn1344290216.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTIuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTIuanBn1346725298.png new file mode 100644 index 0000000..0aaff51 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTIuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTMuanBn1344290218.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTMuanBn1344290218.png new file mode 100755 index 0000000..ea733ba Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTMuanBn1344290218.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTMuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTMuanBn1346725298.png new file mode 100644 index 0000000..767a0de Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTMuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTQuanBn1344290218.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTQuanBn1344290218.png new file mode 100755 index 0000000..d5a8047 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTQuanBn1344290218.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTQuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTQuanBn1346725298.png new file mode 100644 index 0000000..4e9e74e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTQuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTUuanBn1344290220.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTUuanBn1344290220.png new file mode 100755 index 0000000..9270866 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTUuanBn1344290220.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTUuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTUuanBn1346725298.png new file mode 100644 index 0000000..5cc5f1e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTUuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTYuanBn1344290222.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTYuanBn1344290222.png new file mode 100755 index 0000000..6c0b8ee Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTYuanBn1344290222.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTYuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTYuanBn1346725298.png new file mode 100644 index 0000000..88cc54a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTYuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTcuanBn1344290224.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTcuanBn1344290224.png new file mode 100755 index 0000000..a0263cc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTcuanBn1344290224.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTcuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTcuanBn1346725298.png new file mode 100644 index 0000000..92c0b1e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTcuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTguanBn1344290226.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTguanBn1344290226.png new file mode 100755 index 0000000..53d0d9d Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTguanBn1344290226.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTguanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTguanBn1346725298.png new file mode 100644 index 0000000..77644ee Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTguanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTkuanBn1344290228.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTkuanBn1344290228.png new file mode 100755 index 0000000..c32a13b Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTkuanBn1344290228.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTkuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTkuanBn1346725298.png new file mode 100644 index 0000000..98a414c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MTkuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Mi5qcGc1344290242.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Mi5qcGc1344290242.png new file mode 100755 index 0000000..abd8166 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Mi5qcGc1344290242.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Mi5qcGc1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Mi5qcGc1346725298.png new file mode 100644 index 0000000..f4fcd41 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Mi5qcGc1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjAuanBn1344290232.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjAuanBn1344290232.png new file mode 100755 index 0000000..ce0bfab Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjAuanBn1344290232.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjAuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjAuanBn1346725298.png new file mode 100644 index 0000000..153c47b Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjAuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjEuanBn1344290232.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjEuanBn1344290232.png new file mode 100755 index 0000000..744af61 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjEuanBn1344290232.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjEuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjEuanBn1346725298.png new file mode 100644 index 0000000..e108f52 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjEuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjIuanBn1344290236.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjIuanBn1344290236.png new file mode 100755 index 0000000..e1aaa00 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjIuanBn1344290236.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjIuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjIuanBn1346725298.png new file mode 100644 index 0000000..8750d84 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjIuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjMuanBn1344290238.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjMuanBn1344290238.png new file mode 100755 index 0000000..22ba430 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjMuanBn1344290238.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjMuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjMuanBn1346725298.png new file mode 100644 index 0000000..4a83c1d Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjMuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjQuanBn1344290240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjQuanBn1344290240.png new file mode 100755 index 0000000..2911916 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjQuanBn1344290240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjQuanBn1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjQuanBn1346725298.png new file mode 100644 index 0000000..0db6463 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_MjQuanBn1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_My5qcGc1344290244.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_My5qcGc1344290244.png new file mode 100755 index 0000000..3043149 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_My5qcGc1344290244.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_My5qcGc1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_My5qcGc1346725298.png new file mode 100644 index 0000000..b7bb965 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_My5qcGc1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NC5qcGc1344290246.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NC5qcGc1344290246.png new file mode 100755 index 0000000..a6f0418 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NC5qcGc1344290246.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NC5qcGc1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NC5qcGc1346725298.png new file mode 100644 index 0000000..1bae432 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NC5qcGc1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NS5qcGc1344290246.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NS5qcGc1344290246.png new file mode 100755 index 0000000..877da51 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NS5qcGc1344290246.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NS5qcGc1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NS5qcGc1346725298.png new file mode 100644 index 0000000..8870111 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_NS5qcGc1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ni5qcGc1344290248.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ni5qcGc1344290248.png new file mode 100755 index 0000000..f90eb87 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ni5qcGc1344290248.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ni5qcGc1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ni5qcGc1346725298.png new file mode 100644 index 0000000..57273de Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ni5qcGc1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ny5qcGc1344290252.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ny5qcGc1344290252.png new file mode 100755 index 0000000..4944d59 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ny5qcGc1344290252.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ny5qcGc1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ny5qcGc1346725298.png new file mode 100644 index 0000000..038fcc9 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_Ny5qcGc1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OC5qcGc1344290254.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OC5qcGc1344290254.png new file mode 100755 index 0000000..2334ba8 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OC5qcGc1344290254.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OC5qcGc1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OC5qcGc1346725298.png new file mode 100644 index 0000000..2c0b403 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OC5qcGc1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OS5qcGc1344290254.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OS5qcGc1344290254.png new file mode 100755 index 0000000..3690be1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OS5qcGc1344290254.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OS5qcGc1346725298.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OS5qcGc1346725298.png new file mode 100644 index 0000000..5a95ef0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_OS5qcGc1346725298.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG80LmpwZw1348333255.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG80LmpwZw1348333255.png new file mode 100644 index 0000000..efe5bea Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG80LmpwZw1348333255.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG80LmpwZw1360416442.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG80LmpwZw1360416442.png new file mode 100644 index 0000000..046123e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG80LmpwZw1360416442.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG81LmpwZw1348333701.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG81LmpwZw1348333701.png new file mode 100644 index 0000000..76fd945 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG81LmpwZw1348333701.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG81LmpwZw1360416427.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG81LmpwZw1360416427.png new file mode 100644 index 0000000..9b668f4 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG81LmpwZw1360416427.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG82LmpwZw1348333916.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG82LmpwZw1348333916.png new file mode 100644 index 0000000..326173e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG82LmpwZw1348333916.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG82LmpwZw1360416408.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG82LmpwZw1360416408.png new file mode 100644 index 0000000..7169387 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG82LmpwZw1360416408.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG83LmpwZw1348334202.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG83LmpwZw1348334202.png new file mode 100644 index 0000000..604b342 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG83LmpwZw1348334202.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG83LmpwZw1360416399.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG83LmpwZw1360416399.png new file mode 100644 index 0000000..c1026ab Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG83LmpwZw1360416399.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG84LmpwZw1348334406.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG84LmpwZw1348334406.png new file mode 100644 index 0000000..da06495 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG84LmpwZw1348334406.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG84LmpwZw1360416368.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG84LmpwZw1360416368.png new file mode 100644 index 0000000..d65491e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG84LmpwZw1360416368.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85LmpwZw1348333121.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85LmpwZw1348333121.png new file mode 100644 index 0000000..7679306 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85LmpwZw1348333121.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85LmpwZw1360416350.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85LmpwZw1360416350.png new file mode 100644 index 0000000..e8b7893 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85LmpwZw1360416350.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85ci5qcGc1349462392.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85ci5qcGc1349462392.png new file mode 100644 index 0000000..c3d4efe Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85ci5qcGc1349462392.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85ci5qcGc1360416337.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85ci5qcGc1360416337.png new file mode 100644 index 0000000..09b0eec Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG85ci5qcGc1360416337.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xLmpwZw1348332271.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xLmpwZw1348332271.png new file mode 100644 index 0000000..1e92592 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xLmpwZw1348332271.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMC5qcGc1348334561.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMC5qcGc1348334561.png new file mode 100644 index 0000000..612c215 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMC5qcGc1348334561.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMC5qcGc1360416320.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMC5qcGc1360416320.png new file mode 100644 index 0000000..086950d Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMC5qcGc1360416320.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMS5qcGc1348334652.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMS5qcGc1348334652.png new file mode 100644 index 0000000..c2560e8 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMS5qcGc1348334652.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMS5qcGc1360416311.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMS5qcGc1360416311.png new file mode 100644 index 0000000..0a2dde4 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMS5qcGc1360416311.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMi5qcGc1348334715.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMi5qcGc1348334715.png new file mode 100644 index 0000000..1c0dc52 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMi5qcGc1348334715.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMi5qcGc1360416299.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMi5qcGc1360416299.png new file mode 100644 index 0000000..5454167 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMi5qcGc1360416299.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMy5qcGc1348334746.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMy5qcGc1348334746.png new file mode 100644 index 0000000..33e4799 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMy5qcGc1348334746.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMy5qcGc1360416259.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMy5qcGc1360416259.png new file mode 100644 index 0000000..867dd61 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8xMy5qcGc1360416259.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8yLmpwZw1348332336.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8yLmpwZw1348332336.png new file mode 100644 index 0000000..390fdc6 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8yLmpwZw1348332336.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8yLmpwZw1360416466.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8yLmpwZw1360416466.png new file mode 100644 index 0000000..85bad85 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8yLmpwZw1360416466.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8zLmpwZw1348332634.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8zLmpwZw1348332634.png new file mode 100644 index 0000000..7f8df4e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8zLmpwZw1348332634.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8zLmpwZw1360416452.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8zLmpwZw1360416452.png new file mode 100644 index 0000000..2ebc82d Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/.tmb/l1_cGhvdG8zLmpwZw1360416452.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo1.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo1.jpg new file mode 100644 index 0000000..ce152fb Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo1.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo10.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo10.jpg new file mode 100644 index 0000000..88dc26e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo10.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo11.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo11.jpg new file mode 100644 index 0000000..e811fbb Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo11.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo12.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo12.jpg new file mode 100644 index 0000000..8bffb75 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo12.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo13.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo13.jpg new file mode 100644 index 0000000..933d28a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo13.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo2.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo2.jpg new file mode 100644 index 0000000..65c4ff1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo2.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo3.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo3.jpg new file mode 100644 index 0000000..134bfbd Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo3.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo4.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo4.jpg new file mode 100644 index 0000000..7065308 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo4.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo5.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo5.jpg new file mode 100644 index 0000000..17694d5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo5.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo6.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo6.jpg new file mode 100644 index 0000000..a535493 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo6.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo7.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo7.jpg new file mode 100644 index 0000000..acc5ec2 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo7.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo8.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo8.jpg new file mode 100644 index 0000000..504fe3a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo8.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo9.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo9.jpg new file mode 100644 index 0000000..8739255 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo9.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo9r.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo9r.jpg new file mode 100644 index 0000000..b44e158 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gallery/photo9r.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-halflings-red.png b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-halflings-red.png new file mode 100644 index 0000000..ea323f1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-halflings-red.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-halflings-white.png b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-halflings-white.png new file mode 100755 index 0000000..3bf6484 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-halflings-white.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-halflings.png b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-halflings.png new file mode 100755 index 0000000..79bc568 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-halflings.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-white.png b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-white.png new file mode 100644 index 0000000..327f949 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-white.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-white.svg b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-white.svg new file mode 100644 index 0000000..7f31646 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons-white.svg @@ -0,0 +1,4259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons.png b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons.png new file mode 100644 index 0000000..68fe6a5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons.svg b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons.svg new file mode 100644 index 0000000..3d1f35b --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons.svg @@ -0,0 +1,4157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings-white.png b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings-white.png new file mode 100644 index 0000000..b7ceefc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings-white.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings-white.svg b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings-white.svg new file mode 100644 index 0000000..6cb71a9 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings-white.svg @@ -0,0 +1,1007 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings.png b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings.png new file mode 100644 index 0000000..215076c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings.svg b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings.svg new file mode 100644 index 0000000..9579291 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/img/glyphicons_halflings.svg @@ -0,0 +1,1010 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/grid_grey.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/grid_grey.jpg new file mode 100644 index 0000000..d401ddf Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/grid_grey.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gritter-light.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gritter-light.png new file mode 100755 index 0000000..6b5626b Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gritter-light.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gritter-long.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gritter-long.png new file mode 100755 index 0000000..578b891 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gritter-long.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/gritter.png b/gridplatform/bootstrap/static/bootstrap/genius/img/gritter.png new file mode 100755 index 0000000..0ca3bc0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/gritter.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/handle.png b/gridplatform/bootstrap/static/bootstrap/genius/img/handle.png new file mode 100644 index 0000000..116d823 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/handle.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/handlev.png b/gridplatform/bootstrap/static/bootstrap/genius/img/handlev.png new file mode 100644 index 0000000..7f50b6b Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/handlev.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/hue.png b/gridplatform/bootstrap/static/bootstrap/genius/img/hue.png new file mode 100755 index 0000000..d89560e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/hue.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/i_16_radio.png b/gridplatform/bootstrap/static/bootstrap/genius/img/i_16_radio.png new file mode 100644 index 0000000..3ec5ca1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/i_16_radio.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ibutton-slider-default.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ibutton-slider-default.png new file mode 100644 index 0000000..b3919c7 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ibutton-slider-default.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ibutton-slider-giva-original.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ibutton-slider-giva-original.png new file mode 100644 index 0000000..638b76a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ibutton-slider-giva-original.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ibutton-slider-giva2.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ibutton-slider-giva2.png new file mode 100644 index 0000000..980b5f5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ibutton-slider-giva2.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/icons-big.png b/gridplatform/bootstrap/static/bootstrap/genius/img/icons-big.png new file mode 100755 index 0000000..00be0a6 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/icons-big.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/icons-small.png b/gridplatform/bootstrap/static/bootstrap/genius/img/icons-small.png new file mode 100755 index 0000000..95849dc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/icons-small.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ie-spacer.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/ie-spacer.gif new file mode 100755 index 0000000..5bfd67a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ie-spacer.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/off.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/off.png new file mode 100755 index 0000000..f414051 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/off.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/on.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/on.png new file mode 100755 index 0000000..94425e5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/on.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider.png new file mode 100755 index 0000000..80e05ff Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider_center.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider_center.png new file mode 100755 index 0000000..310fc8c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider_center.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider_left.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider_left.png new file mode 100755 index 0000000..51576ce Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider_left.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider_right.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider_right.png new file mode 100755 index 0000000..447d94a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ios-style-checkboxes/slider_right.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/off.png b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/off.png new file mode 100755 index 0000000..f414051 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/off.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/on.png b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/on.png new file mode 100755 index 0000000..94425e5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/on.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider.png b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider.png new file mode 100755 index 0000000..80e05ff Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider_center.png b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider_center.png new file mode 100755 index 0000000..310fc8c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider_center.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider_left.png b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider_left.png new file mode 100755 index 0000000..51576ce Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider_left.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider_right.png b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider_right.png new file mode 100755 index 0000000..447d94a Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/iphone-style-checkboxes/slider_right.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/loading.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/loading.gif new file mode 100755 index 0000000..5b33f7e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/loading.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/loading_background.png b/gridplatform/bootstrap/static/bootstrap/genius/img/loading_background.png new file mode 100755 index 0000000..9de11f4 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/loading_background.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/1.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/1.jpg new file mode 100644 index 0000000..5b126e5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/1.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/1b.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/1b.jpg new file mode 100644 index 0000000..b45baa5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/1b.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/2.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/2.jpg new file mode 100644 index 0000000..c516945 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/2.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/2b.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/2b.jpg new file mode 100644 index 0000000..adb975f Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/2b.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/3.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/3.jpg new file mode 100644 index 0000000..bce172b Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/3.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/3b.jpg b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/3b.jpg new file mode 100644 index 0000000..101426c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/lockscreen/3b.jpg differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/map.png b/gridplatform/bootstrap/static/bootstrap/genius/img/map.png new file mode 100644 index 0000000..33b4d47 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/map.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/progress.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/progress.gif new file mode 100755 index 0000000..8bab11e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/progress.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/quicklook-bg.png b/gridplatform/bootstrap/static/bootstrap/genius/img/quicklook-bg.png new file mode 100755 index 0000000..aedeadd Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/quicklook-bg.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/quicklook-icons.png b/gridplatform/bootstrap/static/bootstrap/genius/img/quicklook-icons.png new file mode 100755 index 0000000..76df30c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/quicklook-icons.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/quote.png b/gridplatform/bootstrap/static/bootstrap/genius/img/quote.png new file mode 100644 index 0000000..5871f83 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/quote.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/resize.png b/gridplatform/bootstrap/static/bootstrap/genius/img/resize.png new file mode 100755 index 0000000..6ec17cd Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/resize.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/saturation.png b/gridplatform/bootstrap/static/bootstrap/genius/img/saturation.png new file mode 100755 index 0000000..594ae50 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/saturation.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/select2-spinner.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/select2-spinner.gif new file mode 100755 index 0000000..5b33f7e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/select2-spinner.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/select2.png b/gridplatform/bootstrap/static/bootstrap/genius/img/select2.png new file mode 100755 index 0000000..1d804ff Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/select2.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/select2x2.png b/gridplatform/bootstrap/static/bootstrap/genius/img/select2x2.png new file mode 100755 index 0000000..4bdd5c9 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/select2x2.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/slider_r.png b/gridplatform/bootstrap/static/bootstrap/genius/img/slider_r.png new file mode 100644 index 0000000..bc632ac Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/slider_r.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/slider_r8.png b/gridplatform/bootstrap/static/bootstrap/genius/img/slider_r8.png new file mode 100644 index 0000000..b586fb1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/slider_r8.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc.png new file mode 100644 index 0000000..48244c8 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc@2x.png new file mode 100644 index 0000000..d6881c5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc_disabled.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc_disabled.png new file mode 100644 index 0000000..d8422da Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc_disabled.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc_disabled@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc_disabled@2x.png new file mode 100644 index 0000000..4364e74 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_asc_disabled@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_both.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_both.png new file mode 100644 index 0000000..f6b18b0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_both.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_both@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_both@2x.png new file mode 100644 index 0000000..8449c0c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_both@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc.png new file mode 100644 index 0000000..94c5c6b Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc@2x.png new file mode 100644 index 0000000..04f5fcf Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc_disabled.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc_disabled.png new file mode 100644 index 0000000..1df93ec Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc_disabled.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc_disabled@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc_disabled@2x.png new file mode 100644 index 0000000..85be54f Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sort_desc_disabled@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/spinner-mini.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/spinner-mini.gif new file mode 100755 index 0000000..5b33f7e Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/spinner-mini.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/sprite.png b/gridplatform/bootstrap/static/bootstrap/genius/img/sprite.png new file mode 100755 index 0000000..66b558f Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/sprite.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/spritemap.png b/gridplatform/bootstrap/static/bootstrap/genius/img/spritemap.png new file mode 100644 index 0000000..9f21314 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/spritemap.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/spritemap@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/spritemap@2x.png new file mode 100644 index 0000000..e877eea Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/spritemap@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/star-half.png b/gridplatform/bootstrap/static/bootstrap/genius/img/star-half.png new file mode 100755 index 0000000..3c19e90 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/star-half.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/star-off.png b/gridplatform/bootstrap/static/bootstrap/genius/img/star-off.png new file mode 100755 index 0000000..956fa7c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/star-off.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/star-on.png b/gridplatform/bootstrap/static/bootstrap/genius/img/star-on.png new file mode 100755 index 0000000..975fe7f Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/star-on.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/tbg.png b/gridplatform/bootstrap/static/bootstrap/genius/img/tbg.png new file mode 100644 index 0000000..dd532e9 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/tbg.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/thumb.png b/gridplatform/bootstrap/static/bootstrap/genius/img/thumb.png new file mode 100755 index 0000000..c6f88fa Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/thumb.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-bg.png b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-bg.png new file mode 100644 index 0000000..5497b18 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-bg.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-left-arrow-kopia.png b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-left-arrow-kopia.png new file mode 100644 index 0000000..21f5859 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-left-arrow-kopia.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-left-arrow.png b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-left-arrow.png new file mode 100644 index 0000000..50d6390 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-left-arrow.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-left-arrow@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-left-arrow@2x.png new file mode 100644 index 0000000..f82dd93 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-left-arrow@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-right-arrow-kopia.png b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-right-arrow-kopia.png new file mode 100644 index 0000000..fe286b3 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-right-arrow-kopia.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-right-arrow.png b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-right-arrow.png new file mode 100644 index 0000000..738eff1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-right-arrow.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-right-arrow@2x.png b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-right-arrow@2x.png new file mode 100644 index 0000000..ec41020 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/timeline-right-arrow@2x.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/toolbar.gif b/gridplatform/bootstrap/static/bootstrap/genius/img/toolbar.gif new file mode 100755 index 0000000..e6eb2da Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/toolbar.gif differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/toolbar.png b/gridplatform/bootstrap/static/bootstrap/genius/img/toolbar.png new file mode 100755 index 0000000..3b51326 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/toolbar.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_0_aaaaaa_40x100.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100755 index 0000000..faa1aa9 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_0_eeeeee_40x100.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_0_eeeeee_40x100.png new file mode 100755 index 0000000..a2d5b32 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_0_eeeeee_40x100.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_55_ffffff_40x100.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_55_ffffff_40x100.png new file mode 100755 index 0000000..5ba9e08 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_55_ffffff_40x100.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_75_ffffff_40x100.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_75_ffffff_40x100.png new file mode 100755 index 0000000..89741c1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_flat_75_ffffff_40x100.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_55_fbf9ee_1x400.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100755 index 0000000..ad3d634 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_65_ffffff_1x400.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_65_ffffff_1x400.png new file mode 100755 index 0000000..df732cd Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_75_dadada_1x400.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_75_dadada_1x400.png new file mode 100755 index 0000000..5a46b47 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_75_dadada_1x400.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_75_e6e6e6_1x400.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100755 index 0000000..86c2baa Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_95_fef1ec_1x400.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_95_fef1ec_1x400.png new file mode 100755 index 0000000..4443fdc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_100_f6f6f6_1x100.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_100_f6f6f6_1x100.png new file mode 100755 index 0000000..07fe4f7 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_100_f6f6f6_1x100.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_25_0073ea_1x100.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_25_0073ea_1x100.png new file mode 100755 index 0000000..a8088a5 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_25_0073ea_1x100.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_50_dddddd_1x100.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_50_dddddd_1x100.png new file mode 100755 index 0000000..225d210 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_50_dddddd_1x100.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_75_cccccc_1x100.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100755 index 0000000..7c9fa6c Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_0073ea_256x240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_0073ea_256x240.png new file mode 100755 index 0000000..1fcab6d Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_0073ea_256x240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_222222_256x240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_222222_256x240.png new file mode 100755 index 0000000..b273ff1 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_222222_256x240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_2e83ff_256x240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_2e83ff_256x240.png new file mode 100755 index 0000000..09d1cdc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_2e83ff_256x240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_454545_256x240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_454545_256x240.png new file mode 100755 index 0000000..b6db1ac Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_454545_256x240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_666666_256x240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_666666_256x240.png new file mode 100755 index 0000000..76cecfc Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_666666_256x240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_888888_256x240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_888888_256x240.png new file mode 100755 index 0000000..6d02426 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_888888_256x240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_cd0a0a_256x240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_cd0a0a_256x240.png new file mode 100755 index 0000000..2ab019b Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_cd0a0a_256x240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_ff0084_256x240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_ff0084_256x240.png new file mode 100755 index 0000000..439c7b7 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_ff0084_256x240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_ffffff_256x240.png b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_ffffff_256x240.png new file mode 100755 index 0000000..4f624bb Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/ui-icons_ffffff_256x240.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/img/uploadify-cancel.png b/gridplatform/bootstrap/static/bootstrap/genius/img/uploadify-cancel.png new file mode 100755 index 0000000..35682b0 Binary files /dev/null and b/gridplatform/bootstrap/static/bootstrap/genius/img/uploadify-cancel.png differ diff --git a/gridplatform/bootstrap/static/bootstrap/genius/js/Chart.min.js b/gridplatform/bootstrap/static/bootstrap/genius/js/Chart.min.js new file mode 100755 index 0000000..ab63588 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/js/Chart.min.js @@ -0,0 +1,39 @@ +var Chart=function(s){function v(a,c,b){a=A((a-c.graphMin)/(c.steps*c.stepValue),1,0);return b*c.steps*a}function x(a,c,b,e){function h(){g+=f;var k=a.animation?A(d(g),null,0):1;e.clearRect(0,0,q,u);a.scaleOverlay?(b(k),c()):(c(),b(k));if(1>=g)D(h);else if("function"==typeof a.onAnimationComplete)a.onAnimationComplete()}var f=a.animation?1/A(a.animationSteps,Number.MAX_VALUE,1):1,d=B[a.animationEasing],g=a.animation?0:1;"function"!==typeof c&&(c=function(){});D(h)}function C(a,c,b,e,h,f){var d;a= +Math.floor(Math.log(e-h)/Math.LN10);h=Math.floor(h/(1*Math.pow(10,a)))*Math.pow(10,a);e=Math.ceil(e/(1*Math.pow(10,a)))*Math.pow(10,a)-h;a=Math.pow(10,a);for(d=Math.round(e/a);dc;)a=dc?c:!isNaN(parseFloat(b))&& +isFinite(b)&&a)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c? +b(c):b}var r=this,B={linear:function(a){return a},easeInQuad:function(a){return a*a},easeOutQuad:function(a){return-1*a*(a-2)},easeInOutQuad:function(a){return 1>(a/=0.5)?0.5*a*a:-0.5*(--a*(a-2)-1)},easeInCubic:function(a){return a*a*a},easeOutCubic:function(a){return 1*((a=a/1-1)*a*a+1)},easeInOutCubic:function(a){return 1>(a/=0.5)?0.5*a*a*a:0.5*((a-=2)*a*a+2)},easeInQuart:function(a){return a*a*a*a},easeOutQuart:function(a){return-1*((a=a/1-1)*a*a*a-1)},easeInOutQuart:function(a){return 1>(a/=0.5)? +0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)},easeInQuint:function(a){return 1*(a/=1)*a*a*a*a},easeOutQuint:function(a){return 1*((a=a/1-1)*a*a*a*a+1)},easeInOutQuint:function(a){return 1>(a/=0.5)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)},easeInSine:function(a){return-1*Math.cos(a/1*(Math.PI/2))+1},easeOutSine:function(a){return 1*Math.sin(a/1*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a/1)-1)},easeInExpo:function(a){return 0==a?1:1*Math.pow(2,10*(a/1-1))},easeOutExpo:function(a){return 1== +a?1:1*(-Math.pow(2,-10*a/1)+1)},easeInOutExpo:function(a){return 0==a?0:1==a?1:1>(a/=0.5)?0.5*Math.pow(2,10*(a-1)):0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return 1<=a?a:-1*(Math.sqrt(1-(a/=1)*a)-1)},easeOutCirc:function(a){return 1*Math.sqrt(1-(a=a/1-1)*a)},easeInOutCirc:function(a){return 1>(a/=0.5)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeInElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);ea?-0.5*e*Math.pow(2,10* +(a-=1))*Math.sin((1*a-c)*2*Math.PI/b):0.5*e*Math.pow(2,-10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInBack:function(a){return 1*(a/=1)*a*(2.70158*a-1.70158)},easeOutBack:function(a){return 1*((a=a/1-1)*a*(2.70158*a+1.70158)+1)},easeInOutBack:function(a){var c=1.70158;return 1>(a/=0.5)?0.5*a*a*(((c*=1.525)+1)*a-c):0.5*((a-=2)*a*(((c*=1.525)+1)*a+c)+2)},easeInBounce:function(a){return 1-B.easeOutBounce(1-a)},easeOutBounce:function(a){return(a/=1)<1/2.75?1*7.5625*a*a:a<2/2.75?1*(7.5625*(a-=1.5/2.75)* +a+0.75):a<2.5/2.75?1*(7.5625*(a-=2.25/2.75)*a+0.9375):1*(7.5625*(a-=2.625/2.75)*a+0.984375)},easeInOutBounce:function(a){return 0.5>a?0.5*B.easeInBounce(2*a):0.5*B.easeOutBounce(2*a-1)+0.5}},q=s.canvas.width,u=s.canvas.height;window.devicePixelRatio&&(s.canvas.style.width=q+"px",s.canvas.style.height=u+"px",s.canvas.height=u*window.devicePixelRatio,s.canvas.width=q*window.devicePixelRatio,s.scale(window.devicePixelRatio,window.devicePixelRatio));this.PolarArea=function(a,c){r.PolarArea.defaults={scaleOverlay:!0, +scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce", +animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.PolarArea.defaults,c):r.PolarArea.defaults;return new G(a,b,s)};this.Radar=function(a,c){r.Radar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!1,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)", +scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,angleShowLineOut:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:12,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Radar.defaults,c):r.Radar.defaults;return new H(a,b,s)};this.Pie=function(a, +c){r.Pie.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.Pie.defaults,c):r.Pie.defaults;return new I(a,b,s)};this.Doughnut=function(a,c){r.Doughnut.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1, +onAnimationComplete:null};var b=c?y(r.Doughnut.defaults,c):r.Doughnut.defaults;return new J(a,b,s)};this.Line=function(a,c){r.Line.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,bezierCurve:!0, +pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:2,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Line.defaults,c):r.Line.defaults;return new K(a,b,s)};this.Bar=function(a,c){r.Bar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'", +scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Bar.defaults,c):r.Bar.defaults;return new L(a,b,s)};var G=function(a,c,b){var e,h,f,d,g,k,j,l,m;g=Math.min.apply(Math,[q,u])/2;g-=Math.max.apply(Math,[0.5*c.scaleFontSize,0.5*c.scaleLineWidth]); +d=2*c.scaleFontSize;c.scaleShowLabelBackdrop&&(d+=2*c.scaleBackdropPaddingY,g-=1.5*c.scaleBackdropPaddingY);l=g;d=d?d:5;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;fe&&(e=a[f].value),a[f].valuel&&(l=h);g-=Math.max.apply(Math,[l,1.5*(c.pointLabelFontSize/2)]);g-=c.pointLabelFontSize;l=g=A(g,null,0);d=d?d:5;e=Number.MIN_VALUE; +h=Number.MAX_VALUE;for(f=0;fe&&(e=a.datasets[f].data[m]),a.datasets[f].data[m]Math.PI?"right":"left";b.textBaseline="middle";b.fillText(a.labels[d],f,-h)}b.restore()},function(d){var e=2*Math.PI/a.datasets[0].data.length;b.save();b.translate(q/2,u/2);for(var g=0;gt?e:t;q/a.labels.lengthe&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]d?h:d;d+=10}r=q-d-t;m=Math.floor(r/(a.labels.length-1));n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0t?e:t;q/a.labels.lengthe&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]< +h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;for(e=0;ed?h:d;d+=10}r=q-d-t;m= +Math.floor(r/a.labels.length);s=(m-2*c.scaleGridLineWidth-2*c.barValueSpacing-(c.barDatasetSpacing*a.datasets.length-1)-(c.barStrokeWidth/2*a.datasets.length-1))/a.datasets.length;n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0awesome + +**/(function(e){"use strict";var t=function(e){this.init("address",e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.abstractinput);e.extend(t.prototype,{render:function(){this.$input=this.$tpl.find("input")},value2html:function(t,n){if(!t){e(n).empty();return}var r=e("
").text(t.city).html()+", "+e("
").text(t.street).html()+" st., bld. "+e("
").text(t.building).html();e(n).html(r)},html2value:function(e){return null},value2str:function(e){var t="";if(e)for(var n in e)t=t+n+":"+e[n]+";";return t},str2value:function(e){return e},value2input:function(e){if(!e)return;this.$input.filter('[name="city"]').val(e.city);this.$input.filter('[name="street"]').val(e.street);this.$input.filter('[name="building"]').val(e.building)},input2value:function(){return{city:this.$input.filter('[name="city"]').val(),street:this.$input.filter('[name="street"]').val(),building:this.$input.filter('[name="building"]').val()}},activate:function(){this.$input.filter('[name="city"]').focus()},autosubmit:function(){this.$input.keydown(function(t){t.which===13&&e(this).closest("form").submit()})}});t.defaults=e.extend({},e.fn.editabletypes.abstractinput.defaults,{tpl:'
',inputclass:""});e.fn.editabletypes.address=t})(window.jQuery); \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/js/bootstrap-colorpicker.min.js b/gridplatform/bootstrap/static/bootstrap/genius/js/bootstrap-colorpicker.min.js new file mode 100644 index 0000000..6cc24ad --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/js/bootstrap-colorpicker.min.js @@ -0,0 +1,18 @@ +/* ========================================================= + * bootstrap-colorpicker.js + * http://www.eyecon.ro/bootstrap-colorpicker + * ========================================================= + * Copyright 2012 Stefan Petre + * + * 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. + * ========================================================= */!function(e){var t=function(e){this.value={h:1,s:1,b:1,a:1};this.setColor(e)};t.prototype={constructor:t,setColor:function(t){t=t.toLowerCase();var n=this;e.each(r.stringParsers,function(e,i){var s=i.re.exec(t),o=s&&i.parse(s),u=i.space||"rgba";if(o){u==="hsla"?n.value=r.RGBtoHSB.apply(null,r.HSLtoRGB.apply(null,o)):n.value=r.RGBtoHSB.apply(null,o);return!1}})},setHue:function(e){this.value.h=1-e},setSaturation:function(e){this.value.s=e},setLightness:function(e){this.value.b=1-e},setAlpha:function(e){this.value.a=parseInt((1-e)*100,10)/100},toRGB:function(e,t,n,r){if(!e){e=this.value.h;t=this.value.s;n=this.value.b}e*=360;var i,s,o,u,a;e=e%360/60;a=n*t;u=a*(1-Math.abs(e%2-1));i=s=o=n-a;e=~~e;i+=[a,u,0,0,u,a][e];s+=[u,a,a,u,0,0][e];o+=[0,0,u,a,a,u][e];return{r:Math.round(i*255),g:Math.round(s*255),b:Math.round(o*255),a:r||this.value.a}},toHex:function(e,t,n,r){var i=this.toRGB(e,t,n,r);return"#"+(1<<24|parseInt(i.r)<<16|parseInt(i.g)<<8|parseInt(i.b)).toString(16).substr(1)},toHSL:function(e,t,n,r){if(!e){e=this.value.h;t=this.value.s;n=this.value.b}var i=e,s=(2-t)*n,o=t*n;s>0&&s<=1?o/=s:o/=2-s;s/=2;o>1&&(o=1);return{h:i,s:o,l:s,a:r||this.value.a}}};var n=function(t,n){this.element=e(t);var i=n.format||this.element.data("color-format")||"hex";this.format=r.translateFormats[i];this.isInput=this.element.is("input");this.component=this.element.is(".color")?this.element.find(".add-on"):!1;this.picker=e(r.template).appendTo("body").on("mousedown",e.proxy(this.mousedown,this));this.isInput?this.element.on({focus:e.proxy(this.show,this),keyup:e.proxy(this.update,this)}):this.component?this.component.on({click:e.proxy(this.show,this)}):this.element.on({click:e.proxy(this.show,this)});if(i==="rgba"||i==="hsla"){this.picker.addClass("alpha");this.alpha=this.picker.find(".colorpicker-alpha")[0].style}if(this.component){this.picker.find(".colorpicker-color").hide();this.preview=this.element.find("i")[0].style}else this.preview=this.picker.find("div:last")[0].style;this.base=this.picker.find("div:first")[0].style;this.update()};n.prototype={constructor:n,show:function(t){this.picker.show();this.height=this.component?this.component.outerHeight():this.element.outerHeight();this.place();e(window).on("resize",e.proxy(this.place,this));if(!this.isInput&&t){t.stopPropagation();t.preventDefault()}e(document).on({mousedown:e.proxy(this.hide,this)});this.element.trigger({type:"show",color:this.color})},update:function(){this.color=new t(this.isInput?this.element.prop("value"):this.element.data("color"));this.picker.find("i").eq(0).css({left:this.color.value.s*100,top:100-this.color.value.b*100}).end().eq(1).css("top",100*(1-this.color.value.h)).end().eq(2).css("top",100*(1-this.color.value.a));this.previewColor()},setValue:function(e){this.color=new t(e);this.picker.find("i").eq(0).css({left:this.color.value.s*100,top:100-this.color.value.b*100}).end().eq(1).css("top",100*(1-this.color.value.h)).end().eq(2).css("top",100*(1-this.color.value.a));this.previewColor();this.element.trigger({type:"changeColor",color:this.color})},hide:function(){this.picker.hide();e(window).off("resize",this.place);if(!this.isInput){e(document).off({mousedown:this.hide});this.component&&this.element.find("input").prop("value",this.format.call(this));this.element.data("color",this.format.call(this))}else this.element.prop("value",this.format.call(this));this.element.trigger({type:"hide",color:this.color})},place:function(){var e=this.component?this.component.offset():this.element.offset();this.picker.css({top:e.top+this.height,left:e.left})},previewColor:function(){try{this.preview.backgroundColor=this.format.call(this)}catch(e){this.preview.backgroundColor=this.color.toHex()}this.base.backgroundColor=this.color.toHex(this.color.value.h,1,1,1);this.alpha&&(this.alpha.backgroundColor=this.color.toHex())},pointer:null,slider:null,mousedown:function(t){t.stopPropagation();t.preventDefault();var n=e(t.target),i=n.closest("div");if(!i.is(".colorpicker")){if(i.is(".colorpicker-saturation"))this.slider=e.extend({},r.sliders.saturation);else if(i.is(".colorpicker-hue"))this.slider=e.extend({},r.sliders.hue);else{if(!i.is(".colorpicker-alpha"))return!1;this.slider=e.extend({},r.sliders.alpha)}var s=i.offset();this.slider.knob=i.find("i")[0].style;this.slider.left=t.pageX-s.left;this.slider.top=t.pageY-s.top;this.pointer={left:t.pageX,top:t.pageY};e(document).on({mousemove:e.proxy(this.mousemove,this),mouseup:e.proxy(this.mouseup,this)}).trigger("mousemove")}return!1},mousemove:function(e){e.stopPropagation();e.preventDefault();var t=Math.max(0,Math.min(this.slider.maxLeft,this.slider.left+((e.pageX||this.pointer.left)-this.pointer.left))),n=Math.max(0,Math.min(this.slider.maxTop,this.slider.top+((e.pageY||this.pointer.top)-this.pointer.top)));this.slider.knob.left=t+"px";this.slider.knob.top=n+"px";this.slider.callLeft&&this.color[this.slider.callLeft].call(this.color,t/100);this.slider.callTop&&this.color[this.slider.callTop].call(this.color,n/100);this.previewColor();this.element.trigger({type:"changeColor",color:this.color});return!1},mouseup:function(t){t.stopPropagation();t.preventDefault();e(document).off({mousemove:this.mousemove,mouseup:this.mouseup});return!1}};e.fn.colorpicker=function(t,r){return this.each(function(){var i=e(this),s=i.data("colorpicker"),o=typeof t=="object"&&t;s||i.data("colorpicker",s=new n(this,e.extend({},e.fn.colorpicker.defaults,o)));typeof t=="string"&&s[t](r)})};e.fn.colorpicker.defaults={};e.fn.colorpicker.Constructor=n;var r={translateFormats:{rgb:function(){var e=this.color.toRGB();return"rgb("+e.r+","+e.g+","+e.b+")"},rgba:function(){var e=this.color.toRGB();return"rgba("+e.r+","+e.g+","+e.b+","+e.a+")"},hsl:function(){var e=this.color.toHSL();return"hsl("+Math.round(e.h*360)+","+Math.round(e.s*100)+"%,"+Math.round(e.l*100)+"%)"},hsla:function(){var e=this.color.toHSL();return"hsla("+Math.round(e.h*360)+","+Math.round(e.s*100)+"%,"+Math.round(e.l*100)+"%,"+e.a+")"},hex:function(){return this.color.toHex()}},sliders:{saturation:{maxLeft:100,maxTop:100,callLeft:"setSaturation",callTop:"setLightness"},hue:{maxLeft:0,maxTop:100,callLeft:!1,callTop:"setHue"},alpha:{maxLeft:0,maxTop:100,callLeft:!1,callTop:"setAlpha"}},RGBtoHSB:function(e,t,n,r){e/=255;t/=255;n/=255;var i,s,o,u;o=Math.max(e,t,n);u=o-Math.min(e,t,n);i=u===0?null:o==e?(t-n)/u:o==t?(n-e)/u+2:(e-t)/u+4;i=(i+360)%6*60/360;s=u===0?0:u/o;return{h:i||1,s:s,b:o,a:r||1}},HueToRGB:function(e,t,n){n<0?n+=1:n>1&&(n-=1);return n*6<1?e+(t-e)*n*6:n*2<1?t:n*3<2?e+(t-e)*(2/3-n)*6:e},HSLtoRGB:function(e,t,n,i){t<0&&(t=0);var s;n<=.5?s=n*(1+t):s=n+t-n*t;var o=2*n-s,u=e+1/3,a=e,f=e-1/3,l=Math.round(r.HueToRGB(o,s,u)*255),c=Math.round(r.HueToRGB(o,s,a)*255),h=Math.round(r.HueToRGB(o,s,f)*255);return[l,c,h,i||1]},stringParsers:[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,parse:function(e){return[e[1],e[2],e[3],e[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,parse:function(e){return[2.55*e[1],2.55*e[2],2.55*e[3],e[4]]}},{re:/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/,parse:function(e){return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}},{re:/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/,parse:function(e){return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(e){return[e[1]/360,e[2]/100,e[3]/100,e[4]]}}],template:'
 
'+E+""+p.getUTCDate()+"
«»
'+h.headTemplate+""+h.footTemplate+"
"+"
"+'
'+''+h.headTemplate+h.contTemplate+h.footTemplate+"
"+"
"+'
'+''+h.headTemplate+h.contTemplate+h.footTemplate+"
"+"
"+"";e.fn.datepicker.DPGlobal=h;e.fn.datepicker.noConflict=function(){e.fn.datepicker=a;return this};e(document).on("focus.datepicker.data-api click.datepicker.data-api",'[data-provide="datepicker"]',function(t){var n=e(this);if(n.data("datepicker"))return;t.preventDefault();n.datepicker("show")});e(function(){e('[data-provide="datepicker-inline"]').datepicker()})})(window.jQuery); \ No newline at end of file diff --git a/gridplatform/bootstrap/static/bootstrap/genius/js/bootstrap-editable.min.js b/gridplatform/bootstrap/static/bootstrap/genius/js/bootstrap-editable.min.js new file mode 100755 index 0000000..6c4df63 --- /dev/null +++ b/gridplatform/bootstrap/static/bootstrap/genius/js/bootstrap-editable.min.js @@ -0,0 +1,7 @@ +/*! X-editable - v1.5.0 +* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery +* http://github.com/vitalets/x-editable +* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ +!function(a){"use strict";var b=function(b,c){this.options=a.extend({},a.fn.editableform.defaults,c),this.$div=a(b),this.options.scope||(this.options.scope=this)};b.prototype={constructor:b,initInput:function(){this.input=this.options.input,this.value=this.input.str2value(this.options.value),this.input.prerender()},initTemplate:function(){this.$form=a(a.fn.editableform.template)},initButtons:function(){var b=this.$form.find(".editable-buttons");b.append(a.fn.editableform.buttons),"bottom"===this.options.showbuttons&&b.addClass("editable-buttons-bottom")},render:function(){this.$loading=a(a.fn.editableform.loading),this.$div.empty().append(this.$loading),this.initTemplate(),this.options.showbuttons?this.initButtons():this.$form.find(".editable-buttons").remove(),this.showLoading(),this.isSaving=!1,this.$div.triggerHandler("rendering"),this.initInput(),this.$form.find("div.editable-input").append(this.input.$tpl),this.$div.append(this.$form),a.when(this.input.render()).then(a.proxy(function(){if(this.options.showbuttons||this.input.autosubmit(),this.$form.find(".editable-cancel").click(a.proxy(this.cancel,this)),this.input.error)this.error(this.input.error),this.$form.find(".editable-submit").attr("disabled",!0),this.input.$input.attr("disabled",!0),this.$form.submit(function(a){a.preventDefault()});else{this.error(!1),this.input.$input.removeAttr("disabled"),this.$form.find(".editable-submit").removeAttr("disabled");var b=null===this.value||void 0===this.value||""===this.value?this.options.defaultValue:this.value;this.input.value2input(b),this.$form.submit(a.proxy(this.submit,this))}this.$div.triggerHandler("rendered"),this.showForm(),this.input.postrender&&this.input.postrender()},this))},cancel:function(){this.$div.triggerHandler("cancel")},showLoading:function(){var a,b;this.$form?(a=this.$form.outerWidth(),b=this.$form.outerHeight(),a&&this.$loading.width(a),b&&this.$loading.height(b),this.$form.hide()):(a=this.$loading.parent().width(),a&&this.$loading.width(a)),this.$loading.show()},showForm:function(a){this.$loading.hide(),this.$form.show(),a!==!1&&this.input.activate(),this.$div.triggerHandler("show")},error:function(b){var c,d=this.$form.find(".control-group"),e=this.$form.find(".editable-error-block");if(b===!1)d.removeClass(a.fn.editableform.errorGroupClass),e.removeClass(a.fn.editableform.errorBlockClass).empty().hide();else{if(b){c=b.split("\n");for(var f=0;f").text(c[f]).html();b=c.join("
")}d.addClass(a.fn.editableform.errorGroupClass),e.addClass(a.fn.editableform.errorBlockClass).html(b).show()}},submit:function(b){b.stopPropagation(),b.preventDefault();var c,d=this.input.input2value();if(c=this.validate(d))return this.error(c),this.showForm(),void 0;if(!this.options.savenochange&&this.input.value2str(d)==this.input.value2str(this.value))return this.$div.triggerHandler("nochange"),void 0;var e=this.input.value2submit(d);this.isSaving=!0,a.when(this.save(e)).done(a.proxy(function(a){this.isSaving=!1;var b="function"==typeof this.options.success?this.options.success.call(this.options.scope,a,d):null;return b===!1?(this.error(!1),this.showForm(!1),void 0):"string"==typeof b?(this.error(b),this.showForm(),void 0):(b&&"object"==typeof b&&b.hasOwnProperty("newValue")&&(d=b.newValue),this.error(!1),this.value=d,this.$div.triggerHandler("save",{newValue:d,submitValue:e,response:a}),void 0)},this)).fail(a.proxy(function(a){this.isSaving=!1;var b;b="function"==typeof this.options.error?this.options.error.call(this.options.scope,a,d):"string"==typeof a?a:a.responseText||a.statusText||"Unknown error!",this.error(b),this.showForm()},this))},save:function(b){this.options.pk=a.fn.editableutils.tryParseJson(this.options.pk,!0);var c,d="function"==typeof this.options.pk?this.options.pk.call(this.options.scope):this.options.pk,e=!!("function"==typeof this.options.url||this.options.url&&("always"===this.options.send||"auto"===this.options.send&&null!==d&&void 0!==d));return e?(this.showLoading(),c={name:this.options.name||"",value:b,pk:d},"function"==typeof this.options.params?c=this.options.params.call(this.options.scope,c):(this.options.params=a.fn.editableutils.tryParseJson(this.options.params,!0),a.extend(c,this.options.params)),"function"==typeof this.options.url?this.options.url.call(this.options.scope,c):a.ajax(a.extend({url:this.options.url,data:c,type:"POST"},this.options.ajaxOptions))):void 0},validate:function(a){return void 0===a&&(a=this.value),"function"==typeof this.options.validate?this.options.validate.call(this.options.scope,a):void 0},option:function(a,b){a in this.options&&(this.options[a]=b),"value"===a&&this.setValue(b)},setValue:function(a,b){this.value=b?this.input.str2value(a):a,this.$form&&this.$form.is(":visible")&&this.input.value2input(this.value)}},a.fn.editableform=function(c){var d=arguments;return this.each(function(){var e=a(this),f=e.data("editableform"),g="object"==typeof c&&c;f||e.data("editableform",f=new b(this,g)),"string"==typeof c&&f[c].apply(f,Array.prototype.slice.call(d,1))})},a.fn.editableform.Constructor=b,a.fn.editableform.defaults={type:"text",url:null,params:null,name:null,pk:null,value:null,defaultValue:null,send:"auto",validate:null,success:null,error:null,ajaxOptions:null,showbuttons:!0,scope:null,savenochange:!1},a.fn.editableform.template='
',a.fn.editableform.loading='
',a.fn.editableform.buttons='',a.fn.editableform.errorGroupClass=null,a.fn.editableform.errorBlockClass="editable-error",a.fn.editableform.engine="jquery"}(window.jQuery),function(a){"use strict";a.fn.editableutils={inherit:function(a,b){var c=function(){};c.prototype=b.prototype,a.prototype=new c,a.prototype.constructor=a,a.superclass=b.prototype},setCursorPosition:function(a,b){if(a.setSelectionRange)a.setSelectionRange(b,b);else if(a.createTextRange){var c=a.createTextRange();c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",b),c.select()}},tryParseJson:function(a,b){if("string"==typeof a&&a.length&&a.match(/^[\{\[].*[\}\]]$/))if(b)try{a=new Function("return "+a)()}catch(c){}finally{return a}else a=new Function("return "+a)();return a},sliceObj:function(b,c,d){var e,f,g={};if(!a.isArray(c)||!c.length)return g;for(var h=0;h").text(b).html()},itemsByValue:function(b,c,d){if(!c||null===b)return[];if("function"!=typeof d){var e=d||"value";d=function(a){return a[e]}}var f=a.isArray(b),g=[],h=this;return a.each(c,function(c,e){if(e.children)g=g.concat(h.itemsByValue(b,e.children,d));else if(f)a.grep(b,function(a){return a==(e&&"object"==typeof e?d(e):e)}).length&&g.push(e);else{var i=e&&"object"==typeof e?d(e):e;b==i&&g.push(e)}}),g},createInput:function(b){var c,d,e,f=b.type;return"date"===f&&("inline"===b.mode?a.fn.editabletypes.datefield?f="datefield":a.fn.editabletypes.dateuifield&&(f="dateuifield"):a.fn.editabletypes.date?f="date":a.fn.editabletypes.dateui&&(f="dateui"),"date"!==f||a.fn.editabletypes.date||(f="combodate")),"datetime"===f&&"inline"===b.mode&&(f="datetimefield"),"wysihtml5"!==f||a.fn.editabletypes[f]||(f="textarea"),"function"==typeof a.fn.editabletypes[f]?(c=a.fn.editabletypes[f],d=this.sliceObj(b,this.objectKeys(c.defaults)),e=new c(d)):(a.error("Unknown type: "+f),!1)},supportsTransitions:function(){var a=document.body||document.documentElement,b=a.style,c="transition",d=["Moz","Webkit","Khtml","O","ms"];if("string"==typeof b[c])return!0;c=c.charAt(0).toUpperCase()+c.substr(1);for(var e=0;e"),this.tip().is(this.innerCss)?this.tip().append(this.$form):this.tip().find(this.innerCss).append(this.$form),this.renderForm()},hide:function(a){if(this.tip()&&this.tip().is(":visible")&&this.$element.hasClass("editable-open")){if(this.$form.data("editableform").isSaving)return this.delayedHide={reason:a},void 0;this.delayedHide=!1,this.$element.removeClass("editable-open"),this.innerHide(),this.$element.triggerHandler("hidden",a||"manual")}},innerShow:function(){},innerHide:function(){},toggle:function(a){this.container()&&this.tip()&&this.tip().is(":visible")?this.hide():this.show(a)},setPosition:function(){},save:function(a,b){this.$element.triggerHandler("save",b),this.hide("save")},option:function(a,b){this.options[a]=b,a in this.containerOptions?(this.containerOptions[a]=b,this.setContainerOption(a,b)):(this.formOptions[a]=b,this.$form&&this.$form.editableform("option",a,b))},setContainerOption:function(a,b){this.call("option",a,b)},destroy:function(){this.hide(),this.innerDestroy(),this.$element.off("destroyed"),this.$element.removeData("editableContainer")},innerDestroy:function(){},closeOthers:function(b){a(".editable-open").each(function(c,d){if(d!==b&&!a(d).find(b).length){var e=a(d),f=e.data("editableContainer");f&&("cancel"===f.options.onblur?e.data("editableContainer").hide("onblur"):"submit"===f.options.onblur&&e.data("editableContainer").tip().find("form").submit())}})},activate:function(){this.tip&&this.tip().is(":visible")&&this.$form&&this.$form.data("editableform").input.activate()}},a.fn.editableContainer=function(d){var e=arguments;return this.each(function(){var f=a(this),g="editableContainer",h=f.data(g),i="object"==typeof d&&d,j="inline"===i.mode?c:b;h||f.data(g,h=new j(this,i)),"string"==typeof d&&h[d].apply(h,Array.prototype.slice.call(e,1))})},a.fn.editableContainer.Popup=b,a.fn.editableContainer.Inline=c,a.fn.editableContainer.defaults={value:null,placement:"top",autohide:!0,onblur:"cancel",anim:!1,mode:"popup"},jQuery.event.special.destroyed={remove:function(a){a.handler&&a.handler()}}}(window.jQuery),function(a){"use strict";a.extend(a.fn.editableContainer.Inline.prototype,a.fn.editableContainer.Popup.prototype,{containerName:"editableform",innerCss:".editable-inline",containerClass:"editable-container editable-inline",initContainer:function(){this.$tip=a(""),this.options.anim||(this.options.anim=0)},splitOptions:function(){this.containerOptions={},this.formOptions=this.options},tip:function(){return this.$tip},innerShow:function(){this.$element.hide(),this.tip().insertAfter(this.$element).show()},innerHide:function(){this.$tip.hide(this.options.anim,a.proxy(function(){this.$element.show(),this.innerDestroy()},this))},innerDestroy:function(){this.tip()&&this.tip().empty().remove()}})}(window.jQuery),function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.editable.defaults,c,a.fn.editableutils.getConfigData(this.$element)),this.options.selector?this.initLive():this.init(),this.options.highlight&&!a.fn.editableutils.supportsTransitions()&&(this.options.highlight=!1)};b.prototype={constructor:b,init:function(){var b,c=!1;if(this.options.name=this.options.name||this.$element.attr("id"),this.options.scope=this.$element[0],this.input=a.fn.editableutils.createInput(this.options),this.input){switch(void 0===this.options.value||null===this.options.value?(this.value=this.input.html2value(a.trim(this.$element.html())),c=!0):(this.options.value=a.fn.editableutils.tryParseJson(this.options.value,!0),this.value="string"==typeof this.options.value?this.input.str2value(this.options.value):this.options.value),this.$element.addClass("editable"),"textarea"===this.input.type&&this.$element.addClass("editable-pre-wrapped"),"manual"!==this.options.toggle?(this.$element.addClass("editable-click"),this.$element.on(this.options.toggle+".editable",a.proxy(function(a){if(this.options.disabled||a.preventDefault(),"mouseenter"===this.options.toggle)this.show();else{var b="click"!==this.options.toggle;this.toggle(b)}},this))):this.$element.attr("tabindex",-1),"function"==typeof this.options.display&&(this.options.autotext="always"),this.options.autotext){case"always":b=!0;break;case"auto":b=!a.trim(this.$element.text()).length&&null!==this.value&&void 0!==this.value&&!c;break;default:b=!1}a.when(b?this.render():!0).then(a.proxy(function(){this.options.disabled?this.disable():this.enable(),this.$element.triggerHandler("init",this)},this))}},initLive:function(){var b=this.options.selector;this.options.selector=!1,this.options.autotext="never",this.$element.on(this.options.toggle+".editable",b,a.proxy(function(b){var c=a(b.target);c.data("editable")||(c.hasClass(this.options.emptyclass)&&c.empty(),c.editable(this.options).trigger(b))},this))},render:function(a){return this.options.display!==!1?this.input.value2htmlFinal?this.input.value2html(this.value,this.$element[0],this.options.display,a):"function"==typeof this.options.display?this.options.display.call(this.$element[0],this.value,a):this.input.value2html(this.value,this.$element[0]):void 0},enable:function(){this.options.disabled=!1,this.$element.removeClass("editable-disabled"),this.handleEmpty(this.isEmpty),"manual"!==this.options.toggle&&"-1"===this.$element.attr("tabindex")&&this.$element.removeAttr("tabindex")},disable:function(){this.options.disabled=!0,this.hide(),this.$element.addClass("editable-disabled"),this.handleEmpty(this.isEmpty),this.$element.attr("tabindex",-1)},toggleDisabled:function(){this.options.disabled?this.enable():this.disable()},option:function(b,c){return b&&"object"==typeof b?(a.each(b,a.proxy(function(b,c){this.option(a.trim(b),c)},this)),void 0):(this.options[b]=c,"disabled"===b?c?this.disable():this.enable():("value"===b&&this.setValue(c),this.container&&this.container.option(b,c),this.input.option&&this.input.option(b,c),void 0))},handleEmpty:function(b){this.options.display!==!1&&(this.isEmpty=void 0!==b?b:"function"==typeof this.input.isEmpty?this.input.isEmpty(this.$element):""===a.trim(this.$element.html()),this.options.disabled?this.isEmpty&&(this.$element.empty(),this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass)):this.isEmpty?(this.$element.html(this.options.emptytext),this.options.emptyclass&&this.$element.addClass(this.options.emptyclass)):this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass))},show:function(b){if(!this.options.disabled){if(this.container){if(this.container.tip().is(":visible"))return}else{var c=a.extend({},this.options,{value:this.value,input:this.input});this.$element.editableContainer(c),this.$element.on("save.internal",a.proxy(this.save,this)),this.container=this.$element.data("editableContainer")}this.container.show(b)}},hide:function(){this.container&&this.container.hide()},toggle:function(a){this.container&&this.container.tip().is(":visible")?this.hide():this.show(a)},save:function(a,b){if(this.options.unsavedclass){var c=!1;c=c||"function"==typeof this.options.url,c=c||this.options.display===!1,c=c||void 0!==b.response,c=c||this.options.savenochange&&this.input.value2str(this.value)!==this.input.value2str(b.newValue),c?this.$element.removeClass(this.options.unsavedclass):this.$element.addClass(this.options.unsavedclass)}if(this.options.highlight){var d=this.$element,e=d.css("background-color");d.css("background-color",this.options.highlight),setTimeout(function(){"transparent"===e&&(e=""),d.css("background-color",e),d.addClass("editable-bg-transition"),setTimeout(function(){d.removeClass("editable-bg-transition")},1700)},10)}this.setValue(b.newValue,!1,b.response)},validate:function(){return"function"==typeof this.options.validate?this.options.validate.call(this,this.value):void 0},setValue:function(b,c,d){this.value=c?this.input.str2value(b):b,this.container&&this.container.option("value",this.value),a.when(this.render(d)).then(a.proxy(function(){this.handleEmpty()},this))},activate:function(){this.container&&this.container.activate()},destroy:function(){this.disable(),this.container&&this.container.destroy(),this.input.destroy(),"manual"!==this.options.toggle&&(this.$element.removeClass("editable-click"),this.$element.off(this.options.toggle+".editable")),this.$element.off("save.internal"),this.$element.removeClass("editable editable-open editable-disabled"),this.$element.removeData("editable")}},a.fn.editable=function(c){var d={},e=arguments,f="editable";switch(c){case"validate":return this.each(function(){var b,c=a(this),e=c.data(f);e&&(b=e.validate())&&(d[e.options.name]=b)}),d;case"getValue":return 2===arguments.length&&arguments[1]===!0?d=this.eq(0).data(f).value:this.each(function(){var b=a(this),c=b.data(f);c&&void 0!==c.value&&null!==c.value&&(d[c.options.name]=c.input.value2submit(c.value))}),d;case"submit":var g,h=arguments[1]||{},i=this,j=this.editable("validate");return a.isEmptyObject(j)?(g=this.editable("getValue"),h.data&&a.extend(g,h.data),a.ajax(a.extend({url:h.url,data:g,type:"POST"},h.ajaxOptions)).success(function(a){"function"==typeof h.success&&h.success.call(i,a,h)}).error(function(){"function"==typeof h.error&&h.error.apply(i,arguments)})):"function"==typeof h.error&&h.error.call(i,j),this}return this.each(function(){var d=a(this),g=d.data(f),h="object"==typeof c&&c;return h&&h.selector?(g=new b(this,h),void 0):(g||d.data(f,g=new b(this,h)),"string"==typeof c&&g[c].apply(g,Array.prototype.slice.call(e,1)),void 0)})},a.fn.editable.defaults={type:"text",disabled:!1,toggle:"click",emptytext:"Empty",autotext:"auto",value:null,display:null,emptyclass:"editable-empty",unsavedclass:"editable-unsaved",selector:null,highlight:"#FFFF80"}}(window.jQuery),function(a){"use strict";a.fn.editabletypes={};var b=function(){};b.prototype={init:function(b,c,d){this.type=b,this.options=a.extend({},d,c)},prerender:function(){this.$tpl=a(this.options.tpl),this.$input=this.$tpl,this.$clear=null,this.error=null},render:function(){},value2html:function(b,c){a(c)[this.options.escape?"text":"html"](a.trim(b))},html2value:function(b){return a("
").html(b).text()},value2str:function(a){return a},str2value:function(a){return a},value2submit:function(a){return a},value2input:function(a){this.$input.val(a)},input2value:function(){return this.$input.val()},activate:function(){this.$input.is(":visible")&&this.$input.focus()},clear:function(){this.$input.val(null)},escape:function(b){return a("
").text(b).html()},autosubmit:function(){},destroy:function(){},setClass:function(){this.options.inputclass&&this.$input.addClass(this.options.inputclass)},setAttr:function(a){void 0!==this.options[a]&&null!==this.options[a]&&this.$input.attr(a,this.options[a])},option:function(a,b){this.options[a]=b}},b.defaults={tpl:"",inputclass:null,escape:!0,scope:null,showbuttons:!0},a.extend(a.fn.editabletypes,{abstractinput:b})}(window.jQuery),function(a){"use strict";var b=function(){};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){var b=a.Deferred();return this.error=null,this.onSourceReady(function(){this.renderList(),b.resolve()},function(){this.error=this.options.sourceError,b.resolve()}),b.promise()},html2value:function(){return null},value2html:function(b,c,d,e){var f=a.Deferred(),g=function(){"function"==typeof d?d.call(c,b,this.sourceData,e):this.value2htmlFinal(b,c),f.resolve()};return null===b?g.call(this):this.onSourceReady(g,function(){f.resolve()}),f.promise()},onSourceReady:function(b,c){var d;if(a.isFunction(this.options.source)?(d=this.options.source.call(this.options.scope),this.sourceData=null):d=this.options.source,this.options.sourceCache&&a.isArray(this.sourceData))return b.call(this),void 0;try{d=a.fn.editableutils.tryParseJson(d,!1)}catch(e){return c.call(this),void 0}if("string"==typeof d){if(this.options.sourceCache){var f,g=d;if(a(document).data(g)||a(document).data(g,{}),f=a(document).data(g),f.loading===!1&&f.sourceData)return this.sourceData=f.sourceData,this.doPrepend(),b.call(this),void 0;if(f.loading===!0)return f.callbacks.push(a.proxy(function(){this.sourceData=f.sourceData,this.doPrepend(),b.call(this)},this)),f.err_callbacks.push(a.proxy(c,this)),void 0;f.loading=!0,f.callbacks=[],f.err_callbacks=[]}var h=a.extend({url:d,type:"get",cache:!1,dataType:"json",success:a.proxy(function(d){f&&(f.loading=!1),this.sourceData=this.makeArray(d),a.isArray(this.sourceData)?(f&&(f.sourceData=this.sourceData,a.each(f.callbacks,function(){this.call()})),this.doPrepend(),b.call(this)):(c.call(this),f&&a.each(f.err_callbacks,function(){this.call()}))},this),error:a.proxy(function(){c.call(this),f&&(f.loading=!1,a.each(f.err_callbacks,function(){this.call()}))},this)},this.options.sourceOptions);a.ajax(h)}else this.sourceData=this.makeArray(d),a.isArray(this.sourceData)?(this.doPrepend(),b.call(this)):c.call(this)},doPrepend:function(){null!==this.options.prepend&&void 0!==this.options.prepend&&(a.isArray(this.prependData)||(a.isFunction(this.options.prepend)&&(this.options.prepend=this.options.prepend.call(this.options.scope)),this.options.prepend=a.fn.editableutils.tryParseJson(this.options.prepend,!0),"string"==typeof this.options.prepend&&(this.options.prepend={"":this.options.prepend}),this.prependData=this.makeArray(this.options.prepend)),a.isArray(this.prependData)&&a.isArray(this.sourceData)&&(this.sourceData=this.prependData.concat(this.sourceData)))},renderList:function(){},value2htmlFinal:function(){},makeArray:function(b){var c,d,e,f,g=[];if(!b||"string"==typeof b)return null;if(a.isArray(b)){f=function(a,b){return d={value:a,text:b},c++>=2?!1:void 0};for(var h=0;h1&&(e.children&&(e.children=this.makeArray(e.children)),g.push(e))):g.push({value:e,text:e})}else a.each(b,function(a,b){g.push({value:a,text:b})});return g},option:function(a,b){this.options[a]=b,"source"===a&&(this.sourceData=null),"prepend"===a&&(this.prependData=null)}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{source:null,prepend:!1,sourceError:"Error when loading list",sourceCache:!0,sourceOptions:null}),a.fn.editabletypes.list=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("text",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.renderClear(),this.setClass(),this.setAttr("placeholder")},activate:function(){this.$input.is(":visible")&&(this.$input.focus(),a.fn.editableutils.setCursorPosition(this.$input.get(0),this.$input.val().length),this.toggleClear&&this.toggleClear())},renderClear:function(){this.options.clear&&(this.$clear=a(''),this.$input.after(this.$clear).css("padding-right",24).keyup(a.proxy(function(b){if(!~a.inArray(b.keyCode,[40,38,9,13,27])){clearTimeout(this.t);var c=this;this.t=setTimeout(function(){c.toggleClear(b)},100)}},this)).parent().css("position","relative"),this.$clear.click(a.proxy(this.clear,this)))},postrender:function(){},toggleClear:function(){if(this.$clear){var a=this.$input.val().length,b=this.$clear.is(":visible");a&&!b&&this.$clear.show(),!a&&b&&this.$clear.hide()}},clear:function(){this.$clear.hide(),this.$input.val("").focus()}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'',placeholder:null,clear:!0}),a.fn.editabletypes.text=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("textarea",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.setClass(),this.setAttr("placeholder"),this.setAttr("rows"),this.$input.keydown(function(b){b.ctrlKey&&13===b.which&&a(this).closest("form").submit()})},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:"",inputclass:"input-large",placeholder:null,rows:7}),a.fn.editabletypes.textarea=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("select",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.list),a.extend(b.prototype,{renderList:function(){this.$input.empty();var b=function(c,d){var e;if(a.isArray(d))for(var f=0;f",e),d[f].children))):(e.value=d[f].value,d[f].disabled&&(e.disabled=!0),c.append(a("