├── README.md └── mqtt ├── Node.js ├── .gitignore ├── README.md ├── package.json ├── publisher.js └── subscriber.js ├── README.md ├── mqtt_send_digital ├── mqtt_send_digital.fzz ├── mqtt_send_digital.ino └── mqtt_send_digital_bb.png ├── python ├── README.md ├── ca.crt ├── publisher.py └── subscriber.py └── web-interface ├── animate.css ├── bulb.svg ├── bulb_off.svg ├── index.html ├── light.svg ├── main.js ├── mqttws31.js ├── style.css └── webpanel.png /README.md: -------------------------------------------------------------------------------- 1 | # Cloud Examples 2 | 3 | A collection of code examples for interacting with the Arduino Cloud. 4 | 5 | ## [MQTT Examples](mqtt) 6 | 7 | Examples using the [MQTT](http://mqtt.org) protocol. MQTT is a lightweight 8 | publish/suscribe connectivity protocol. 9 | -------------------------------------------------------------------------------- /mqtt/Node.js/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /mqtt/Node.js/README.md: -------------------------------------------------------------------------------- 1 | # Arduino Cloud - Node.js MQTT client examples 2 | 3 | This folder contains examples on how to use [Node.js](https://nodejs.org/en/) to interact with the Arduino Cloud MQTT broker service. 4 | 5 | It uses the [MQTT.js](https://github.com/mqttjs/MQTT.js) library. 6 | 7 | ## Getting Started 8 | 9 | 1. Make sure Node.js is installed, it can be downloaded from [here](https://nodejs.org/en/download/). 10 | 1. Run ``npm install`` in this folder to install the MQTT.js library. 11 | 1. Login into https://cloud.arduino.cc with your Arduino account to view your MQTT credentials. 12 | 13 | ## Examples 14 | 15 | ### Subscriber 16 | 17 | 1. Open [``subscriber.js``](subscriber.js) in a text editor. 18 | 1. Update the ``username`` and ``password``, save the file. 19 | 1. Run ``node subscriber.js`` 20 | 21 | Any messages sent to the subscribed topic will be printed out to the console. 22 | 23 | ### Publisher 24 | 25 | 1. Open [``publisher.js``](publisher.js) in a text editor. 26 | 1. Update the ``username`` and ``password``, save the file. 27 | 1. Run ``node publisher.js`` 28 | 29 | To send a custom message, run with a parameter: 30 | 31 | ```sh 32 | node publisher.js 0 33 | 34 | node publisher.js 255 35 | ``` 36 | 37 | The first command will publish "0", while the second command will publish "255" to the topic 38 | -------------------------------------------------------------------------------- /mqtt/Node.js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arduino-cloud-mqtt-client-example", 3 | "version": "1.0.0", 4 | "license": "ISC", 5 | "private": true, 6 | "dependencies": { 7 | "mqtt": "^1.4.1" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mqtt/Node.js/publisher.js: -------------------------------------------------------------------------------- 1 | var mqtt = require('mqtt'); // https://github.com/mqttjs/MQTT.js 2 | 3 | var brokerURI = 'mqtts://mqtt.arduino.cc'; 4 | 5 | // use the values shown after logging into https://cloud.arduino.cc 6 | var username = 'username'; 7 | var password = 'password'; 8 | var baseTopic = '/' + username; 9 | var topic = baseTopic + '/001'; 10 | 11 | // default message 12 | var message = '0'; 13 | 14 | if (process.argv.length > 2) { 15 | // use command line argument as message 16 | message = process.argv[2] 17 | } 18 | 19 | // create client and connect 20 | var client = mqtt.connect(brokerURI, { 21 | username: username, 22 | password: password 23 | }); 24 | 25 | // attatch event listener for 'connect' event 26 | client.on('connect', function () { 27 | // client has connected to the broker 28 | console.log('connected'); 29 | 30 | // publish the message to the topic 31 | client.publish(topic, message, {}, function() { 32 | // mesage has been published 33 | console.log('message published: ' + message); 34 | 35 | // all done, exit 36 | process.exit(0); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /mqtt/Node.js/subscriber.js: -------------------------------------------------------------------------------- 1 | var mqtt = require('mqtt'); // https://github.com/mqttjs/MQTT.js 2 | 3 | var brokerURI = 'mqtts://mqtt.arduino.cc'; 4 | 5 | // use the values shown after logging into https://cloud.arduino.cc 6 | var username = 'username'; 7 | var password = 'password'; 8 | var baseTopic = '/' + username; 9 | var topic = baseTopic + '/001'; 10 | 11 | // default message 12 | var message = '0'; 13 | 14 | if (process.argv.length > 2) { 15 | // use command line argument as message 16 | message = process.argv[2] 17 | } 18 | 19 | // create client and connect 20 | var client = mqtt.connect(brokerURI, { 21 | username: username, 22 | password: password 23 | }); 24 | 25 | // attatch event listener for 'connect' event 26 | client.on('connect', function () { 27 | // client has connected to the broker 28 | console.log('connected'); 29 | 30 | // subscribe to the topic 31 | client.subscribe(topic); 32 | }); 33 | 34 | // attatch event listener for 'message' event 35 | client.on('message', function (topic, message) { 36 | // print out topic and message 37 | console.log('Received message: ' + topic + ' ' + message); 38 | }); 39 | -------------------------------------------------------------------------------- /mqtt/README.md: -------------------------------------------------------------------------------- 1 | # Using MQTT with the Arduino WiFi Shield 101 and Arduino Cloud 2 | 3 | All examples require you to supply your own Arduino Cloud MQTT service credentials. Credentials can be found after logging into the Arduino Cloud portal: [cloud.arduino.cc](https://cloud.arduino.cc) 4 | 5 | ## Arduino Client 6 | 7 | This series of examples is based on [pubsubclient](https://github.com/knolleary/pubsubclient) Arduino Client for MQTT library by Nick O'Leary ([@knolleary](https://github.com/knolleary)). 8 | 9 | ## [MQTT Send Digital](mqtt_send_digital) 10 | 11 | This example updates the Arduino Cloud MQTT broker service with the status of an LED which is controlled by a pushbutton. 12 | 13 | An Arduino WiFi shield 101 is used to connect securely to the broker service using SSL. 14 | 15 | To run: 16 | 17 | 1. Install the ```PubSubClient``` library using the Arduino IDE library manager (Sketch -> Include Library -> Manage Libraries...). 18 | 1. Install the ```WiFi101``` library using the Arduino IDE library manager (Sketch -> Include Library -> Manage Libraries...). 19 | 1. Connect the WiFi Shield 101 to your Arduino or Genuino board. 20 | 1. Wire the LED and pushbutton as shown in the diagram below. **Note:** if you are using the Uno, wire the LED to pin 3 instead of 13. 21 | 1. Connect your Arduino or Genuino board to your computer using a USB cable. 22 | 1. Open the ``mqtt_send_digital.ino`` sketch in the Arduino IDE. 23 | 1. Update the WiFi settings and MQTT settings in the sketch file. 24 | 1. Upload the sketch to your boards. 25 | 1. Use the Serial Monitor to verify the successful connectivity to the WiFI network and MQTT broker. 26 | 27 | ![Wiring diagram for sketch](mqtt_send_digital/mqtt_send_digital_bb.png) 28 | 29 | When the pushbutton is pressed or released the LED will turn on or off, and also send a message to the MQTT broker to update the topic value. 30 | 31 | # [Web UI Client](web-interface) 32 | 33 | The Web UI example visualizes the mesages sent by the Arduino MQTT client. It uses the [Paho JavaScript Client library](https://eclipse.org/paho/clients/js/) to connect to the Arduino Cloud MQTT broker service. 34 | 35 | 36 | To run: 37 | 38 | 1. Download the source from this repository. By either: 39 | * Downloading and extracting [cloud-examples-master.zip](https://github.com/arduino/cloud-examples/archive/master.zip) 40 | * Or cloning the repository using ``git`` 41 | 1. Go into the ``mqtt/web-interface`` folder. 42 | 1. Open the ``main.js`` file in a text editor. 43 | 1. Update the MQTT settings at the top of the file. 44 | 1. Open ``index.html`` in a Web Browser 45 | 46 | An image of a light bulb is display on the page, it will update when the pushbutton is pressed and released. 47 | 48 | ![Web UI screenshot](web-interface/webpanel.png) 49 | 50 | ## [Node.js Client](Node.js) 51 | 52 | See [Node.js](Node.js) folder, it contains a publisher and subscriber example. 53 | 54 | ## [Python Client](python) 55 | 56 | See [Python](python) folder, it contains a publisher and subscriber example. 57 | -------------------------------------------------------------------------------- /mqtt/mqtt_send_digital/mqtt_send_digital.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arduino/cloud-examples/fd19106aa900df5f591f50b4bb61ed1f7545df77/mqtt/mqtt_send_digital/mqtt_send_digital.fzz -------------------------------------------------------------------------------- /mqtt/mqtt_send_digital/mqtt_send_digital.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This example connects to a WPA encrypted WiFi network, 3 | using the WiFi Shield 101. 4 | 5 | Then connects to the Arduino Cloud MQTT broker using 6 | SSL, and sends updates on the status of an LED which 7 | is controlled by a button. 8 | 9 | Circuit: 10 | * WiFi shield attached 11 | * LED 12 | * button 13 | 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | // include PubSubClient library 21 | // https://github.com/knolleary/pubsubclient 22 | #include 23 | 24 | // WiFi settings 25 | char ssid[] = "yourNetwork"; // your network SSID (name) 26 | char password[] = "secretPassword"; // your network password 27 | 28 | // MQTT settings 29 | char mqttServer[] = "mqtt.arduino.cc"; 30 | int mqttPort = 8883; 31 | char mqttClientName[] = "arduinoWiFiSSLClient"; 32 | char mqttUsername[] = "username"; // your MQTT username 33 | char mqttPassword[] = "password"; // your MQTT password 34 | char mqttTopic[] = "/username/001"; // your MQTT topic //topic 35 | 36 | // You can also access the MQTT broker service 37 | // using the same set of credentials using 38 | // WebSockets via the following URI: 39 | // 40 | // wss://mqtt.arduino.cc:9002/ 41 | // 42 | // This would allow you to subscribe and publish 43 | // to MQTT topics using a web browser. 44 | 45 | // constants won't change. They're used here to 46 | // set pin numbers: 47 | const int buttonPin = 2; // the number of the pushbutton pin 48 | const int ledPin = 13; // the number of the LED pin 49 | 50 | // variables will change: 51 | int wifiStatus = WL_IDLE_STATUS; // the Wifi radio's status 52 | int buttonState = 0; // variable for reading the pushbutton status 53 | int oldButtonState = -1; // variable for storing the old pushbutton status 54 | 55 | 56 | // Initialize the WiFi SSL client library 57 | WiFiSSLClient wifiSSLClient; 58 | 59 | // Initialize the PubSubClient 60 | PubSubClient mqttClient(mqttServer, mqttPort, wifiSSLClient); 61 | 62 | void setup() { 63 | // Initialize serial and wait for port to open: 64 | Serial.begin(9600); 65 | while (!Serial) { 66 | ; // wait for serial port to connect. Needed for native USB port only 67 | } 68 | 69 | setupWiFi(); 70 | 71 | Serial.println(F("Connecting to MQTT broker ...")); 72 | if (mqttClient.connect(mqttClientName, mqttUsername, mqttPassword)) { 73 | Serial.println(F("Connected :D")); 74 | } else { 75 | Serial.println(F("Connection failed :(")); 76 | // don't continue: 77 | while (true); 78 | } 79 | 80 | // initialize the LED pin as an output: 81 | pinMode(ledPin, OUTPUT); 82 | // initialize the pushbutton pin as an input pullup: 83 | pinMode(buttonPin, INPUT_PULLUP); 84 | } 85 | 86 | void setupWiFi() { 87 | // check for the presence of the shield: 88 | if (WiFi.status() == WL_NO_SHIELD) { 89 | Serial.println(F("WiFi shield not present")); 90 | // don't continue: 91 | while (true); 92 | } 93 | 94 | Serial.print("Firmware version is "); 95 | Serial.println(WiFi.firmwareVersion()); 96 | 97 | // attempt to connect to Wifi network: 98 | while (wifiStatus != WL_CONNECTED) { 99 | Serial.print(F("Attempting to connect to WPA SSID: ")); 100 | Serial.println(ssid); 101 | // Connect to WPA/WPA2 network: 102 | wifiStatus = WiFi.begin(ssid, password); 103 | 104 | if (wifiStatus != WL_CONNECTED) { 105 | // wait 10 seconds for next connection attempt 106 | delay(10000); 107 | } 108 | } 109 | 110 | Serial.println(F("Connected to wifi")); 111 | 112 | Serial.print(F("SSID: ")); 113 | Serial.println(WiFi.SSID()); 114 | 115 | // print your WiFi shield's IP address: 116 | IPAddress ip = WiFi.localIP(); 117 | Serial.print(F("IP Address: ")); 118 | Serial.println(ip); 119 | 120 | Serial.print(F("signal strength (RSSI):")); 121 | Serial.print(WiFi.RSSI()); 122 | Serial.println(F(" dBm")); 123 | } 124 | 125 | void loop() { 126 | // let the MQTT client process events 127 | mqttClient.loop(); 128 | 129 | // read the state of the pushbutton value: 130 | buttonState = digitalRead(buttonPin); 131 | 132 | // compare button state to old, to see 133 | // if it has changed 134 | if (oldButtonState != buttonState) { 135 | // it has changed store the new value: 136 | oldButtonState = buttonState; 137 | 138 | // check if the pushbutton is pressed. 139 | // if it is, the buttonState is LOW: 140 | if (buttonState == LOW) { 141 | Serial.println(F("Button pressed")); 142 | 143 | // turn LED on: 144 | digitalWrite(ledPin, HIGH); 145 | 146 | // publish new value for topic to MQTT broker 147 | mqttClient.publish(mqttTopic, "255"); 148 | } else { 149 | Serial.println(F("Button released")); 150 | 151 | // turn LED off: 152 | digitalWrite(ledPin, LOW); 153 | 154 | // publish new value for topic to MQTT broker 155 | mqttClient.publish(mqttTopic, "0"); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /mqtt/mqtt_send_digital/mqtt_send_digital_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arduino/cloud-examples/fd19106aa900df5f591f50b4bb61ed1f7545df77/mqtt/mqtt_send_digital/mqtt_send_digital_bb.png -------------------------------------------------------------------------------- /mqtt/python/README.md: -------------------------------------------------------------------------------- 1 | # Arduino Cloud - Python MQTT client examples 2 | 3 | This folder contains examples on how to use [Python](https://www.python.org) to interact with the Arduino Cloud MQTT broker service. 4 | 5 | It uses the [paho Python client](https://eclipse.org/paho/clients/python/) library. 6 | 7 | ## Getting Started 8 | 9 | 1. Make sure Python is installed, it can be downloaded from [here](https://www.python.org/downloads/). 10 | 1. Run ``pip install paho-mqtt`` to install the paho Python client library. 11 | 1. Login into https://cloud.arduino.cc with your Arduino account to view your MQTT credentials. 12 | 13 | ## Examples 14 | 15 | ### Subscriber 16 | 17 | 1. Open [``subscriber.py``](subscriber.py) in a text editor. 18 | 1. Update the ``username`` and ``password``, save the file. 19 | 1. Run ``python subscriber.py`` 20 | 21 | Any messages sent to the subscribed topic will be printed out to the console. 22 | 23 | ### Publisher 24 | 25 | 1. Open [``publisher.py``](publisher.py) in a text editor. 26 | 1. Update the ``username`` and ``password``, save the file. 27 | 1. Run ``python publisher.py`` 28 | 29 | To send a custom message, run with a parameter: 30 | 31 | ```sh 32 | python publisher.py 0 33 | 34 | python publisher.py 255 35 | ``` 36 | 37 | The first command will publish "0", while the second command will publish "255" to the topic. 38 | -------------------------------------------------------------------------------- /mqtt/python/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh 3 | MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE 4 | YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 5 | MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo 6 | ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg 7 | MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN 8 | ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA 9 | PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w 10 | wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi 11 | EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY 12 | avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ 13 | YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE 14 | sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h 15 | /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 16 | IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj 17 | YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD 18 | ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy 19 | OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P 20 | TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ 21 | HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER 22 | dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf 23 | ReYNnyicsbkqWletNw+vHX/bvZ8= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /mqtt/python/publisher.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import paho.mqtt.client as mqtt # https://eclipse.org/paho/clients/python/ 3 | 4 | server = "mqtt.arduino.cc" 5 | port = 8883 6 | 7 | # use the values shown after logging into https://cloud.arduino.cc 8 | username = "username" 9 | password = "password" 10 | base_topic = "/" + username; 11 | topic = base_topic + "/001" 12 | 13 | # default message value 14 | message = "0" 15 | 16 | if len(sys.argv) > 1: 17 | # use command line argument as message 18 | message = sys.argv[1] 19 | 20 | # The callback for when the client is connected to the broker 21 | def on_connect(client, userdata, flags, rc): 22 | print("Connected with result: " + mqtt.connack_string(rc)) 23 | 24 | # publish message to the topic 25 | client.publish(topic, message) 26 | 27 | # The callback for when the client is disconnected from the broker 28 | def on_disconnect(client, userdata, rc): 29 | if rc != 0: 30 | print("Unexpected disconnection") 31 | 32 | # The callback for when the client has published a message 33 | def on_publish(client, userdata, mid): 34 | print("Message published: " + message) 35 | 36 | # message published, disconnect 37 | client.disconnect() 38 | 39 | # create a new MQTT client 40 | client = mqtt.Client() 41 | 42 | # configure CA cert for SSL connection 43 | client.tls_set("ca.crt") 44 | 45 | # set username and password 46 | client.username_pw_set(username, password) 47 | 48 | # assign callbacks 49 | client.on_connect = on_connect 50 | client.on_disconnect = on_disconnect 51 | client.on_publish = on_publish 52 | 53 | # start connection 54 | client.connect(server, port) 55 | 56 | # let the client loop (this is a blocking call), will unblock when the client disconnects 57 | client.loop_forever() 58 | -------------------------------------------------------------------------------- /mqtt/python/subscriber.py: -------------------------------------------------------------------------------- 1 | import paho.mqtt.client as mqtt # https://eclipse.org/paho/clients/python/ 2 | 3 | server = "mqtt.arduino.cc" 4 | port = 8883 5 | 6 | # use the values shown after logging into https://cloud.arduino.cc 7 | username = "username" 8 | password = "password" 9 | base_topic = "/" + username; 10 | topic = base_topic + "/001" 11 | 12 | 13 | # The callback for when the client is connected to the broker 14 | def on_connect(client, userdata, flags, rc): 15 | print("Connected with result: " + mqtt.connack_string(rc)) 16 | 17 | # subscribe to the topic 18 | client.subscribe(topic) 19 | 20 | # The callback for when the client is disconnected from the broker 21 | def on_disconnect(client, userdata, rc): 22 | if rc != 0: 23 | print("Unexpected disconnection") 24 | 25 | # The callback for when the client is subscribed to a topic 26 | def on_subscribe(client, userdata, mid, granted_qos): 27 | print("Subscribed to topic: " + topic) 28 | 29 | # The callback for when a message for a subscribed topic is received from the broker 30 | def on_message(client, userdata, msg): 31 | print("Received message: " + msg.topic + " " + str(msg.payload)) 32 | 33 | # create a new MQTT client 34 | client = mqtt.Client() 35 | 36 | # configure CA cert for SSL connection 37 | client.tls_set("ca.crt") 38 | 39 | # set username and password 40 | client.username_pw_set(username, password) 41 | 42 | # assign callbacks 43 | client.on_connect = on_connect 44 | client.on_disconnect = on_disconnect 45 | client.on_subscribe = on_subscribe 46 | client.on_message = on_message 47 | 48 | # start connection 49 | client.connect(server, port) 50 | 51 | # let the client loop forever (this is a blocking call) 52 | client.loop_forever() 53 | -------------------------------------------------------------------------------- /mqtt/web-interface/animate.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /*! 4 | Animate.css - http://daneden.me/animate 5 | Licensed under the MIT license - http://opensource.org/licenses/MIT 6 | 7 | Copyright (c) 2015 Daniel Eden 8 | */ 9 | 10 | .animated { 11 | -webkit-animation-duration: 1s; 12 | animation-duration: 1s; 13 | -webkit-animation-fill-mode: both; 14 | animation-fill-mode: both; 15 | } 16 | 17 | .animated.infinite { 18 | -webkit-animation-iteration-count: infinite; 19 | animation-iteration-count: infinite; 20 | } 21 | 22 | .animated.hinge { 23 | -webkit-animation-duration: 2s; 24 | animation-duration: 2s; 25 | } 26 | 27 | .animated.bounceIn, 28 | .animated.bounceOut { 29 | -webkit-animation-duration: .75s; 30 | animation-duration: .75s; 31 | } 32 | 33 | .animated.flipOutX, 34 | .animated.flipOutY { 35 | -webkit-animation-duration: .75s; 36 | animation-duration: .75s; 37 | } 38 | 39 | @-webkit-keyframes bounce { 40 | from, 20%, 53%, 80%, to { 41 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 42 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 43 | -webkit-transform: translate3d(0,0,0); 44 | transform: translate3d(0,0,0); 45 | } 46 | 47 | 40%, 43% { 48 | -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); 49 | animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); 50 | -webkit-transform: translate3d(0, -30px, 0); 51 | transform: translate3d(0, -30px, 0); 52 | } 53 | 54 | 70% { 55 | -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); 56 | animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); 57 | -webkit-transform: translate3d(0, -15px, 0); 58 | transform: translate3d(0, -15px, 0); 59 | } 60 | 61 | 90% { 62 | -webkit-transform: translate3d(0,-4px,0); 63 | transform: translate3d(0,-4px,0); 64 | } 65 | } 66 | 67 | @keyframes bounce { 68 | from, 20%, 53%, 80%, to { 69 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 70 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 71 | -webkit-transform: translate3d(0,0,0); 72 | transform: translate3d(0,0,0); 73 | } 74 | 75 | 40%, 43% { 76 | -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); 77 | animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); 78 | -webkit-transform: translate3d(0, -30px, 0); 79 | transform: translate3d(0, -30px, 0); 80 | } 81 | 82 | 70% { 83 | -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); 84 | animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); 85 | -webkit-transform: translate3d(0, -15px, 0); 86 | transform: translate3d(0, -15px, 0); 87 | } 88 | 89 | 90% { 90 | -webkit-transform: translate3d(0,-4px,0); 91 | transform: translate3d(0,-4px,0); 92 | } 93 | } 94 | 95 | .bounce { 96 | -webkit-animation-name: bounce; 97 | animation-name: bounce; 98 | -webkit-transform-origin: center bottom; 99 | transform-origin: center bottom; 100 | } 101 | 102 | @-webkit-keyframes flash { 103 | from, 50%, to { 104 | opacity: 1; 105 | } 106 | 107 | 25%, 75% { 108 | opacity: 0; 109 | } 110 | } 111 | 112 | @keyframes flash { 113 | from, 50%, to { 114 | opacity: 1; 115 | } 116 | 117 | 25%, 75% { 118 | opacity: 0; 119 | } 120 | } 121 | 122 | .flash { 123 | -webkit-animation-name: flash; 124 | animation-name: flash; 125 | } 126 | 127 | /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ 128 | 129 | @-webkit-keyframes pulse { 130 | from { 131 | -webkit-transform: scale3d(1, 1, 1); 132 | transform: scale3d(1, 1, 1); 133 | } 134 | 135 | 50% { 136 | -webkit-transform: scale3d(1.05, 1.05, 1.05); 137 | transform: scale3d(1.05, 1.05, 1.05); 138 | } 139 | 140 | to { 141 | -webkit-transform: scale3d(1, 1, 1); 142 | transform: scale3d(1, 1, 1); 143 | } 144 | } 145 | 146 | @keyframes pulse { 147 | from { 148 | -webkit-transform: scale3d(1, 1, 1); 149 | transform: scale3d(1, 1, 1); 150 | } 151 | 152 | 50% { 153 | -webkit-transform: scale3d(1.05, 1.05, 1.05); 154 | transform: scale3d(1.05, 1.05, 1.05); 155 | } 156 | 157 | to { 158 | -webkit-transform: scale3d(1, 1, 1); 159 | transform: scale3d(1, 1, 1); 160 | } 161 | } 162 | 163 | .pulse { 164 | -webkit-animation-name: pulse; 165 | animation-name: pulse; 166 | } 167 | 168 | @-webkit-keyframes rubberBand { 169 | from { 170 | -webkit-transform: scale3d(1, 1, 1); 171 | transform: scale3d(1, 1, 1); 172 | } 173 | 174 | 30% { 175 | -webkit-transform: scale3d(1.25, 0.75, 1); 176 | transform: scale3d(1.25, 0.75, 1); 177 | } 178 | 179 | 40% { 180 | -webkit-transform: scale3d(0.75, 1.25, 1); 181 | transform: scale3d(0.75, 1.25, 1); 182 | } 183 | 184 | 50% { 185 | -webkit-transform: scale3d(1.15, 0.85, 1); 186 | transform: scale3d(1.15, 0.85, 1); 187 | } 188 | 189 | 65% { 190 | -webkit-transform: scale3d(.95, 1.05, 1); 191 | transform: scale3d(.95, 1.05, 1); 192 | } 193 | 194 | 75% { 195 | -webkit-transform: scale3d(1.05, .95, 1); 196 | transform: scale3d(1.05, .95, 1); 197 | } 198 | 199 | to { 200 | -webkit-transform: scale3d(1, 1, 1); 201 | transform: scale3d(1, 1, 1); 202 | } 203 | } 204 | 205 | @keyframes rubberBand { 206 | from { 207 | -webkit-transform: scale3d(1, 1, 1); 208 | transform: scale3d(1, 1, 1); 209 | } 210 | 211 | 30% { 212 | -webkit-transform: scale3d(1.25, 0.75, 1); 213 | transform: scale3d(1.25, 0.75, 1); 214 | } 215 | 216 | 40% { 217 | -webkit-transform: scale3d(0.75, 1.25, 1); 218 | transform: scale3d(0.75, 1.25, 1); 219 | } 220 | 221 | 50% { 222 | -webkit-transform: scale3d(1.15, 0.85, 1); 223 | transform: scale3d(1.15, 0.85, 1); 224 | } 225 | 226 | 65% { 227 | -webkit-transform: scale3d(.95, 1.05, 1); 228 | transform: scale3d(.95, 1.05, 1); 229 | } 230 | 231 | 75% { 232 | -webkit-transform: scale3d(1.05, .95, 1); 233 | transform: scale3d(1.05, .95, 1); 234 | } 235 | 236 | to { 237 | -webkit-transform: scale3d(1, 1, 1); 238 | transform: scale3d(1, 1, 1); 239 | } 240 | } 241 | 242 | .rubberBand { 243 | -webkit-animation-name: rubberBand; 244 | animation-name: rubberBand; 245 | } 246 | 247 | @-webkit-keyframes shake { 248 | from, to { 249 | -webkit-transform: translate3d(0, 0, 0); 250 | transform: translate3d(0, 0, 0); 251 | } 252 | 253 | 10%, 30%, 50%, 70%, 90% { 254 | -webkit-transform: translate3d(-10px, 0, 0); 255 | transform: translate3d(-10px, 0, 0); 256 | } 257 | 258 | 20%, 40%, 60%, 80% { 259 | -webkit-transform: translate3d(10px, 0, 0); 260 | transform: translate3d(10px, 0, 0); 261 | } 262 | } 263 | 264 | @keyframes shake { 265 | from, to { 266 | -webkit-transform: translate3d(0, 0, 0); 267 | transform: translate3d(0, 0, 0); 268 | } 269 | 270 | 10%, 30%, 50%, 70%, 90% { 271 | -webkit-transform: translate3d(-10px, 0, 0); 272 | transform: translate3d(-10px, 0, 0); 273 | } 274 | 275 | 20%, 40%, 60%, 80% { 276 | -webkit-transform: translate3d(10px, 0, 0); 277 | transform: translate3d(10px, 0, 0); 278 | } 279 | } 280 | 281 | .shake { 282 | -webkit-animation-name: shake; 283 | animation-name: shake; 284 | } 285 | 286 | @-webkit-keyframes swing { 287 | 20% { 288 | -webkit-transform: rotate3d(0, 0, 1, 15deg); 289 | transform: rotate3d(0, 0, 1, 15deg); 290 | } 291 | 292 | 40% { 293 | -webkit-transform: rotate3d(0, 0, 1, -10deg); 294 | transform: rotate3d(0, 0, 1, -10deg); 295 | } 296 | 297 | 60% { 298 | -webkit-transform: rotate3d(0, 0, 1, 5deg); 299 | transform: rotate3d(0, 0, 1, 5deg); 300 | } 301 | 302 | 80% { 303 | -webkit-transform: rotate3d(0, 0, 1, -5deg); 304 | transform: rotate3d(0, 0, 1, -5deg); 305 | } 306 | 307 | to { 308 | -webkit-transform: rotate3d(0, 0, 1, 0deg); 309 | transform: rotate3d(0, 0, 1, 0deg); 310 | } 311 | } 312 | 313 | @keyframes swing { 314 | 20% { 315 | -webkit-transform: rotate3d(0, 0, 1, 15deg); 316 | transform: rotate3d(0, 0, 1, 15deg); 317 | } 318 | 319 | 40% { 320 | -webkit-transform: rotate3d(0, 0, 1, -10deg); 321 | transform: rotate3d(0, 0, 1, -10deg); 322 | } 323 | 324 | 60% { 325 | -webkit-transform: rotate3d(0, 0, 1, 5deg); 326 | transform: rotate3d(0, 0, 1, 5deg); 327 | } 328 | 329 | 80% { 330 | -webkit-transform: rotate3d(0, 0, 1, -5deg); 331 | transform: rotate3d(0, 0, 1, -5deg); 332 | } 333 | 334 | to { 335 | -webkit-transform: rotate3d(0, 0, 1, 0deg); 336 | transform: rotate3d(0, 0, 1, 0deg); 337 | } 338 | } 339 | 340 | .swing { 341 | -webkit-transform-origin: top center; 342 | transform-origin: top center; 343 | -webkit-animation-name: swing; 344 | animation-name: swing; 345 | } 346 | 347 | @-webkit-keyframes tada { 348 | from { 349 | -webkit-transform: scale3d(1, 1, 1); 350 | transform: scale3d(1, 1, 1); 351 | } 352 | 353 | 10%, 20% { 354 | -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); 355 | transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); 356 | } 357 | 358 | 30%, 50%, 70%, 90% { 359 | -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); 360 | transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); 361 | } 362 | 363 | 40%, 60%, 80% { 364 | -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); 365 | transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); 366 | } 367 | 368 | to { 369 | -webkit-transform: scale3d(1, 1, 1); 370 | transform: scale3d(1, 1, 1); 371 | } 372 | } 373 | 374 | @keyframes tada { 375 | from { 376 | -webkit-transform: scale3d(1, 1, 1); 377 | transform: scale3d(1, 1, 1); 378 | } 379 | 380 | 10%, 20% { 381 | -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); 382 | transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); 383 | } 384 | 385 | 30%, 50%, 70%, 90% { 386 | -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); 387 | transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); 388 | } 389 | 390 | 40%, 60%, 80% { 391 | -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); 392 | transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); 393 | } 394 | 395 | to { 396 | -webkit-transform: scale3d(1, 1, 1); 397 | transform: scale3d(1, 1, 1); 398 | } 399 | } 400 | 401 | .tada { 402 | -webkit-animation-name: tada; 403 | animation-name: tada; 404 | } 405 | 406 | /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ 407 | 408 | @-webkit-keyframes wobble { 409 | from { 410 | -webkit-transform: none; 411 | transform: none; 412 | } 413 | 414 | 15% { 415 | -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); 416 | transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); 417 | } 418 | 419 | 30% { 420 | -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); 421 | transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); 422 | } 423 | 424 | 45% { 425 | -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); 426 | transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); 427 | } 428 | 429 | 60% { 430 | -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); 431 | transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); 432 | } 433 | 434 | 75% { 435 | -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); 436 | transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); 437 | } 438 | 439 | to { 440 | -webkit-transform: none; 441 | transform: none; 442 | } 443 | } 444 | 445 | @keyframes wobble { 446 | from { 447 | -webkit-transform: none; 448 | transform: none; 449 | } 450 | 451 | 15% { 452 | -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); 453 | transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); 454 | } 455 | 456 | 30% { 457 | -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); 458 | transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); 459 | } 460 | 461 | 45% { 462 | -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); 463 | transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); 464 | } 465 | 466 | 60% { 467 | -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); 468 | transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); 469 | } 470 | 471 | 75% { 472 | -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); 473 | transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); 474 | } 475 | 476 | to { 477 | -webkit-transform: none; 478 | transform: none; 479 | } 480 | } 481 | 482 | .wobble { 483 | -webkit-animation-name: wobble; 484 | animation-name: wobble; 485 | } 486 | 487 | @-webkit-keyframes jello { 488 | from, 11.1%, to { 489 | -webkit-transform: none; 490 | transform: none; 491 | } 492 | 493 | 22.2% { 494 | -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); 495 | transform: skewX(-12.5deg) skewY(-12.5deg); 496 | } 497 | 498 | 33.3% { 499 | -webkit-transform: skewX(6.25deg) skewY(6.25deg); 500 | transform: skewX(6.25deg) skewY(6.25deg); 501 | } 502 | 503 | 44.4% { 504 | -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); 505 | transform: skewX(-3.125deg) skewY(-3.125deg); 506 | } 507 | 508 | 55.5% { 509 | -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); 510 | transform: skewX(1.5625deg) skewY(1.5625deg); 511 | } 512 | 513 | 66.6% { 514 | -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); 515 | transform: skewX(-0.78125deg) skewY(-0.78125deg); 516 | } 517 | 518 | 77.7% { 519 | -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); 520 | transform: skewX(0.390625deg) skewY(0.390625deg); 521 | } 522 | 523 | 88.8% { 524 | -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); 525 | transform: skewX(-0.1953125deg) skewY(-0.1953125deg); 526 | } 527 | } 528 | 529 | @keyframes jello { 530 | from, 11.1%, to { 531 | -webkit-transform: none; 532 | transform: none; 533 | } 534 | 535 | 22.2% { 536 | -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); 537 | transform: skewX(-12.5deg) skewY(-12.5deg); 538 | } 539 | 540 | 33.3% { 541 | -webkit-transform: skewX(6.25deg) skewY(6.25deg); 542 | transform: skewX(6.25deg) skewY(6.25deg); 543 | } 544 | 545 | 44.4% { 546 | -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); 547 | transform: skewX(-3.125deg) skewY(-3.125deg); 548 | } 549 | 550 | 55.5% { 551 | -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); 552 | transform: skewX(1.5625deg) skewY(1.5625deg); 553 | } 554 | 555 | 66.6% { 556 | -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); 557 | transform: skewX(-0.78125deg) skewY(-0.78125deg); 558 | } 559 | 560 | 77.7% { 561 | -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); 562 | transform: skewX(0.390625deg) skewY(0.390625deg); 563 | } 564 | 565 | 88.8% { 566 | -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); 567 | transform: skewX(-0.1953125deg) skewY(-0.1953125deg); 568 | } 569 | } 570 | 571 | .jello { 572 | -webkit-animation-name: jello; 573 | animation-name: jello; 574 | -webkit-transform-origin: center; 575 | transform-origin: center; 576 | } 577 | 578 | @-webkit-keyframes bounceIn { 579 | from, 20%, 40%, 60%, 80%, to { 580 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 581 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 582 | } 583 | 584 | 0% { 585 | opacity: 0; 586 | -webkit-transform: scale3d(.3, .3, .3); 587 | transform: scale3d(.3, .3, .3); 588 | } 589 | 590 | 20% { 591 | -webkit-transform: scale3d(1.1, 1.1, 1.1); 592 | transform: scale3d(1.1, 1.1, 1.1); 593 | } 594 | 595 | 40% { 596 | -webkit-transform: scale3d(.9, .9, .9); 597 | transform: scale3d(.9, .9, .9); 598 | } 599 | 600 | 60% { 601 | opacity: 1; 602 | -webkit-transform: scale3d(1.03, 1.03, 1.03); 603 | transform: scale3d(1.03, 1.03, 1.03); 604 | } 605 | 606 | 80% { 607 | -webkit-transform: scale3d(.97, .97, .97); 608 | transform: scale3d(.97, .97, .97); 609 | } 610 | 611 | to { 612 | opacity: 1; 613 | -webkit-transform: scale3d(1, 1, 1); 614 | transform: scale3d(1, 1, 1); 615 | } 616 | } 617 | 618 | @keyframes bounceIn { 619 | from, 20%, 40%, 60%, 80%, to { 620 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 621 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 622 | } 623 | 624 | 0% { 625 | opacity: 0; 626 | -webkit-transform: scale3d(.3, .3, .3); 627 | transform: scale3d(.3, .3, .3); 628 | } 629 | 630 | 20% { 631 | -webkit-transform: scale3d(1.1, 1.1, 1.1); 632 | transform: scale3d(1.1, 1.1, 1.1); 633 | } 634 | 635 | 40% { 636 | -webkit-transform: scale3d(.9, .9, .9); 637 | transform: scale3d(.9, .9, .9); 638 | } 639 | 640 | 60% { 641 | opacity: 1; 642 | -webkit-transform: scale3d(1.03, 1.03, 1.03); 643 | transform: scale3d(1.03, 1.03, 1.03); 644 | } 645 | 646 | 80% { 647 | -webkit-transform: scale3d(.97, .97, .97); 648 | transform: scale3d(.97, .97, .97); 649 | } 650 | 651 | to { 652 | opacity: 1; 653 | -webkit-transform: scale3d(1, 1, 1); 654 | transform: scale3d(1, 1, 1); 655 | } 656 | } 657 | 658 | .bounceIn { 659 | -webkit-animation-name: bounceIn; 660 | animation-name: bounceIn; 661 | } 662 | 663 | @-webkit-keyframes bounceInDown { 664 | from, 60%, 75%, 90%, to { 665 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 666 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 667 | } 668 | 669 | 0% { 670 | opacity: 0; 671 | -webkit-transform: translate3d(0, -3000px, 0); 672 | transform: translate3d(0, -3000px, 0); 673 | } 674 | 675 | 60% { 676 | opacity: 1; 677 | -webkit-transform: translate3d(0, 25px, 0); 678 | transform: translate3d(0, 25px, 0); 679 | } 680 | 681 | 75% { 682 | -webkit-transform: translate3d(0, -10px, 0); 683 | transform: translate3d(0, -10px, 0); 684 | } 685 | 686 | 90% { 687 | -webkit-transform: translate3d(0, 5px, 0); 688 | transform: translate3d(0, 5px, 0); 689 | } 690 | 691 | to { 692 | -webkit-transform: none; 693 | transform: none; 694 | } 695 | } 696 | 697 | @keyframes bounceInDown { 698 | from, 60%, 75%, 90%, to { 699 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 700 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 701 | } 702 | 703 | 0% { 704 | opacity: 0; 705 | -webkit-transform: translate3d(0, -3000px, 0); 706 | transform: translate3d(0, -3000px, 0); 707 | } 708 | 709 | 60% { 710 | opacity: 1; 711 | -webkit-transform: translate3d(0, 25px, 0); 712 | transform: translate3d(0, 25px, 0); 713 | } 714 | 715 | 75% { 716 | -webkit-transform: translate3d(0, -10px, 0); 717 | transform: translate3d(0, -10px, 0); 718 | } 719 | 720 | 90% { 721 | -webkit-transform: translate3d(0, 5px, 0); 722 | transform: translate3d(0, 5px, 0); 723 | } 724 | 725 | to { 726 | -webkit-transform: none; 727 | transform: none; 728 | } 729 | } 730 | 731 | .bounceInDown { 732 | -webkit-animation-name: bounceInDown; 733 | animation-name: bounceInDown; 734 | } 735 | 736 | @-webkit-keyframes bounceInLeft { 737 | from, 60%, 75%, 90%, to { 738 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 739 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 740 | } 741 | 742 | 0% { 743 | opacity: 0; 744 | -webkit-transform: translate3d(-3000px, 0, 0); 745 | transform: translate3d(-3000px, 0, 0); 746 | } 747 | 748 | 60% { 749 | opacity: 1; 750 | -webkit-transform: translate3d(25px, 0, 0); 751 | transform: translate3d(25px, 0, 0); 752 | } 753 | 754 | 75% { 755 | -webkit-transform: translate3d(-10px, 0, 0); 756 | transform: translate3d(-10px, 0, 0); 757 | } 758 | 759 | 90% { 760 | -webkit-transform: translate3d(5px, 0, 0); 761 | transform: translate3d(5px, 0, 0); 762 | } 763 | 764 | to { 765 | -webkit-transform: none; 766 | transform: none; 767 | } 768 | } 769 | 770 | @keyframes bounceInLeft { 771 | from, 60%, 75%, 90%, to { 772 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 773 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 774 | } 775 | 776 | 0% { 777 | opacity: 0; 778 | -webkit-transform: translate3d(-3000px, 0, 0); 779 | transform: translate3d(-3000px, 0, 0); 780 | } 781 | 782 | 60% { 783 | opacity: 1; 784 | -webkit-transform: translate3d(25px, 0, 0); 785 | transform: translate3d(25px, 0, 0); 786 | } 787 | 788 | 75% { 789 | -webkit-transform: translate3d(-10px, 0, 0); 790 | transform: translate3d(-10px, 0, 0); 791 | } 792 | 793 | 90% { 794 | -webkit-transform: translate3d(5px, 0, 0); 795 | transform: translate3d(5px, 0, 0); 796 | } 797 | 798 | to { 799 | -webkit-transform: none; 800 | transform: none; 801 | } 802 | } 803 | 804 | .bounceInLeft { 805 | -webkit-animation-name: bounceInLeft; 806 | animation-name: bounceInLeft; 807 | } 808 | 809 | @-webkit-keyframes bounceInRight { 810 | from, 60%, 75%, 90%, to { 811 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 812 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 813 | } 814 | 815 | from { 816 | opacity: 0; 817 | -webkit-transform: translate3d(3000px, 0, 0); 818 | transform: translate3d(3000px, 0, 0); 819 | } 820 | 821 | 60% { 822 | opacity: 1; 823 | -webkit-transform: translate3d(-25px, 0, 0); 824 | transform: translate3d(-25px, 0, 0); 825 | } 826 | 827 | 75% { 828 | -webkit-transform: translate3d(10px, 0, 0); 829 | transform: translate3d(10px, 0, 0); 830 | } 831 | 832 | 90% { 833 | -webkit-transform: translate3d(-5px, 0, 0); 834 | transform: translate3d(-5px, 0, 0); 835 | } 836 | 837 | to { 838 | -webkit-transform: none; 839 | transform: none; 840 | } 841 | } 842 | 843 | @keyframes bounceInRight { 844 | from, 60%, 75%, 90%, to { 845 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 846 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 847 | } 848 | 849 | from { 850 | opacity: 0; 851 | -webkit-transform: translate3d(3000px, 0, 0); 852 | transform: translate3d(3000px, 0, 0); 853 | } 854 | 855 | 60% { 856 | opacity: 1; 857 | -webkit-transform: translate3d(-25px, 0, 0); 858 | transform: translate3d(-25px, 0, 0); 859 | } 860 | 861 | 75% { 862 | -webkit-transform: translate3d(10px, 0, 0); 863 | transform: translate3d(10px, 0, 0); 864 | } 865 | 866 | 90% { 867 | -webkit-transform: translate3d(-5px, 0, 0); 868 | transform: translate3d(-5px, 0, 0); 869 | } 870 | 871 | to { 872 | -webkit-transform: none; 873 | transform: none; 874 | } 875 | } 876 | 877 | .bounceInRight { 878 | -webkit-animation-name: bounceInRight; 879 | animation-name: bounceInRight; 880 | } 881 | 882 | @-webkit-keyframes bounceInUp { 883 | from, 60%, 75%, 90%, to { 884 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 885 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 886 | } 887 | 888 | from { 889 | opacity: 0; 890 | -webkit-transform: translate3d(0, 3000px, 0); 891 | transform: translate3d(0, 3000px, 0); 892 | } 893 | 894 | 60% { 895 | opacity: 1; 896 | -webkit-transform: translate3d(0, -20px, 0); 897 | transform: translate3d(0, -20px, 0); 898 | } 899 | 900 | 75% { 901 | -webkit-transform: translate3d(0, 10px, 0); 902 | transform: translate3d(0, 10px, 0); 903 | } 904 | 905 | 90% { 906 | -webkit-transform: translate3d(0, -5px, 0); 907 | transform: translate3d(0, -5px, 0); 908 | } 909 | 910 | to { 911 | -webkit-transform: translate3d(0, 0, 0); 912 | transform: translate3d(0, 0, 0); 913 | } 914 | } 915 | 916 | @keyframes bounceInUp { 917 | from, 60%, 75%, 90%, to { 918 | -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 919 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 920 | } 921 | 922 | from { 923 | opacity: 0; 924 | -webkit-transform: translate3d(0, 3000px, 0); 925 | transform: translate3d(0, 3000px, 0); 926 | } 927 | 928 | 60% { 929 | opacity: 1; 930 | -webkit-transform: translate3d(0, -20px, 0); 931 | transform: translate3d(0, -20px, 0); 932 | } 933 | 934 | 75% { 935 | -webkit-transform: translate3d(0, 10px, 0); 936 | transform: translate3d(0, 10px, 0); 937 | } 938 | 939 | 90% { 940 | -webkit-transform: translate3d(0, -5px, 0); 941 | transform: translate3d(0, -5px, 0); 942 | } 943 | 944 | to { 945 | -webkit-transform: translate3d(0, 0, 0); 946 | transform: translate3d(0, 0, 0); 947 | } 948 | } 949 | 950 | .bounceInUp { 951 | -webkit-animation-name: bounceInUp; 952 | animation-name: bounceInUp; 953 | } 954 | 955 | @-webkit-keyframes bounceOut { 956 | 20% { 957 | -webkit-transform: scale3d(.9, .9, .9); 958 | transform: scale3d(.9, .9, .9); 959 | } 960 | 961 | 50%, 55% { 962 | opacity: 1; 963 | -webkit-transform: scale3d(1.1, 1.1, 1.1); 964 | transform: scale3d(1.1, 1.1, 1.1); 965 | } 966 | 967 | to { 968 | opacity: 0; 969 | -webkit-transform: scale3d(.3, .3, .3); 970 | transform: scale3d(.3, .3, .3); 971 | } 972 | } 973 | 974 | @keyframes bounceOut { 975 | 20% { 976 | -webkit-transform: scale3d(.9, .9, .9); 977 | transform: scale3d(.9, .9, .9); 978 | } 979 | 980 | 50%, 55% { 981 | opacity: 1; 982 | -webkit-transform: scale3d(1.1, 1.1, 1.1); 983 | transform: scale3d(1.1, 1.1, 1.1); 984 | } 985 | 986 | to { 987 | opacity: 0; 988 | -webkit-transform: scale3d(.3, .3, .3); 989 | transform: scale3d(.3, .3, .3); 990 | } 991 | } 992 | 993 | .bounceOut { 994 | -webkit-animation-name: bounceOut; 995 | animation-name: bounceOut; 996 | } 997 | 998 | @-webkit-keyframes bounceOutDown { 999 | 20% { 1000 | -webkit-transform: translate3d(0, 10px, 0); 1001 | transform: translate3d(0, 10px, 0); 1002 | } 1003 | 1004 | 40%, 45% { 1005 | opacity: 1; 1006 | -webkit-transform: translate3d(0, -20px, 0); 1007 | transform: translate3d(0, -20px, 0); 1008 | } 1009 | 1010 | to { 1011 | opacity: 0; 1012 | -webkit-transform: translate3d(0, 2000px, 0); 1013 | transform: translate3d(0, 2000px, 0); 1014 | } 1015 | } 1016 | 1017 | @keyframes bounceOutDown { 1018 | 20% { 1019 | -webkit-transform: translate3d(0, 10px, 0); 1020 | transform: translate3d(0, 10px, 0); 1021 | } 1022 | 1023 | 40%, 45% { 1024 | opacity: 1; 1025 | -webkit-transform: translate3d(0, -20px, 0); 1026 | transform: translate3d(0, -20px, 0); 1027 | } 1028 | 1029 | to { 1030 | opacity: 0; 1031 | -webkit-transform: translate3d(0, 2000px, 0); 1032 | transform: translate3d(0, 2000px, 0); 1033 | } 1034 | } 1035 | 1036 | .bounceOutDown { 1037 | -webkit-animation-name: bounceOutDown; 1038 | animation-name: bounceOutDown; 1039 | } 1040 | 1041 | @-webkit-keyframes bounceOutLeft { 1042 | 20% { 1043 | opacity: 1; 1044 | -webkit-transform: translate3d(20px, 0, 0); 1045 | transform: translate3d(20px, 0, 0); 1046 | } 1047 | 1048 | to { 1049 | opacity: 0; 1050 | -webkit-transform: translate3d(-2000px, 0, 0); 1051 | transform: translate3d(-2000px, 0, 0); 1052 | } 1053 | } 1054 | 1055 | @keyframes bounceOutLeft { 1056 | 20% { 1057 | opacity: 1; 1058 | -webkit-transform: translate3d(20px, 0, 0); 1059 | transform: translate3d(20px, 0, 0); 1060 | } 1061 | 1062 | to { 1063 | opacity: 0; 1064 | -webkit-transform: translate3d(-2000px, 0, 0); 1065 | transform: translate3d(-2000px, 0, 0); 1066 | } 1067 | } 1068 | 1069 | .bounceOutLeft { 1070 | -webkit-animation-name: bounceOutLeft; 1071 | animation-name: bounceOutLeft; 1072 | } 1073 | 1074 | @-webkit-keyframes bounceOutRight { 1075 | 20% { 1076 | opacity: 1; 1077 | -webkit-transform: translate3d(-20px, 0, 0); 1078 | transform: translate3d(-20px, 0, 0); 1079 | } 1080 | 1081 | to { 1082 | opacity: 0; 1083 | -webkit-transform: translate3d(2000px, 0, 0); 1084 | transform: translate3d(2000px, 0, 0); 1085 | } 1086 | } 1087 | 1088 | @keyframes bounceOutRight { 1089 | 20% { 1090 | opacity: 1; 1091 | -webkit-transform: translate3d(-20px, 0, 0); 1092 | transform: translate3d(-20px, 0, 0); 1093 | } 1094 | 1095 | to { 1096 | opacity: 0; 1097 | -webkit-transform: translate3d(2000px, 0, 0); 1098 | transform: translate3d(2000px, 0, 0); 1099 | } 1100 | } 1101 | 1102 | .bounceOutRight { 1103 | -webkit-animation-name: bounceOutRight; 1104 | animation-name: bounceOutRight; 1105 | } 1106 | 1107 | @-webkit-keyframes bounceOutUp { 1108 | 20% { 1109 | -webkit-transform: translate3d(0, -10px, 0); 1110 | transform: translate3d(0, -10px, 0); 1111 | } 1112 | 1113 | 40%, 45% { 1114 | opacity: 1; 1115 | -webkit-transform: translate3d(0, 20px, 0); 1116 | transform: translate3d(0, 20px, 0); 1117 | } 1118 | 1119 | to { 1120 | opacity: 0; 1121 | -webkit-transform: translate3d(0, -2000px, 0); 1122 | transform: translate3d(0, -2000px, 0); 1123 | } 1124 | } 1125 | 1126 | @keyframes bounceOutUp { 1127 | 20% { 1128 | -webkit-transform: translate3d(0, -10px, 0); 1129 | transform: translate3d(0, -10px, 0); 1130 | } 1131 | 1132 | 40%, 45% { 1133 | opacity: 1; 1134 | -webkit-transform: translate3d(0, 20px, 0); 1135 | transform: translate3d(0, 20px, 0); 1136 | } 1137 | 1138 | to { 1139 | opacity: 0; 1140 | -webkit-transform: translate3d(0, -2000px, 0); 1141 | transform: translate3d(0, -2000px, 0); 1142 | } 1143 | } 1144 | 1145 | .bounceOutUp { 1146 | -webkit-animation-name: bounceOutUp; 1147 | animation-name: bounceOutUp; 1148 | } 1149 | 1150 | @-webkit-keyframes fadeIn { 1151 | from { 1152 | opacity: 0; 1153 | } 1154 | 1155 | to { 1156 | opacity: 1; 1157 | } 1158 | } 1159 | 1160 | @keyframes fadeIn { 1161 | from { 1162 | opacity: 0; 1163 | } 1164 | 1165 | to { 1166 | opacity: 1; 1167 | } 1168 | } 1169 | 1170 | .fadeIn { 1171 | -webkit-animation-name: fadeIn; 1172 | animation-name: fadeIn; 1173 | } 1174 | 1175 | @-webkit-keyframes fadeInDown { 1176 | from { 1177 | opacity: 0; 1178 | -webkit-transform: translate3d(0, -100%, 0); 1179 | transform: translate3d(0, -100%, 0); 1180 | } 1181 | 1182 | to { 1183 | opacity: 1; 1184 | -webkit-transform: none; 1185 | transform: none; 1186 | } 1187 | } 1188 | 1189 | @keyframes fadeInDown { 1190 | from { 1191 | opacity: 0; 1192 | -webkit-transform: translate3d(0, -100%, 0); 1193 | transform: translate3d(0, -100%, 0); 1194 | } 1195 | 1196 | to { 1197 | opacity: 1; 1198 | -webkit-transform: none; 1199 | transform: none; 1200 | } 1201 | } 1202 | 1203 | .fadeInDown { 1204 | -webkit-animation-name: fadeInDown; 1205 | animation-name: fadeInDown; 1206 | } 1207 | 1208 | @-webkit-keyframes fadeInDownBig { 1209 | from { 1210 | opacity: 0; 1211 | -webkit-transform: translate3d(0, -2000px, 0); 1212 | transform: translate3d(0, -2000px, 0); 1213 | } 1214 | 1215 | to { 1216 | opacity: 1; 1217 | -webkit-transform: none; 1218 | transform: none; 1219 | } 1220 | } 1221 | 1222 | @keyframes fadeInDownBig { 1223 | from { 1224 | opacity: 0; 1225 | -webkit-transform: translate3d(0, -2000px, 0); 1226 | transform: translate3d(0, -2000px, 0); 1227 | } 1228 | 1229 | to { 1230 | opacity: 1; 1231 | -webkit-transform: none; 1232 | transform: none; 1233 | } 1234 | } 1235 | 1236 | .fadeInDownBig { 1237 | -webkit-animation-name: fadeInDownBig; 1238 | animation-name: fadeInDownBig; 1239 | } 1240 | 1241 | @-webkit-keyframes fadeInLeft { 1242 | from { 1243 | opacity: 0; 1244 | -webkit-transform: translate3d(-100%, 0, 0); 1245 | transform: translate3d(-100%, 0, 0); 1246 | } 1247 | 1248 | to { 1249 | opacity: 1; 1250 | -webkit-transform: none; 1251 | transform: none; 1252 | } 1253 | } 1254 | 1255 | @keyframes fadeInLeft { 1256 | from { 1257 | opacity: 0; 1258 | -webkit-transform: translate3d(-100%, 0, 0); 1259 | transform: translate3d(-100%, 0, 0); 1260 | } 1261 | 1262 | to { 1263 | opacity: 1; 1264 | -webkit-transform: none; 1265 | transform: none; 1266 | } 1267 | } 1268 | 1269 | .fadeInLeft { 1270 | -webkit-animation-name: fadeInLeft; 1271 | animation-name: fadeInLeft; 1272 | } 1273 | 1274 | @-webkit-keyframes fadeInLeftBig { 1275 | from { 1276 | opacity: 0; 1277 | -webkit-transform: translate3d(-2000px, 0, 0); 1278 | transform: translate3d(-2000px, 0, 0); 1279 | } 1280 | 1281 | to { 1282 | opacity: 1; 1283 | -webkit-transform: none; 1284 | transform: none; 1285 | } 1286 | } 1287 | 1288 | @keyframes fadeInLeftBig { 1289 | from { 1290 | opacity: 0; 1291 | -webkit-transform: translate3d(-2000px, 0, 0); 1292 | transform: translate3d(-2000px, 0, 0); 1293 | } 1294 | 1295 | to { 1296 | opacity: 1; 1297 | -webkit-transform: none; 1298 | transform: none; 1299 | } 1300 | } 1301 | 1302 | .fadeInLeftBig { 1303 | -webkit-animation-name: fadeInLeftBig; 1304 | animation-name: fadeInLeftBig; 1305 | } 1306 | 1307 | @-webkit-keyframes fadeInRight { 1308 | from { 1309 | opacity: 0; 1310 | -webkit-transform: translate3d(100%, 0, 0); 1311 | transform: translate3d(100%, 0, 0); 1312 | } 1313 | 1314 | to { 1315 | opacity: 1; 1316 | -webkit-transform: none; 1317 | transform: none; 1318 | } 1319 | } 1320 | 1321 | @keyframes fadeInRight { 1322 | from { 1323 | opacity: 0; 1324 | -webkit-transform: translate3d(100%, 0, 0); 1325 | transform: translate3d(100%, 0, 0); 1326 | } 1327 | 1328 | to { 1329 | opacity: 1; 1330 | -webkit-transform: none; 1331 | transform: none; 1332 | } 1333 | } 1334 | 1335 | .fadeInRight { 1336 | -webkit-animation-name: fadeInRight; 1337 | animation-name: fadeInRight; 1338 | } 1339 | 1340 | @-webkit-keyframes fadeInRightBig { 1341 | from { 1342 | opacity: 0; 1343 | -webkit-transform: translate3d(2000px, 0, 0); 1344 | transform: translate3d(2000px, 0, 0); 1345 | } 1346 | 1347 | to { 1348 | opacity: 1; 1349 | -webkit-transform: none; 1350 | transform: none; 1351 | } 1352 | } 1353 | 1354 | @keyframes fadeInRightBig { 1355 | from { 1356 | opacity: 0; 1357 | -webkit-transform: translate3d(2000px, 0, 0); 1358 | transform: translate3d(2000px, 0, 0); 1359 | } 1360 | 1361 | to { 1362 | opacity: 1; 1363 | -webkit-transform: none; 1364 | transform: none; 1365 | } 1366 | } 1367 | 1368 | .fadeInRightBig { 1369 | -webkit-animation-name: fadeInRightBig; 1370 | animation-name: fadeInRightBig; 1371 | } 1372 | 1373 | @-webkit-keyframes fadeInUp { 1374 | from { 1375 | opacity: 0; 1376 | -webkit-transform: translate3d(0, 100%, 0); 1377 | transform: translate3d(0, 100%, 0); 1378 | } 1379 | 1380 | to { 1381 | opacity: 1; 1382 | -webkit-transform: none; 1383 | transform: none; 1384 | } 1385 | } 1386 | 1387 | @keyframes fadeInUp { 1388 | from { 1389 | opacity: 0; 1390 | -webkit-transform: translate3d(0, 100%, 0); 1391 | transform: translate3d(0, 100%, 0); 1392 | } 1393 | 1394 | to { 1395 | opacity: 1; 1396 | -webkit-transform: none; 1397 | transform: none; 1398 | } 1399 | } 1400 | 1401 | .fadeInUp { 1402 | -webkit-animation-name: fadeInUp; 1403 | animation-name: fadeInUp; 1404 | } 1405 | 1406 | @-webkit-keyframes fadeInUpBig { 1407 | from { 1408 | opacity: 0; 1409 | -webkit-transform: translate3d(0, 2000px, 0); 1410 | transform: translate3d(0, 2000px, 0); 1411 | } 1412 | 1413 | to { 1414 | opacity: 1; 1415 | -webkit-transform: none; 1416 | transform: none; 1417 | } 1418 | } 1419 | 1420 | @keyframes fadeInUpBig { 1421 | from { 1422 | opacity: 0; 1423 | -webkit-transform: translate3d(0, 2000px, 0); 1424 | transform: translate3d(0, 2000px, 0); 1425 | } 1426 | 1427 | to { 1428 | opacity: 1; 1429 | -webkit-transform: none; 1430 | transform: none; 1431 | } 1432 | } 1433 | 1434 | .fadeInUpBig { 1435 | -webkit-animation-name: fadeInUpBig; 1436 | animation-name: fadeInUpBig; 1437 | } 1438 | 1439 | @-webkit-keyframes fadeOut { 1440 | from { 1441 | opacity: 1; 1442 | } 1443 | 1444 | to { 1445 | opacity: 0; 1446 | } 1447 | } 1448 | 1449 | @keyframes fadeOut { 1450 | from { 1451 | opacity: 1; 1452 | } 1453 | 1454 | to { 1455 | opacity: 0; 1456 | } 1457 | } 1458 | 1459 | .fadeOut { 1460 | -webkit-animation-name: fadeOut; 1461 | animation-name: fadeOut; 1462 | } 1463 | 1464 | @-webkit-keyframes fadeOutDown { 1465 | from { 1466 | opacity: 1; 1467 | } 1468 | 1469 | to { 1470 | opacity: 0; 1471 | -webkit-transform: translate3d(0, 100%, 0); 1472 | transform: translate3d(0, 100%, 0); 1473 | } 1474 | } 1475 | 1476 | @keyframes fadeOutDown { 1477 | from { 1478 | opacity: 1; 1479 | } 1480 | 1481 | to { 1482 | opacity: 0; 1483 | -webkit-transform: translate3d(0, 100%, 0); 1484 | transform: translate3d(0, 100%, 0); 1485 | } 1486 | } 1487 | 1488 | .fadeOutDown { 1489 | -webkit-animation-name: fadeOutDown; 1490 | animation-name: fadeOutDown; 1491 | } 1492 | 1493 | @-webkit-keyframes fadeOutDownBig { 1494 | from { 1495 | opacity: 1; 1496 | } 1497 | 1498 | to { 1499 | opacity: 0; 1500 | -webkit-transform: translate3d(0, 2000px, 0); 1501 | transform: translate3d(0, 2000px, 0); 1502 | } 1503 | } 1504 | 1505 | @keyframes fadeOutDownBig { 1506 | from { 1507 | opacity: 1; 1508 | } 1509 | 1510 | to { 1511 | opacity: 0; 1512 | -webkit-transform: translate3d(0, 2000px, 0); 1513 | transform: translate3d(0, 2000px, 0); 1514 | } 1515 | } 1516 | 1517 | .fadeOutDownBig { 1518 | -webkit-animation-name: fadeOutDownBig; 1519 | animation-name: fadeOutDownBig; 1520 | } 1521 | 1522 | @-webkit-keyframes fadeOutLeft { 1523 | from { 1524 | opacity: 1; 1525 | } 1526 | 1527 | to { 1528 | opacity: 0; 1529 | -webkit-transform: translate3d(-100%, 0, 0); 1530 | transform: translate3d(-100%, 0, 0); 1531 | } 1532 | } 1533 | 1534 | @keyframes fadeOutLeft { 1535 | from { 1536 | opacity: 1; 1537 | } 1538 | 1539 | to { 1540 | opacity: 0; 1541 | -webkit-transform: translate3d(-100%, 0, 0); 1542 | transform: translate3d(-100%, 0, 0); 1543 | } 1544 | } 1545 | 1546 | .fadeOutLeft { 1547 | -webkit-animation-name: fadeOutLeft; 1548 | animation-name: fadeOutLeft; 1549 | } 1550 | 1551 | @-webkit-keyframes fadeOutLeftBig { 1552 | from { 1553 | opacity: 1; 1554 | } 1555 | 1556 | to { 1557 | opacity: 0; 1558 | -webkit-transform: translate3d(-2000px, 0, 0); 1559 | transform: translate3d(-2000px, 0, 0); 1560 | } 1561 | } 1562 | 1563 | @keyframes fadeOutLeftBig { 1564 | from { 1565 | opacity: 1; 1566 | } 1567 | 1568 | to { 1569 | opacity: 0; 1570 | -webkit-transform: translate3d(-2000px, 0, 0); 1571 | transform: translate3d(-2000px, 0, 0); 1572 | } 1573 | } 1574 | 1575 | .fadeOutLeftBig { 1576 | -webkit-animation-name: fadeOutLeftBig; 1577 | animation-name: fadeOutLeftBig; 1578 | } 1579 | 1580 | @-webkit-keyframes fadeOutRight { 1581 | from { 1582 | opacity: 1; 1583 | } 1584 | 1585 | to { 1586 | opacity: 0; 1587 | -webkit-transform: translate3d(100%, 0, 0); 1588 | transform: translate3d(100%, 0, 0); 1589 | } 1590 | } 1591 | 1592 | @keyframes fadeOutRight { 1593 | from { 1594 | opacity: 1; 1595 | } 1596 | 1597 | to { 1598 | opacity: 0; 1599 | -webkit-transform: translate3d(100%, 0, 0); 1600 | transform: translate3d(100%, 0, 0); 1601 | } 1602 | } 1603 | 1604 | .fadeOutRight { 1605 | -webkit-animation-name: fadeOutRight; 1606 | animation-name: fadeOutRight; 1607 | } 1608 | 1609 | @-webkit-keyframes fadeOutRightBig { 1610 | from { 1611 | opacity: 1; 1612 | } 1613 | 1614 | to { 1615 | opacity: 0; 1616 | -webkit-transform: translate3d(2000px, 0, 0); 1617 | transform: translate3d(2000px, 0, 0); 1618 | } 1619 | } 1620 | 1621 | @keyframes fadeOutRightBig { 1622 | from { 1623 | opacity: 1; 1624 | } 1625 | 1626 | to { 1627 | opacity: 0; 1628 | -webkit-transform: translate3d(2000px, 0, 0); 1629 | transform: translate3d(2000px, 0, 0); 1630 | } 1631 | } 1632 | 1633 | .fadeOutRightBig { 1634 | -webkit-animation-name: fadeOutRightBig; 1635 | animation-name: fadeOutRightBig; 1636 | } 1637 | 1638 | @-webkit-keyframes fadeOutUp { 1639 | from { 1640 | opacity: 1; 1641 | } 1642 | 1643 | to { 1644 | opacity: 0; 1645 | -webkit-transform: translate3d(0, -100%, 0); 1646 | transform: translate3d(0, -100%, 0); 1647 | } 1648 | } 1649 | 1650 | @keyframes fadeOutUp { 1651 | from { 1652 | opacity: 1; 1653 | } 1654 | 1655 | to { 1656 | opacity: 0; 1657 | -webkit-transform: translate3d(0, -100%, 0); 1658 | transform: translate3d(0, -100%, 0); 1659 | } 1660 | } 1661 | 1662 | .fadeOutUp { 1663 | -webkit-animation-name: fadeOutUp; 1664 | animation-name: fadeOutUp; 1665 | } 1666 | 1667 | @-webkit-keyframes fadeOutUpBig { 1668 | from { 1669 | opacity: 1; 1670 | } 1671 | 1672 | to { 1673 | opacity: 0; 1674 | -webkit-transform: translate3d(0, -2000px, 0); 1675 | transform: translate3d(0, -2000px, 0); 1676 | } 1677 | } 1678 | 1679 | @keyframes fadeOutUpBig { 1680 | from { 1681 | opacity: 1; 1682 | } 1683 | 1684 | to { 1685 | opacity: 0; 1686 | -webkit-transform: translate3d(0, -2000px, 0); 1687 | transform: translate3d(0, -2000px, 0); 1688 | } 1689 | } 1690 | 1691 | .fadeOutUpBig { 1692 | -webkit-animation-name: fadeOutUpBig; 1693 | animation-name: fadeOutUpBig; 1694 | } 1695 | 1696 | @-webkit-keyframes flip { 1697 | from { 1698 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); 1699 | transform: perspective(400px) rotate3d(0, 1, 0, -360deg); 1700 | -webkit-animation-timing-function: ease-out; 1701 | animation-timing-function: ease-out; 1702 | } 1703 | 1704 | 40% { 1705 | -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); 1706 | transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); 1707 | -webkit-animation-timing-function: ease-out; 1708 | animation-timing-function: ease-out; 1709 | } 1710 | 1711 | 50% { 1712 | -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); 1713 | transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); 1714 | -webkit-animation-timing-function: ease-in; 1715 | animation-timing-function: ease-in; 1716 | } 1717 | 1718 | 80% { 1719 | -webkit-transform: perspective(400px) scale3d(.95, .95, .95); 1720 | transform: perspective(400px) scale3d(.95, .95, .95); 1721 | -webkit-animation-timing-function: ease-in; 1722 | animation-timing-function: ease-in; 1723 | } 1724 | 1725 | to { 1726 | -webkit-transform: perspective(400px); 1727 | transform: perspective(400px); 1728 | -webkit-animation-timing-function: ease-in; 1729 | animation-timing-function: ease-in; 1730 | } 1731 | } 1732 | 1733 | @keyframes flip { 1734 | from { 1735 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); 1736 | transform: perspective(400px) rotate3d(0, 1, 0, -360deg); 1737 | -webkit-animation-timing-function: ease-out; 1738 | animation-timing-function: ease-out; 1739 | } 1740 | 1741 | 40% { 1742 | -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); 1743 | transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); 1744 | -webkit-animation-timing-function: ease-out; 1745 | animation-timing-function: ease-out; 1746 | } 1747 | 1748 | 50% { 1749 | -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); 1750 | transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); 1751 | -webkit-animation-timing-function: ease-in; 1752 | animation-timing-function: ease-in; 1753 | } 1754 | 1755 | 80% { 1756 | -webkit-transform: perspective(400px) scale3d(.95, .95, .95); 1757 | transform: perspective(400px) scale3d(.95, .95, .95); 1758 | -webkit-animation-timing-function: ease-in; 1759 | animation-timing-function: ease-in; 1760 | } 1761 | 1762 | to { 1763 | -webkit-transform: perspective(400px); 1764 | transform: perspective(400px); 1765 | -webkit-animation-timing-function: ease-in; 1766 | animation-timing-function: ease-in; 1767 | } 1768 | } 1769 | 1770 | .animated.flip { 1771 | -webkit-backface-visibility: visible; 1772 | backface-visibility: visible; 1773 | -webkit-animation-name: flip; 1774 | animation-name: flip; 1775 | } 1776 | 1777 | @-webkit-keyframes flipInX { 1778 | from { 1779 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 1780 | transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 1781 | -webkit-animation-timing-function: ease-in; 1782 | animation-timing-function: ease-in; 1783 | opacity: 0; 1784 | } 1785 | 1786 | 40% { 1787 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 1788 | transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 1789 | -webkit-animation-timing-function: ease-in; 1790 | animation-timing-function: ease-in; 1791 | } 1792 | 1793 | 60% { 1794 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); 1795 | transform: perspective(400px) rotate3d(1, 0, 0, 10deg); 1796 | opacity: 1; 1797 | } 1798 | 1799 | 80% { 1800 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); 1801 | transform: perspective(400px) rotate3d(1, 0, 0, -5deg); 1802 | } 1803 | 1804 | to { 1805 | -webkit-transform: perspective(400px); 1806 | transform: perspective(400px); 1807 | } 1808 | } 1809 | 1810 | @keyframes flipInX { 1811 | from { 1812 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 1813 | transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 1814 | -webkit-animation-timing-function: ease-in; 1815 | animation-timing-function: ease-in; 1816 | opacity: 0; 1817 | } 1818 | 1819 | 40% { 1820 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 1821 | transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 1822 | -webkit-animation-timing-function: ease-in; 1823 | animation-timing-function: ease-in; 1824 | } 1825 | 1826 | 60% { 1827 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); 1828 | transform: perspective(400px) rotate3d(1, 0, 0, 10deg); 1829 | opacity: 1; 1830 | } 1831 | 1832 | 80% { 1833 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); 1834 | transform: perspective(400px) rotate3d(1, 0, 0, -5deg); 1835 | } 1836 | 1837 | to { 1838 | -webkit-transform: perspective(400px); 1839 | transform: perspective(400px); 1840 | } 1841 | } 1842 | 1843 | .flipInX { 1844 | -webkit-backface-visibility: visible !important; 1845 | backface-visibility: visible !important; 1846 | -webkit-animation-name: flipInX; 1847 | animation-name: flipInX; 1848 | } 1849 | 1850 | @-webkit-keyframes flipInY { 1851 | from { 1852 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 1853 | transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 1854 | -webkit-animation-timing-function: ease-in; 1855 | animation-timing-function: ease-in; 1856 | opacity: 0; 1857 | } 1858 | 1859 | 40% { 1860 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); 1861 | transform: perspective(400px) rotate3d(0, 1, 0, -20deg); 1862 | -webkit-animation-timing-function: ease-in; 1863 | animation-timing-function: ease-in; 1864 | } 1865 | 1866 | 60% { 1867 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); 1868 | transform: perspective(400px) rotate3d(0, 1, 0, 10deg); 1869 | opacity: 1; 1870 | } 1871 | 1872 | 80% { 1873 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); 1874 | transform: perspective(400px) rotate3d(0, 1, 0, -5deg); 1875 | } 1876 | 1877 | to { 1878 | -webkit-transform: perspective(400px); 1879 | transform: perspective(400px); 1880 | } 1881 | } 1882 | 1883 | @keyframes flipInY { 1884 | from { 1885 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 1886 | transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 1887 | -webkit-animation-timing-function: ease-in; 1888 | animation-timing-function: ease-in; 1889 | opacity: 0; 1890 | } 1891 | 1892 | 40% { 1893 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); 1894 | transform: perspective(400px) rotate3d(0, 1, 0, -20deg); 1895 | -webkit-animation-timing-function: ease-in; 1896 | animation-timing-function: ease-in; 1897 | } 1898 | 1899 | 60% { 1900 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); 1901 | transform: perspective(400px) rotate3d(0, 1, 0, 10deg); 1902 | opacity: 1; 1903 | } 1904 | 1905 | 80% { 1906 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); 1907 | transform: perspective(400px) rotate3d(0, 1, 0, -5deg); 1908 | } 1909 | 1910 | to { 1911 | -webkit-transform: perspective(400px); 1912 | transform: perspective(400px); 1913 | } 1914 | } 1915 | 1916 | .flipInY { 1917 | -webkit-backface-visibility: visible !important; 1918 | backface-visibility: visible !important; 1919 | -webkit-animation-name: flipInY; 1920 | animation-name: flipInY; 1921 | } 1922 | 1923 | @-webkit-keyframes flipOutX { 1924 | from { 1925 | -webkit-transform: perspective(400px); 1926 | transform: perspective(400px); 1927 | } 1928 | 1929 | 30% { 1930 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 1931 | transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 1932 | opacity: 1; 1933 | } 1934 | 1935 | to { 1936 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 1937 | transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 1938 | opacity: 0; 1939 | } 1940 | } 1941 | 1942 | @keyframes flipOutX { 1943 | from { 1944 | -webkit-transform: perspective(400px); 1945 | transform: perspective(400px); 1946 | } 1947 | 1948 | 30% { 1949 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 1950 | transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 1951 | opacity: 1; 1952 | } 1953 | 1954 | to { 1955 | -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 1956 | transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 1957 | opacity: 0; 1958 | } 1959 | } 1960 | 1961 | .flipOutX { 1962 | -webkit-animation-name: flipOutX; 1963 | animation-name: flipOutX; 1964 | -webkit-backface-visibility: visible !important; 1965 | backface-visibility: visible !important; 1966 | } 1967 | 1968 | @-webkit-keyframes flipOutY { 1969 | from { 1970 | -webkit-transform: perspective(400px); 1971 | transform: perspective(400px); 1972 | } 1973 | 1974 | 30% { 1975 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); 1976 | transform: perspective(400px) rotate3d(0, 1, 0, -15deg); 1977 | opacity: 1; 1978 | } 1979 | 1980 | to { 1981 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 1982 | transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 1983 | opacity: 0; 1984 | } 1985 | } 1986 | 1987 | @keyframes flipOutY { 1988 | from { 1989 | -webkit-transform: perspective(400px); 1990 | transform: perspective(400px); 1991 | } 1992 | 1993 | 30% { 1994 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); 1995 | transform: perspective(400px) rotate3d(0, 1, 0, -15deg); 1996 | opacity: 1; 1997 | } 1998 | 1999 | to { 2000 | -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 2001 | transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 2002 | opacity: 0; 2003 | } 2004 | } 2005 | 2006 | .flipOutY { 2007 | -webkit-backface-visibility: visible !important; 2008 | backface-visibility: visible !important; 2009 | -webkit-animation-name: flipOutY; 2010 | animation-name: flipOutY; 2011 | } 2012 | 2013 | @-webkit-keyframes lightSpeedIn { 2014 | from { 2015 | -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); 2016 | transform: translate3d(100%, 0, 0) skewX(-30deg); 2017 | opacity: 0; 2018 | } 2019 | 2020 | 60% { 2021 | -webkit-transform: skewX(20deg); 2022 | transform: skewX(20deg); 2023 | opacity: 1; 2024 | } 2025 | 2026 | 80% { 2027 | -webkit-transform: skewX(-5deg); 2028 | transform: skewX(-5deg); 2029 | opacity: 1; 2030 | } 2031 | 2032 | to { 2033 | -webkit-transform: none; 2034 | transform: none; 2035 | opacity: 1; 2036 | } 2037 | } 2038 | 2039 | @keyframes lightSpeedIn { 2040 | from { 2041 | -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); 2042 | transform: translate3d(100%, 0, 0) skewX(-30deg); 2043 | opacity: 0; 2044 | } 2045 | 2046 | 60% { 2047 | -webkit-transform: skewX(20deg); 2048 | transform: skewX(20deg); 2049 | opacity: 1; 2050 | } 2051 | 2052 | 80% { 2053 | -webkit-transform: skewX(-5deg); 2054 | transform: skewX(-5deg); 2055 | opacity: 1; 2056 | } 2057 | 2058 | to { 2059 | -webkit-transform: none; 2060 | transform: none; 2061 | opacity: 1; 2062 | } 2063 | } 2064 | 2065 | .lightSpeedIn { 2066 | -webkit-animation-name: lightSpeedIn; 2067 | animation-name: lightSpeedIn; 2068 | -webkit-animation-timing-function: ease-out; 2069 | animation-timing-function: ease-out; 2070 | } 2071 | 2072 | @-webkit-keyframes lightSpeedOut { 2073 | from { 2074 | opacity: 1; 2075 | } 2076 | 2077 | to { 2078 | -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); 2079 | transform: translate3d(100%, 0, 0) skewX(30deg); 2080 | opacity: 0; 2081 | } 2082 | } 2083 | 2084 | @keyframes lightSpeedOut { 2085 | from { 2086 | opacity: 1; 2087 | } 2088 | 2089 | to { 2090 | -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); 2091 | transform: translate3d(100%, 0, 0) skewX(30deg); 2092 | opacity: 0; 2093 | } 2094 | } 2095 | 2096 | .lightSpeedOut { 2097 | -webkit-animation-name: lightSpeedOut; 2098 | animation-name: lightSpeedOut; 2099 | -webkit-animation-timing-function: ease-in; 2100 | animation-timing-function: ease-in; 2101 | } 2102 | 2103 | @-webkit-keyframes rotateIn { 2104 | from { 2105 | -webkit-transform-origin: center; 2106 | transform-origin: center; 2107 | -webkit-transform: rotate3d(0, 0, 1, -200deg); 2108 | transform: rotate3d(0, 0, 1, -200deg); 2109 | opacity: 0; 2110 | } 2111 | 2112 | to { 2113 | -webkit-transform-origin: center; 2114 | transform-origin: center; 2115 | -webkit-transform: none; 2116 | transform: none; 2117 | opacity: 1; 2118 | } 2119 | } 2120 | 2121 | @keyframes rotateIn { 2122 | from { 2123 | -webkit-transform-origin: center; 2124 | transform-origin: center; 2125 | -webkit-transform: rotate3d(0, 0, 1, -200deg); 2126 | transform: rotate3d(0, 0, 1, -200deg); 2127 | opacity: 0; 2128 | } 2129 | 2130 | to { 2131 | -webkit-transform-origin: center; 2132 | transform-origin: center; 2133 | -webkit-transform: none; 2134 | transform: none; 2135 | opacity: 1; 2136 | } 2137 | } 2138 | 2139 | .rotateIn { 2140 | -webkit-animation-name: rotateIn; 2141 | animation-name: rotateIn; 2142 | } 2143 | 2144 | @-webkit-keyframes rotateInDownLeft { 2145 | from { 2146 | -webkit-transform-origin: left bottom; 2147 | transform-origin: left bottom; 2148 | -webkit-transform: rotate3d(0, 0, 1, -45deg); 2149 | transform: rotate3d(0, 0, 1, -45deg); 2150 | opacity: 0; 2151 | } 2152 | 2153 | to { 2154 | -webkit-transform-origin: left bottom; 2155 | transform-origin: left bottom; 2156 | -webkit-transform: none; 2157 | transform: none; 2158 | opacity: 1; 2159 | } 2160 | } 2161 | 2162 | @keyframes rotateInDownLeft { 2163 | from { 2164 | -webkit-transform-origin: left bottom; 2165 | transform-origin: left bottom; 2166 | -webkit-transform: rotate3d(0, 0, 1, -45deg); 2167 | transform: rotate3d(0, 0, 1, -45deg); 2168 | opacity: 0; 2169 | } 2170 | 2171 | to { 2172 | -webkit-transform-origin: left bottom; 2173 | transform-origin: left bottom; 2174 | -webkit-transform: none; 2175 | transform: none; 2176 | opacity: 1; 2177 | } 2178 | } 2179 | 2180 | .rotateInDownLeft { 2181 | -webkit-animation-name: rotateInDownLeft; 2182 | animation-name: rotateInDownLeft; 2183 | } 2184 | 2185 | @-webkit-keyframes rotateInDownRight { 2186 | from { 2187 | -webkit-transform-origin: right bottom; 2188 | transform-origin: right bottom; 2189 | -webkit-transform: rotate3d(0, 0, 1, 45deg); 2190 | transform: rotate3d(0, 0, 1, 45deg); 2191 | opacity: 0; 2192 | } 2193 | 2194 | to { 2195 | -webkit-transform-origin: right bottom; 2196 | transform-origin: right bottom; 2197 | -webkit-transform: none; 2198 | transform: none; 2199 | opacity: 1; 2200 | } 2201 | } 2202 | 2203 | @keyframes rotateInDownRight { 2204 | from { 2205 | -webkit-transform-origin: right bottom; 2206 | transform-origin: right bottom; 2207 | -webkit-transform: rotate3d(0, 0, 1, 45deg); 2208 | transform: rotate3d(0, 0, 1, 45deg); 2209 | opacity: 0; 2210 | } 2211 | 2212 | to { 2213 | -webkit-transform-origin: right bottom; 2214 | transform-origin: right bottom; 2215 | -webkit-transform: none; 2216 | transform: none; 2217 | opacity: 1; 2218 | } 2219 | } 2220 | 2221 | .rotateInDownRight { 2222 | -webkit-animation-name: rotateInDownRight; 2223 | animation-name: rotateInDownRight; 2224 | } 2225 | 2226 | @-webkit-keyframes rotateInUpLeft { 2227 | from { 2228 | -webkit-transform-origin: left bottom; 2229 | transform-origin: left bottom; 2230 | -webkit-transform: rotate3d(0, 0, 1, 45deg); 2231 | transform: rotate3d(0, 0, 1, 45deg); 2232 | opacity: 0; 2233 | } 2234 | 2235 | to { 2236 | -webkit-transform-origin: left bottom; 2237 | transform-origin: left bottom; 2238 | -webkit-transform: none; 2239 | transform: none; 2240 | opacity: 1; 2241 | } 2242 | } 2243 | 2244 | @keyframes rotateInUpLeft { 2245 | from { 2246 | -webkit-transform-origin: left bottom; 2247 | transform-origin: left bottom; 2248 | -webkit-transform: rotate3d(0, 0, 1, 45deg); 2249 | transform: rotate3d(0, 0, 1, 45deg); 2250 | opacity: 0; 2251 | } 2252 | 2253 | to { 2254 | -webkit-transform-origin: left bottom; 2255 | transform-origin: left bottom; 2256 | -webkit-transform: none; 2257 | transform: none; 2258 | opacity: 1; 2259 | } 2260 | } 2261 | 2262 | .rotateInUpLeft { 2263 | -webkit-animation-name: rotateInUpLeft; 2264 | animation-name: rotateInUpLeft; 2265 | } 2266 | 2267 | @-webkit-keyframes rotateInUpRight { 2268 | from { 2269 | -webkit-transform-origin: right bottom; 2270 | transform-origin: right bottom; 2271 | -webkit-transform: rotate3d(0, 0, 1, -90deg); 2272 | transform: rotate3d(0, 0, 1, -90deg); 2273 | opacity: 0; 2274 | } 2275 | 2276 | to { 2277 | -webkit-transform-origin: right bottom; 2278 | transform-origin: right bottom; 2279 | -webkit-transform: none; 2280 | transform: none; 2281 | opacity: 1; 2282 | } 2283 | } 2284 | 2285 | @keyframes rotateInUpRight { 2286 | from { 2287 | -webkit-transform-origin: right bottom; 2288 | transform-origin: right bottom; 2289 | -webkit-transform: rotate3d(0, 0, 1, -90deg); 2290 | transform: rotate3d(0, 0, 1, -90deg); 2291 | opacity: 0; 2292 | } 2293 | 2294 | to { 2295 | -webkit-transform-origin: right bottom; 2296 | transform-origin: right bottom; 2297 | -webkit-transform: none; 2298 | transform: none; 2299 | opacity: 1; 2300 | } 2301 | } 2302 | 2303 | .rotateInUpRight { 2304 | -webkit-animation-name: rotateInUpRight; 2305 | animation-name: rotateInUpRight; 2306 | } 2307 | 2308 | @-webkit-keyframes rotateOut { 2309 | from { 2310 | -webkit-transform-origin: center; 2311 | transform-origin: center; 2312 | opacity: 1; 2313 | } 2314 | 2315 | to { 2316 | -webkit-transform-origin: center; 2317 | transform-origin: center; 2318 | -webkit-transform: rotate3d(0, 0, 1, 200deg); 2319 | transform: rotate3d(0, 0, 1, 200deg); 2320 | opacity: 0; 2321 | } 2322 | } 2323 | 2324 | @keyframes rotateOut { 2325 | from { 2326 | -webkit-transform-origin: center; 2327 | transform-origin: center; 2328 | opacity: 1; 2329 | } 2330 | 2331 | to { 2332 | -webkit-transform-origin: center; 2333 | transform-origin: center; 2334 | -webkit-transform: rotate3d(0, 0, 1, 200deg); 2335 | transform: rotate3d(0, 0, 1, 200deg); 2336 | opacity: 0; 2337 | } 2338 | } 2339 | 2340 | .rotateOut { 2341 | -webkit-animation-name: rotateOut; 2342 | animation-name: rotateOut; 2343 | } 2344 | 2345 | @-webkit-keyframes rotateOutDownLeft { 2346 | from { 2347 | -webkit-transform-origin: left bottom; 2348 | transform-origin: left bottom; 2349 | opacity: 1; 2350 | } 2351 | 2352 | to { 2353 | -webkit-transform-origin: left bottom; 2354 | transform-origin: left bottom; 2355 | -webkit-transform: rotate3d(0, 0, 1, 45deg); 2356 | transform: rotate3d(0, 0, 1, 45deg); 2357 | opacity: 0; 2358 | } 2359 | } 2360 | 2361 | @keyframes rotateOutDownLeft { 2362 | from { 2363 | -webkit-transform-origin: left bottom; 2364 | transform-origin: left bottom; 2365 | opacity: 1; 2366 | } 2367 | 2368 | to { 2369 | -webkit-transform-origin: left bottom; 2370 | transform-origin: left bottom; 2371 | -webkit-transform: rotate3d(0, 0, 1, 45deg); 2372 | transform: rotate3d(0, 0, 1, 45deg); 2373 | opacity: 0; 2374 | } 2375 | } 2376 | 2377 | .rotateOutDownLeft { 2378 | -webkit-animation-name: rotateOutDownLeft; 2379 | animation-name: rotateOutDownLeft; 2380 | } 2381 | 2382 | @-webkit-keyframes rotateOutDownRight { 2383 | from { 2384 | -webkit-transform-origin: right bottom; 2385 | transform-origin: right bottom; 2386 | opacity: 1; 2387 | } 2388 | 2389 | to { 2390 | -webkit-transform-origin: right bottom; 2391 | transform-origin: right bottom; 2392 | -webkit-transform: rotate3d(0, 0, 1, -45deg); 2393 | transform: rotate3d(0, 0, 1, -45deg); 2394 | opacity: 0; 2395 | } 2396 | } 2397 | 2398 | @keyframes rotateOutDownRight { 2399 | from { 2400 | -webkit-transform-origin: right bottom; 2401 | transform-origin: right bottom; 2402 | opacity: 1; 2403 | } 2404 | 2405 | to { 2406 | -webkit-transform-origin: right bottom; 2407 | transform-origin: right bottom; 2408 | -webkit-transform: rotate3d(0, 0, 1, -45deg); 2409 | transform: rotate3d(0, 0, 1, -45deg); 2410 | opacity: 0; 2411 | } 2412 | } 2413 | 2414 | .rotateOutDownRight { 2415 | -webkit-animation-name: rotateOutDownRight; 2416 | animation-name: rotateOutDownRight; 2417 | } 2418 | 2419 | @-webkit-keyframes rotateOutUpLeft { 2420 | from { 2421 | -webkit-transform-origin: left bottom; 2422 | transform-origin: left bottom; 2423 | opacity: 1; 2424 | } 2425 | 2426 | to { 2427 | -webkit-transform-origin: left bottom; 2428 | transform-origin: left bottom; 2429 | -webkit-transform: rotate3d(0, 0, 1, -45deg); 2430 | transform: rotate3d(0, 0, 1, -45deg); 2431 | opacity: 0; 2432 | } 2433 | } 2434 | 2435 | @keyframes rotateOutUpLeft { 2436 | from { 2437 | -webkit-transform-origin: left bottom; 2438 | transform-origin: left bottom; 2439 | opacity: 1; 2440 | } 2441 | 2442 | to { 2443 | -webkit-transform-origin: left bottom; 2444 | transform-origin: left bottom; 2445 | -webkit-transform: rotate3d(0, 0, 1, -45deg); 2446 | transform: rotate3d(0, 0, 1, -45deg); 2447 | opacity: 0; 2448 | } 2449 | } 2450 | 2451 | .rotateOutUpLeft { 2452 | -webkit-animation-name: rotateOutUpLeft; 2453 | animation-name: rotateOutUpLeft; 2454 | } 2455 | 2456 | @-webkit-keyframes rotateOutUpRight { 2457 | from { 2458 | -webkit-transform-origin: right bottom; 2459 | transform-origin: right bottom; 2460 | opacity: 1; 2461 | } 2462 | 2463 | to { 2464 | -webkit-transform-origin: right bottom; 2465 | transform-origin: right bottom; 2466 | -webkit-transform: rotate3d(0, 0, 1, 90deg); 2467 | transform: rotate3d(0, 0, 1, 90deg); 2468 | opacity: 0; 2469 | } 2470 | } 2471 | 2472 | @keyframes rotateOutUpRight { 2473 | from { 2474 | -webkit-transform-origin: right bottom; 2475 | transform-origin: right bottom; 2476 | opacity: 1; 2477 | } 2478 | 2479 | to { 2480 | -webkit-transform-origin: right bottom; 2481 | transform-origin: right bottom; 2482 | -webkit-transform: rotate3d(0, 0, 1, 90deg); 2483 | transform: rotate3d(0, 0, 1, 90deg); 2484 | opacity: 0; 2485 | } 2486 | } 2487 | 2488 | .rotateOutUpRight { 2489 | -webkit-animation-name: rotateOutUpRight; 2490 | animation-name: rotateOutUpRight; 2491 | } 2492 | 2493 | @-webkit-keyframes hinge { 2494 | 0% { 2495 | -webkit-transform-origin: top left; 2496 | transform-origin: top left; 2497 | -webkit-animation-timing-function: ease-in-out; 2498 | animation-timing-function: ease-in-out; 2499 | } 2500 | 2501 | 20%, 60% { 2502 | -webkit-transform: rotate3d(0, 0, 1, 80deg); 2503 | transform: rotate3d(0, 0, 1, 80deg); 2504 | -webkit-transform-origin: top left; 2505 | transform-origin: top left; 2506 | -webkit-animation-timing-function: ease-in-out; 2507 | animation-timing-function: ease-in-out; 2508 | } 2509 | 2510 | 40%, 80% { 2511 | -webkit-transform: rotate3d(0, 0, 1, 60deg); 2512 | transform: rotate3d(0, 0, 1, 60deg); 2513 | -webkit-transform-origin: top left; 2514 | transform-origin: top left; 2515 | -webkit-animation-timing-function: ease-in-out; 2516 | animation-timing-function: ease-in-out; 2517 | opacity: 1; 2518 | } 2519 | 2520 | to { 2521 | -webkit-transform: translate3d(0, 700px, 0); 2522 | transform: translate3d(0, 700px, 0); 2523 | opacity: 0; 2524 | } 2525 | } 2526 | 2527 | @keyframes hinge { 2528 | 0% { 2529 | -webkit-transform-origin: top left; 2530 | transform-origin: top left; 2531 | -webkit-animation-timing-function: ease-in-out; 2532 | animation-timing-function: ease-in-out; 2533 | } 2534 | 2535 | 20%, 60% { 2536 | -webkit-transform: rotate3d(0, 0, 1, 80deg); 2537 | transform: rotate3d(0, 0, 1, 80deg); 2538 | -webkit-transform-origin: top left; 2539 | transform-origin: top left; 2540 | -webkit-animation-timing-function: ease-in-out; 2541 | animation-timing-function: ease-in-out; 2542 | } 2543 | 2544 | 40%, 80% { 2545 | -webkit-transform: rotate3d(0, 0, 1, 60deg); 2546 | transform: rotate3d(0, 0, 1, 60deg); 2547 | -webkit-transform-origin: top left; 2548 | transform-origin: top left; 2549 | -webkit-animation-timing-function: ease-in-out; 2550 | animation-timing-function: ease-in-out; 2551 | opacity: 1; 2552 | } 2553 | 2554 | to { 2555 | -webkit-transform: translate3d(0, 700px, 0); 2556 | transform: translate3d(0, 700px, 0); 2557 | opacity: 0; 2558 | } 2559 | } 2560 | 2561 | .hinge { 2562 | -webkit-animation-name: hinge; 2563 | animation-name: hinge; 2564 | } 2565 | 2566 | /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ 2567 | 2568 | @-webkit-keyframes rollIn { 2569 | from { 2570 | opacity: 0; 2571 | -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); 2572 | transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); 2573 | } 2574 | 2575 | to { 2576 | opacity: 1; 2577 | -webkit-transform: none; 2578 | transform: none; 2579 | } 2580 | } 2581 | 2582 | @keyframes rollIn { 2583 | from { 2584 | opacity: 0; 2585 | -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); 2586 | transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); 2587 | } 2588 | 2589 | to { 2590 | opacity: 1; 2591 | -webkit-transform: none; 2592 | transform: none; 2593 | } 2594 | } 2595 | 2596 | .rollIn { 2597 | -webkit-animation-name: rollIn; 2598 | animation-name: rollIn; 2599 | } 2600 | 2601 | /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ 2602 | 2603 | @-webkit-keyframes rollOut { 2604 | from { 2605 | opacity: 1; 2606 | } 2607 | 2608 | to { 2609 | opacity: 0; 2610 | -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); 2611 | transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); 2612 | } 2613 | } 2614 | 2615 | @keyframes rollOut { 2616 | from { 2617 | opacity: 1; 2618 | } 2619 | 2620 | to { 2621 | opacity: 0; 2622 | -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); 2623 | transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); 2624 | } 2625 | } 2626 | 2627 | .rollOut { 2628 | -webkit-animation-name: rollOut; 2629 | animation-name: rollOut; 2630 | } 2631 | 2632 | @-webkit-keyframes zoomIn { 2633 | from { 2634 | opacity: 0; 2635 | -webkit-transform: scale3d(.3, .3, .3); 2636 | transform: scale3d(.3, .3, .3); 2637 | } 2638 | 2639 | 50% { 2640 | opacity: 1; 2641 | } 2642 | } 2643 | 2644 | @keyframes zoomIn { 2645 | from { 2646 | opacity: 0; 2647 | -webkit-transform: scale3d(.3, .3, .3); 2648 | transform: scale3d(.3, .3, .3); 2649 | } 2650 | 2651 | 50% { 2652 | opacity: 1; 2653 | } 2654 | } 2655 | 2656 | .zoomIn { 2657 | -webkit-animation-name: zoomIn; 2658 | animation-name: zoomIn; 2659 | } 2660 | 2661 | @-webkit-keyframes zoomInDown { 2662 | from { 2663 | opacity: 0; 2664 | -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); 2665 | transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); 2666 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2667 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2668 | } 2669 | 2670 | 60% { 2671 | opacity: 1; 2672 | -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); 2673 | transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); 2674 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2675 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2676 | } 2677 | } 2678 | 2679 | @keyframes zoomInDown { 2680 | from { 2681 | opacity: 0; 2682 | -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); 2683 | transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); 2684 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2685 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2686 | } 2687 | 2688 | 60% { 2689 | opacity: 1; 2690 | -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); 2691 | transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); 2692 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2693 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2694 | } 2695 | } 2696 | 2697 | .zoomInDown { 2698 | -webkit-animation-name: zoomInDown; 2699 | animation-name: zoomInDown; 2700 | } 2701 | 2702 | @-webkit-keyframes zoomInLeft { 2703 | from { 2704 | opacity: 0; 2705 | -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); 2706 | transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); 2707 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2708 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2709 | } 2710 | 2711 | 60% { 2712 | opacity: 1; 2713 | -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); 2714 | transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); 2715 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2716 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2717 | } 2718 | } 2719 | 2720 | @keyframes zoomInLeft { 2721 | from { 2722 | opacity: 0; 2723 | -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); 2724 | transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); 2725 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2726 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2727 | } 2728 | 2729 | 60% { 2730 | opacity: 1; 2731 | -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); 2732 | transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); 2733 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2734 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2735 | } 2736 | } 2737 | 2738 | .zoomInLeft { 2739 | -webkit-animation-name: zoomInLeft; 2740 | animation-name: zoomInLeft; 2741 | } 2742 | 2743 | @-webkit-keyframes zoomInRight { 2744 | from { 2745 | opacity: 0; 2746 | -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); 2747 | transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); 2748 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2749 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2750 | } 2751 | 2752 | 60% { 2753 | opacity: 1; 2754 | -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); 2755 | transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); 2756 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2757 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2758 | } 2759 | } 2760 | 2761 | @keyframes zoomInRight { 2762 | from { 2763 | opacity: 0; 2764 | -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); 2765 | transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); 2766 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2767 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2768 | } 2769 | 2770 | 60% { 2771 | opacity: 1; 2772 | -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); 2773 | transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); 2774 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2775 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2776 | } 2777 | } 2778 | 2779 | .zoomInRight { 2780 | -webkit-animation-name: zoomInRight; 2781 | animation-name: zoomInRight; 2782 | } 2783 | 2784 | @-webkit-keyframes zoomInUp { 2785 | from { 2786 | opacity: 0; 2787 | -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); 2788 | transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); 2789 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2790 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2791 | } 2792 | 2793 | 60% { 2794 | opacity: 1; 2795 | -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); 2796 | transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); 2797 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2798 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2799 | } 2800 | } 2801 | 2802 | @keyframes zoomInUp { 2803 | from { 2804 | opacity: 0; 2805 | -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); 2806 | transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); 2807 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2808 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2809 | } 2810 | 2811 | 60% { 2812 | opacity: 1; 2813 | -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); 2814 | transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); 2815 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2816 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2817 | } 2818 | } 2819 | 2820 | .zoomInUp { 2821 | -webkit-animation-name: zoomInUp; 2822 | animation-name: zoomInUp; 2823 | } 2824 | 2825 | @-webkit-keyframes zoomOut { 2826 | from { 2827 | opacity: 1; 2828 | } 2829 | 2830 | 50% { 2831 | opacity: 0; 2832 | -webkit-transform: scale3d(.3, .3, .3); 2833 | transform: scale3d(.3, .3, .3); 2834 | } 2835 | 2836 | to { 2837 | opacity: 0; 2838 | } 2839 | } 2840 | 2841 | @keyframes zoomOut { 2842 | from { 2843 | opacity: 1; 2844 | } 2845 | 2846 | 50% { 2847 | opacity: 0; 2848 | -webkit-transform: scale3d(.3, .3, .3); 2849 | transform: scale3d(.3, .3, .3); 2850 | } 2851 | 2852 | to { 2853 | opacity: 0; 2854 | } 2855 | } 2856 | 2857 | .zoomOut { 2858 | -webkit-animation-name: zoomOut; 2859 | animation-name: zoomOut; 2860 | } 2861 | 2862 | @-webkit-keyframes zoomOutDown { 2863 | 40% { 2864 | opacity: 1; 2865 | -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); 2866 | transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); 2867 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2868 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2869 | } 2870 | 2871 | to { 2872 | opacity: 0; 2873 | -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); 2874 | transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); 2875 | -webkit-transform-origin: center bottom; 2876 | transform-origin: center bottom; 2877 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2878 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2879 | } 2880 | } 2881 | 2882 | @keyframes zoomOutDown { 2883 | 40% { 2884 | opacity: 1; 2885 | -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); 2886 | transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); 2887 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2888 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2889 | } 2890 | 2891 | to { 2892 | opacity: 0; 2893 | -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); 2894 | transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); 2895 | -webkit-transform-origin: center bottom; 2896 | transform-origin: center bottom; 2897 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2898 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2899 | } 2900 | } 2901 | 2902 | .zoomOutDown { 2903 | -webkit-animation-name: zoomOutDown; 2904 | animation-name: zoomOutDown; 2905 | } 2906 | 2907 | @-webkit-keyframes zoomOutLeft { 2908 | 40% { 2909 | opacity: 1; 2910 | -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); 2911 | transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); 2912 | } 2913 | 2914 | to { 2915 | opacity: 0; 2916 | -webkit-transform: scale(.1) translate3d(-2000px, 0, 0); 2917 | transform: scale(.1) translate3d(-2000px, 0, 0); 2918 | -webkit-transform-origin: left center; 2919 | transform-origin: left center; 2920 | } 2921 | } 2922 | 2923 | @keyframes zoomOutLeft { 2924 | 40% { 2925 | opacity: 1; 2926 | -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); 2927 | transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); 2928 | } 2929 | 2930 | to { 2931 | opacity: 0; 2932 | -webkit-transform: scale(.1) translate3d(-2000px, 0, 0); 2933 | transform: scale(.1) translate3d(-2000px, 0, 0); 2934 | -webkit-transform-origin: left center; 2935 | transform-origin: left center; 2936 | } 2937 | } 2938 | 2939 | .zoomOutLeft { 2940 | -webkit-animation-name: zoomOutLeft; 2941 | animation-name: zoomOutLeft; 2942 | } 2943 | 2944 | @-webkit-keyframes zoomOutRight { 2945 | 40% { 2946 | opacity: 1; 2947 | -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); 2948 | transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); 2949 | } 2950 | 2951 | to { 2952 | opacity: 0; 2953 | -webkit-transform: scale(.1) translate3d(2000px, 0, 0); 2954 | transform: scale(.1) translate3d(2000px, 0, 0); 2955 | -webkit-transform-origin: right center; 2956 | transform-origin: right center; 2957 | } 2958 | } 2959 | 2960 | @keyframes zoomOutRight { 2961 | 40% { 2962 | opacity: 1; 2963 | -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); 2964 | transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); 2965 | } 2966 | 2967 | to { 2968 | opacity: 0; 2969 | -webkit-transform: scale(.1) translate3d(2000px, 0, 0); 2970 | transform: scale(.1) translate3d(2000px, 0, 0); 2971 | -webkit-transform-origin: right center; 2972 | transform-origin: right center; 2973 | } 2974 | } 2975 | 2976 | .zoomOutRight { 2977 | -webkit-animation-name: zoomOutRight; 2978 | animation-name: zoomOutRight; 2979 | } 2980 | 2981 | @-webkit-keyframes zoomOutUp { 2982 | 40% { 2983 | opacity: 1; 2984 | -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); 2985 | transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); 2986 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2987 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 2988 | } 2989 | 2990 | to { 2991 | opacity: 0; 2992 | -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); 2993 | transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); 2994 | -webkit-transform-origin: center bottom; 2995 | transform-origin: center bottom; 2996 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2997 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 2998 | } 2999 | } 3000 | 3001 | @keyframes zoomOutUp { 3002 | 40% { 3003 | opacity: 1; 3004 | -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); 3005 | transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); 3006 | -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 3007 | animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); 3008 | } 3009 | 3010 | to { 3011 | opacity: 0; 3012 | -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); 3013 | transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); 3014 | -webkit-transform-origin: center bottom; 3015 | transform-origin: center bottom; 3016 | -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 3017 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); 3018 | } 3019 | } 3020 | 3021 | .zoomOutUp { 3022 | -webkit-animation-name: zoomOutUp; 3023 | animation-name: zoomOutUp; 3024 | } 3025 | 3026 | @-webkit-keyframes slideInDown { 3027 | from { 3028 | -webkit-transform: translate3d(0, -100%, 0); 3029 | transform: translate3d(0, -100%, 0); 3030 | visibility: visible; 3031 | } 3032 | 3033 | to { 3034 | -webkit-transform: translate3d(0, 0, 0); 3035 | transform: translate3d(0, 0, 0); 3036 | } 3037 | } 3038 | 3039 | @keyframes slideInDown { 3040 | from { 3041 | -webkit-transform: translate3d(0, -100%, 0); 3042 | transform: translate3d(0, -100%, 0); 3043 | visibility: visible; 3044 | } 3045 | 3046 | to { 3047 | -webkit-transform: translate3d(0, 0, 0); 3048 | transform: translate3d(0, 0, 0); 3049 | } 3050 | } 3051 | 3052 | .slideInDown { 3053 | -webkit-animation-name: slideInDown; 3054 | animation-name: slideInDown; 3055 | } 3056 | 3057 | @-webkit-keyframes slideInLeft { 3058 | from { 3059 | -webkit-transform: translate3d(-100%, 0, 0); 3060 | transform: translate3d(-100%, 0, 0); 3061 | visibility: visible; 3062 | } 3063 | 3064 | to { 3065 | -webkit-transform: translate3d(0, 0, 0); 3066 | transform: translate3d(0, 0, 0); 3067 | } 3068 | } 3069 | 3070 | @keyframes slideInLeft { 3071 | from { 3072 | -webkit-transform: translate3d(-100%, 0, 0); 3073 | transform: translate3d(-100%, 0, 0); 3074 | visibility: visible; 3075 | } 3076 | 3077 | to { 3078 | -webkit-transform: translate3d(0, 0, 0); 3079 | transform: translate3d(0, 0, 0); 3080 | } 3081 | } 3082 | 3083 | .slideInLeft { 3084 | -webkit-animation-name: slideInLeft; 3085 | animation-name: slideInLeft; 3086 | } 3087 | 3088 | @-webkit-keyframes slideInRight { 3089 | from { 3090 | -webkit-transform: translate3d(100%, 0, 0); 3091 | transform: translate3d(100%, 0, 0); 3092 | visibility: visible; 3093 | } 3094 | 3095 | to { 3096 | -webkit-transform: translate3d(0, 0, 0); 3097 | transform: translate3d(0, 0, 0); 3098 | } 3099 | } 3100 | 3101 | @keyframes slideInRight { 3102 | from { 3103 | -webkit-transform: translate3d(100%, 0, 0); 3104 | transform: translate3d(100%, 0, 0); 3105 | visibility: visible; 3106 | } 3107 | 3108 | to { 3109 | -webkit-transform: translate3d(0, 0, 0); 3110 | transform: translate3d(0, 0, 0); 3111 | } 3112 | } 3113 | 3114 | .slideInRight { 3115 | -webkit-animation-name: slideInRight; 3116 | animation-name: slideInRight; 3117 | } 3118 | 3119 | @-webkit-keyframes slideInUp { 3120 | from { 3121 | -webkit-transform: translate3d(0, 100%, 0); 3122 | transform: translate3d(0, 100%, 0); 3123 | visibility: visible; 3124 | } 3125 | 3126 | to { 3127 | -webkit-transform: translate3d(0, 0, 0); 3128 | transform: translate3d(0, 0, 0); 3129 | } 3130 | } 3131 | 3132 | @keyframes slideInUp { 3133 | from { 3134 | -webkit-transform: translate3d(0, 100%, 0); 3135 | transform: translate3d(0, 100%, 0); 3136 | visibility: visible; 3137 | } 3138 | 3139 | to { 3140 | -webkit-transform: translate3d(0, 0, 0); 3141 | transform: translate3d(0, 0, 0); 3142 | } 3143 | } 3144 | 3145 | .slideInUp { 3146 | -webkit-animation-name: slideInUp; 3147 | animation-name: slideInUp; 3148 | } 3149 | 3150 | @-webkit-keyframes slideOutDown { 3151 | from { 3152 | -webkit-transform: translate3d(0, 0, 0); 3153 | transform: translate3d(0, 0, 0); 3154 | } 3155 | 3156 | to { 3157 | visibility: hidden; 3158 | -webkit-transform: translate3d(0, 100%, 0); 3159 | transform: translate3d(0, 100%, 0); 3160 | } 3161 | } 3162 | 3163 | @keyframes slideOutDown { 3164 | from { 3165 | -webkit-transform: translate3d(0, 0, 0); 3166 | transform: translate3d(0, 0, 0); 3167 | } 3168 | 3169 | to { 3170 | visibility: hidden; 3171 | -webkit-transform: translate3d(0, 100%, 0); 3172 | transform: translate3d(0, 100%, 0); 3173 | } 3174 | } 3175 | 3176 | .slideOutDown { 3177 | -webkit-animation-name: slideOutDown; 3178 | animation-name: slideOutDown; 3179 | } 3180 | 3181 | @-webkit-keyframes slideOutLeft { 3182 | from { 3183 | -webkit-transform: translate3d(0, 0, 0); 3184 | transform: translate3d(0, 0, 0); 3185 | } 3186 | 3187 | to { 3188 | visibility: hidden; 3189 | -webkit-transform: translate3d(-100%, 0, 0); 3190 | transform: translate3d(-100%, 0, 0); 3191 | } 3192 | } 3193 | 3194 | @keyframes slideOutLeft { 3195 | from { 3196 | -webkit-transform: translate3d(0, 0, 0); 3197 | transform: translate3d(0, 0, 0); 3198 | } 3199 | 3200 | to { 3201 | visibility: hidden; 3202 | -webkit-transform: translate3d(-100%, 0, 0); 3203 | transform: translate3d(-100%, 0, 0); 3204 | } 3205 | } 3206 | 3207 | .slideOutLeft { 3208 | -webkit-animation-name: slideOutLeft; 3209 | animation-name: slideOutLeft; 3210 | } 3211 | 3212 | @-webkit-keyframes slideOutRight { 3213 | from { 3214 | -webkit-transform: translate3d(0, 0, 0); 3215 | transform: translate3d(0, 0, 0); 3216 | } 3217 | 3218 | to { 3219 | visibility: hidden; 3220 | -webkit-transform: translate3d(100%, 0, 0); 3221 | transform: translate3d(100%, 0, 0); 3222 | } 3223 | } 3224 | 3225 | @keyframes slideOutRight { 3226 | from { 3227 | -webkit-transform: translate3d(0, 0, 0); 3228 | transform: translate3d(0, 0, 0); 3229 | } 3230 | 3231 | to { 3232 | visibility: hidden; 3233 | -webkit-transform: translate3d(100%, 0, 0); 3234 | transform: translate3d(100%, 0, 0); 3235 | } 3236 | } 3237 | 3238 | .slideOutRight { 3239 | -webkit-animation-name: slideOutRight; 3240 | animation-name: slideOutRight; 3241 | } 3242 | 3243 | @-webkit-keyframes slideOutUp { 3244 | from { 3245 | -webkit-transform: translate3d(0, 0, 0); 3246 | transform: translate3d(0, 0, 0); 3247 | } 3248 | 3249 | to { 3250 | visibility: hidden; 3251 | -webkit-transform: translate3d(0, -100%, 0); 3252 | transform: translate3d(0, -100%, 0); 3253 | } 3254 | } 3255 | 3256 | @keyframes slideOutUp { 3257 | from { 3258 | -webkit-transform: translate3d(0, 0, 0); 3259 | transform: translate3d(0, 0, 0); 3260 | } 3261 | 3262 | to { 3263 | visibility: hidden; 3264 | -webkit-transform: translate3d(0, -100%, 0); 3265 | transform: translate3d(0, -100%, 0); 3266 | } 3267 | } 3268 | 3269 | .slideOutUp { 3270 | -webkit-animation-name: slideOutUp; 3271 | animation-name: slideOutUp; 3272 | } -------------------------------------------------------------------------------- /mqtt/web-interface/bulb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /mqtt/web-interface/bulb_off.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /mqtt/web-interface/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Arduino Cloud - MQTT message receiver example 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /mqtt/web-interface/light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /mqtt/web-interface/main.js: -------------------------------------------------------------------------------- 1 | // constants 2 | var mqttBrokerURI = "wss://mqtt.arduino.cc:9002/"; 3 | var mqttClientName = "browser-" + (new Date().getTime()); 4 | var mqttUsername = "username"; // your MQTT username 5 | var mqttPassword = "password"; // your MQTT password 6 | var mqttTopic = "/" + mqttUsername + "/001"; // your MQTT topic //topic 7 | 8 | // wait for page to be ready 9 | document.addEventListener("DOMContentLoaded", function(event) { 10 | // Create a client instance, 11 | // uses the paho library (https://www.eclipse.org/paho/clients/js/) 12 | client = new Paho.MQTT.Client(mqttBrokerURI, mqttClientName); 13 | 14 | // set callback handlers 15 | client.onConnectionLost = onConnectionLost; 16 | client.onMessageArrived = onMessageArrived; 17 | 18 | // connect the client 19 | client.connect({ 20 | userName: mqttUsername, 21 | password: mqttPassword, 22 | onSuccess: onConnect 23 | }); 24 | 25 | // called when the client connects 26 | function onConnect() { 27 | // Once a connection has been made, subscribe to the topic. 28 | console.log("connected"); 29 | client.subscribe(mqttTopic); 30 | console.log("subscribed to " + mqttTopic); 31 | } 32 | 33 | // called when the client loses it's connection 34 | function onConnectionLost(responseObject) { 35 | if (responseObject.errorCode !== 0) { 36 | console.log("connection lost:" + responseObject.errorMessage); 37 | } 38 | } 39 | 40 | function onMessageArrived(message) { 41 | console.log(message); 42 | console.log("new message arrived:" + message.payloadString); 43 | 44 | if (message.payloadString === "0") { 45 | switchoff(); 46 | } else if (message.payloadString === "255") { 47 | switchOn(); 48 | } 49 | } 50 | 51 | function switchOn() { 52 | document.querySelector('.intensity').classList.remove('fadeOut'); 53 | document.querySelector('.intensity').classList.add('fadeIn'); 54 | } 55 | 56 | function switchoff() { 57 | document.querySelector('.intensity').classList.remove('fadeIn'); 58 | document.querySelector('.intensity').classList.add('fadeOut'); 59 | } 60 | }); 61 | -------------------------------------------------------------------------------- /mqtt/web-interface/mqttws31.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 IBM Corp. 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * and Eclipse Distribution License v1.0 which accompany this distribution. 7 | * 8 | * The Eclipse Public License is available at 9 | * http://www.eclipse.org/legal/epl-v10.html 10 | * and the Eclipse Distribution License is available at 11 | * http://www.eclipse.org/org/documents/edl-v10.php. 12 | * 13 | * Contributors: 14 | * Andrew Banks - initial API and implementation and initial documentation 15 | *******************************************************************************/ 16 | 17 | 18 | // Only expose a single object name in the global namespace. 19 | // Everything must go through this module. Global Paho.MQTT module 20 | // only has a single public function, client, which returns 21 | // a Paho.MQTT client object given connection details. 22 | 23 | /** 24 | * Send and receive messages using web browsers. 25 | *

26 | * This programming interface lets a JavaScript client application use the MQTT V3.1 or 27 | * V3.1.1 protocol to connect to an MQTT-supporting messaging server. 28 | * 29 | * The function supported includes: 30 | *

    31 | *
  1. Connecting to and disconnecting from a server. The server is identified by its host name and port number. 32 | *
  2. Specifying options that relate to the communications link with the server, 33 | * for example the frequency of keep-alive heartbeats, and whether SSL/TLS is required. 34 | *
  3. Subscribing to and receiving messages from MQTT Topics. 35 | *
  4. Publishing messages to MQTT Topics. 36 | *
37 | *

38 | * The API consists of two main objects: 39 | *

40 | *
{@link Paho.MQTT.Client}
41 | *
This contains methods that provide the functionality of the API, 42 | * including provision of callbacks that notify the application when a message 43 | * arrives from or is delivered to the messaging server, 44 | * or when the status of its connection to the messaging server changes.
45 | *
{@link Paho.MQTT.Message}
46 | *
This encapsulates the payload of the message along with various attributes 47 | * associated with its delivery, in particular the destination to which it has 48 | * been (or is about to be) sent.
49 | *
50 | *

51 | * The programming interface validates parameters passed to it, and will throw 52 | * an Error containing an error message intended for developer use, if it detects 53 | * an error with any parameter. 54 | *

55 | * Example: 56 | * 57 | *

  58 | client = new Paho.MQTT.Client(location.hostname, Number(location.port), "clientId");
  59 | client.onConnectionLost = onConnectionLost;
  60 | client.onMessageArrived = onMessageArrived;
  61 | client.connect({onSuccess:onConnect});
  62 | 
  63 | function onConnect() {
  64 |   // Once a connection has been made, make a subscription and send a message.
  65 |   console.log("onConnect");
  66 |   client.subscribe("/World");
  67 |   message = new Paho.MQTT.Message("Hello");
  68 |   message.destinationName = "/World";
  69 |   client.send(message); 
  70 | };
  71 | function onConnectionLost(responseObject) {
  72 |   if (responseObject.errorCode !== 0)
  73 | 	console.log("onConnectionLost:"+responseObject.errorMessage);
  74 | };
  75 | function onMessageArrived(message) {
  76 |   console.log("onMessageArrived:"+message.payloadString);
  77 |   client.disconnect(); 
  78 | };	
  79 |  * 
80 | * @namespace Paho.MQTT 81 | */ 82 | 83 | if (typeof Paho === "undefined") { 84 | Paho = {}; 85 | } 86 | 87 | Paho.MQTT = (function (global) { 88 | 89 | // Private variables below, these are only visible inside the function closure 90 | // which is used to define the module. 91 | 92 | var version = "@VERSION@"; 93 | var buildLevel = "@BUILDLEVEL@"; 94 | 95 | /** 96 | * Unique message type identifiers, with associated 97 | * associated integer values. 98 | * @private 99 | */ 100 | var MESSAGE_TYPE = { 101 | CONNECT: 1, 102 | CONNACK: 2, 103 | PUBLISH: 3, 104 | PUBACK: 4, 105 | PUBREC: 5, 106 | PUBREL: 6, 107 | PUBCOMP: 7, 108 | SUBSCRIBE: 8, 109 | SUBACK: 9, 110 | UNSUBSCRIBE: 10, 111 | UNSUBACK: 11, 112 | PINGREQ: 12, 113 | PINGRESP: 13, 114 | DISCONNECT: 14 115 | }; 116 | 117 | // Collection of utility methods used to simplify module code 118 | // and promote the DRY pattern. 119 | 120 | /** 121 | * Validate an object's parameter names to ensure they 122 | * match a list of expected variables name for this option 123 | * type. Used to ensure option object passed into the API don't 124 | * contain erroneous parameters. 125 | * @param {Object} obj - User options object 126 | * @param {Object} keys - valid keys and types that may exist in obj. 127 | * @throws {Error} Invalid option parameter found. 128 | * @private 129 | */ 130 | var validate = function(obj, keys) { 131 | for (var key in obj) { 132 | if (obj.hasOwnProperty(key)) { 133 | if (keys.hasOwnProperty(key)) { 134 | if (typeof obj[key] !== keys[key]) 135 | throw new Error(format(ERROR.INVALID_TYPE, [typeof obj[key], key])); 136 | } else { 137 | var errorStr = "Unknown property, " + key + ". Valid properties are:"; 138 | for (var key in keys) 139 | if (keys.hasOwnProperty(key)) 140 | errorStr = errorStr+" "+key; 141 | throw new Error(errorStr); 142 | } 143 | } 144 | } 145 | }; 146 | 147 | /** 148 | * Return a new function which runs the user function bound 149 | * to a fixed scope. 150 | * @param {function} User function 151 | * @param {object} Function scope 152 | * @return {function} User function bound to another scope 153 | * @private 154 | */ 155 | var scope = function (f, scope) { 156 | return function () { 157 | return f.apply(scope, arguments); 158 | }; 159 | }; 160 | 161 | /** 162 | * Unique message type identifiers, with associated 163 | * associated integer values. 164 | * @private 165 | */ 166 | var ERROR = { 167 | OK: {code:0, text:"AMQJSC0000I OK."}, 168 | CONNECT_TIMEOUT: {code:1, text:"AMQJSC0001E Connect timed out."}, 169 | SUBSCRIBE_TIMEOUT: {code:2, text:"AMQJS0002E Subscribe timed out."}, 170 | UNSUBSCRIBE_TIMEOUT: {code:3, text:"AMQJS0003E Unsubscribe timed out."}, 171 | PING_TIMEOUT: {code:4, text:"AMQJS0004E Ping timed out."}, 172 | INTERNAL_ERROR: {code:5, text:"AMQJS0005E Internal error. Error Message: {0}, Stack trace: {1}"}, 173 | CONNACK_RETURNCODE: {code:6, text:"AMQJS0006E Bad Connack return code:{0} {1}."}, 174 | SOCKET_ERROR: {code:7, text:"AMQJS0007E Socket error:{0}."}, 175 | SOCKET_CLOSE: {code:8, text:"AMQJS0008I Socket closed."}, 176 | MALFORMED_UTF: {code:9, text:"AMQJS0009E Malformed UTF data:{0} {1} {2}."}, 177 | UNSUPPORTED: {code:10, text:"AMQJS0010E {0} is not supported by this browser."}, 178 | INVALID_STATE: {code:11, text:"AMQJS0011E Invalid state {0}."}, 179 | INVALID_TYPE: {code:12, text:"AMQJS0012E Invalid type {0} for {1}."}, 180 | INVALID_ARGUMENT: {code:13, text:"AMQJS0013E Invalid argument {0} for {1}."}, 181 | UNSUPPORTED_OPERATION: {code:14, text:"AMQJS0014E Unsupported operation."}, 182 | INVALID_STORED_DATA: {code:15, text:"AMQJS0015E Invalid data in local storage key={0} value={1}."}, 183 | INVALID_MQTT_MESSAGE_TYPE: {code:16, text:"AMQJS0016E Invalid MQTT message type {0}."}, 184 | MALFORMED_UNICODE: {code:17, text:"AMQJS0017E Malformed Unicode string:{0} {1}."}, 185 | }; 186 | 187 | /** CONNACK RC Meaning. */ 188 | var CONNACK_RC = { 189 | 0:"Connection Accepted", 190 | 1:"Connection Refused: unacceptable protocol version", 191 | 2:"Connection Refused: identifier rejected", 192 | 3:"Connection Refused: server unavailable", 193 | 4:"Connection Refused: bad user name or password", 194 | 5:"Connection Refused: not authorized" 195 | }; 196 | 197 | /** 198 | * Format an error message text. 199 | * @private 200 | * @param {error} ERROR.KEY value above. 201 | * @param {substitutions} [array] substituted into the text. 202 | * @return the text with the substitutions made. 203 | */ 204 | var format = function(error, substitutions) { 205 | var text = error.text; 206 | if (substitutions) { 207 | var field,start; 208 | for (var i=0; i 0) { 212 | var part1 = text.substring(0,start); 213 | var part2 = text.substring(start+field.length); 214 | text = part1+substitutions[i]+part2; 215 | } 216 | } 217 | } 218 | return text; 219 | }; 220 | 221 | //MQTT protocol and version 6 M Q I s d p 3 222 | var MqttProtoIdentifierv3 = [0x00,0x06,0x4d,0x51,0x49,0x73,0x64,0x70,0x03]; 223 | //MQTT proto/version for 311 4 M Q T T 4 224 | var MqttProtoIdentifierv4 = [0x00,0x04,0x4d,0x51,0x54,0x54,0x04]; 225 | 226 | /** 227 | * Construct an MQTT wire protocol message. 228 | * @param type MQTT packet type. 229 | * @param options optional wire message attributes. 230 | * 231 | * Optional properties 232 | * 233 | * messageIdentifier: message ID in the range [0..65535] 234 | * payloadMessage: Application Message - PUBLISH only 235 | * connectStrings: array of 0 or more Strings to be put into the CONNECT payload 236 | * topics: array of strings (SUBSCRIBE, UNSUBSCRIBE) 237 | * requestQoS: array of QoS values [0..2] 238 | * 239 | * "Flag" properties 240 | * cleanSession: true if present / false if absent (CONNECT) 241 | * willMessage: true if present / false if absent (CONNECT) 242 | * isRetained: true if present / false if absent (CONNECT) 243 | * userName: true if present / false if absent (CONNECT) 244 | * password: true if present / false if absent (CONNECT) 245 | * keepAliveInterval: integer [0..65535] (CONNECT) 246 | * 247 | * @private 248 | * @ignore 249 | */ 250 | var WireMessage = function (type, options) { 251 | this.type = type; 252 | for (var name in options) { 253 | if (options.hasOwnProperty(name)) { 254 | this[name] = options[name]; 255 | } 256 | } 257 | }; 258 | 259 | WireMessage.prototype.encode = function() { 260 | // Compute the first byte of the fixed header 261 | var first = ((this.type & 0x0f) << 4); 262 | 263 | /* 264 | * Now calculate the length of the variable header + payload by adding up the lengths 265 | * of all the component parts 266 | */ 267 | 268 | var remLength = 0; 269 | var topicStrLength = new Array(); 270 | var destinationNameLength = 0; 271 | 272 | // if the message contains a messageIdentifier then we need two bytes for that 273 | if (this.messageIdentifier != undefined) 274 | remLength += 2; 275 | 276 | switch(this.type) { 277 | // If this a Connect then we need to include 12 bytes for its header 278 | case MESSAGE_TYPE.CONNECT: 279 | switch(this.mqttVersion) { 280 | case 3: 281 | remLength += MqttProtoIdentifierv3.length + 3; 282 | break; 283 | case 4: 284 | remLength += MqttProtoIdentifierv4.length + 3; 285 | break; 286 | } 287 | 288 | remLength += UTF8Length(this.clientId) + 2; 289 | if (this.willMessage != undefined) { 290 | remLength += UTF8Length(this.willMessage.destinationName) + 2; 291 | // Will message is always a string, sent as UTF-8 characters with a preceding length. 292 | var willMessagePayloadBytes = this.willMessage.payloadBytes; 293 | if (!(willMessagePayloadBytes instanceof Uint8Array)) 294 | willMessagePayloadBytes = new Uint8Array(payloadBytes); 295 | remLength += willMessagePayloadBytes.byteLength +2; 296 | } 297 | if (this.userName != undefined) 298 | remLength += UTF8Length(this.userName) + 2; 299 | if (this.password != undefined) 300 | remLength += UTF8Length(this.password) + 2; 301 | break; 302 | 303 | // Subscribe, Unsubscribe can both contain topic strings 304 | case MESSAGE_TYPE.SUBSCRIBE: 305 | first |= 0x02; // Qos = 1; 306 | for ( var i = 0; i < this.topics.length; i++) { 307 | topicStrLength[i] = UTF8Length(this.topics[i]); 308 | remLength += topicStrLength[i] + 2; 309 | } 310 | remLength += this.requestedQos.length; // 1 byte for each topic's Qos 311 | // QoS on Subscribe only 312 | break; 313 | 314 | case MESSAGE_TYPE.UNSUBSCRIBE: 315 | first |= 0x02; // Qos = 1; 316 | for ( var i = 0; i < this.topics.length; i++) { 317 | topicStrLength[i] = UTF8Length(this.topics[i]); 318 | remLength += topicStrLength[i] + 2; 319 | } 320 | break; 321 | 322 | case MESSAGE_TYPE.PUBREL: 323 | first |= 0x02; // Qos = 1; 324 | break; 325 | 326 | case MESSAGE_TYPE.PUBLISH: 327 | if (this.payloadMessage.duplicate) first |= 0x08; 328 | first = first |= (this.payloadMessage.qos << 1); 329 | if (this.payloadMessage.retained) first |= 0x01; 330 | destinationNameLength = UTF8Length(this.payloadMessage.destinationName); 331 | remLength += destinationNameLength + 2; 332 | var payloadBytes = this.payloadMessage.payloadBytes; 333 | remLength += payloadBytes.byteLength; 334 | if (payloadBytes instanceof ArrayBuffer) 335 | payloadBytes = new Uint8Array(payloadBytes); 336 | else if (!(payloadBytes instanceof Uint8Array)) 337 | payloadBytes = new Uint8Array(payloadBytes.buffer); 338 | break; 339 | 340 | case MESSAGE_TYPE.DISCONNECT: 341 | break; 342 | 343 | default: 344 | ; 345 | } 346 | 347 | // Now we can allocate a buffer for the message 348 | 349 | var mbi = encodeMBI(remLength); // Convert the length to MQTT MBI format 350 | var pos = mbi.length + 1; // Offset of start of variable header 351 | var buffer = new ArrayBuffer(remLength + pos); 352 | var byteStream = new Uint8Array(buffer); // view it as a sequence of bytes 353 | 354 | //Write the fixed header into the buffer 355 | byteStream[0] = first; 356 | byteStream.set(mbi,1); 357 | 358 | // If this is a PUBLISH then the variable header starts with a topic 359 | if (this.type == MESSAGE_TYPE.PUBLISH) 360 | pos = writeString(this.payloadMessage.destinationName, destinationNameLength, byteStream, pos); 361 | // If this is a CONNECT then the variable header contains the protocol name/version, flags and keepalive time 362 | 363 | else if (this.type == MESSAGE_TYPE.CONNECT) { 364 | switch (this.mqttVersion) { 365 | case 3: 366 | byteStream.set(MqttProtoIdentifierv3, pos); 367 | pos += MqttProtoIdentifierv3.length; 368 | break; 369 | case 4: 370 | byteStream.set(MqttProtoIdentifierv4, pos); 371 | pos += MqttProtoIdentifierv4.length; 372 | break; 373 | } 374 | var connectFlags = 0; 375 | if (this.cleanSession) 376 | connectFlags = 0x02; 377 | if (this.willMessage != undefined ) { 378 | connectFlags |= 0x04; 379 | connectFlags |= (this.willMessage.qos<<3); 380 | if (this.willMessage.retained) { 381 | connectFlags |= 0x20; 382 | } 383 | } 384 | if (this.userName != undefined) 385 | connectFlags |= 0x80; 386 | if (this.password != undefined) 387 | connectFlags |= 0x40; 388 | byteStream[pos++] = connectFlags; 389 | pos = writeUint16 (this.keepAliveInterval, byteStream, pos); 390 | } 391 | 392 | // Output the messageIdentifier - if there is one 393 | if (this.messageIdentifier != undefined) 394 | pos = writeUint16 (this.messageIdentifier, byteStream, pos); 395 | 396 | switch(this.type) { 397 | case MESSAGE_TYPE.CONNECT: 398 | pos = writeString(this.clientId, UTF8Length(this.clientId), byteStream, pos); 399 | if (this.willMessage != undefined) { 400 | pos = writeString(this.willMessage.destinationName, UTF8Length(this.willMessage.destinationName), byteStream, pos); 401 | pos = writeUint16(willMessagePayloadBytes.byteLength, byteStream, pos); 402 | byteStream.set(willMessagePayloadBytes, pos); 403 | pos += willMessagePayloadBytes.byteLength; 404 | 405 | } 406 | if (this.userName != undefined) 407 | pos = writeString(this.userName, UTF8Length(this.userName), byteStream, pos); 408 | if (this.password != undefined) 409 | pos = writeString(this.password, UTF8Length(this.password), byteStream, pos); 410 | break; 411 | 412 | case MESSAGE_TYPE.PUBLISH: 413 | // PUBLISH has a text or binary payload, if text do not add a 2 byte length field, just the UTF characters. 414 | byteStream.set(payloadBytes, pos); 415 | 416 | break; 417 | 418 | // case MESSAGE_TYPE.PUBREC: 419 | // case MESSAGE_TYPE.PUBREL: 420 | // case MESSAGE_TYPE.PUBCOMP: 421 | // break; 422 | 423 | case MESSAGE_TYPE.SUBSCRIBE: 424 | // SUBSCRIBE has a list of topic strings and request QoS 425 | for (var i=0; i> 4; 448 | var messageInfo = first &= 0x0f; 449 | pos += 1; 450 | 451 | 452 | // Decode the remaining length (MBI format) 453 | 454 | var digit; 455 | var remLength = 0; 456 | var multiplier = 1; 457 | do { 458 | if (pos == input.length) { 459 | return [null,startingPos]; 460 | } 461 | digit = input[pos++]; 462 | remLength += ((digit & 0x7F) * multiplier); 463 | multiplier *= 128; 464 | } while ((digit & 0x80) != 0); 465 | 466 | var endPos = pos+remLength; 467 | if (endPos > input.length) { 468 | return [null,startingPos]; 469 | } 470 | 471 | var wireMessage = new WireMessage(type); 472 | switch(type) { 473 | case MESSAGE_TYPE.CONNACK: 474 | var connectAcknowledgeFlags = input[pos++]; 475 | if (connectAcknowledgeFlags & 0x01) 476 | wireMessage.sessionPresent = true; 477 | wireMessage.returnCode = input[pos++]; 478 | break; 479 | 480 | case MESSAGE_TYPE.PUBLISH: 481 | var qos = (messageInfo >> 1) & 0x03; 482 | 483 | var len = readUint16(input, pos); 484 | pos += 2; 485 | var topicName = parseUTF8(input, pos, len); 486 | pos += len; 487 | // If QoS 1 or 2 there will be a messageIdentifier 488 | if (qos > 0) { 489 | wireMessage.messageIdentifier = readUint16(input, pos); 490 | pos += 2; 491 | } 492 | 493 | var message = new Paho.MQTT.Message(input.subarray(pos, endPos)); 494 | if ((messageInfo & 0x01) == 0x01) 495 | message.retained = true; 496 | if ((messageInfo & 0x08) == 0x08) 497 | message.duplicate = true; 498 | message.qos = qos; 499 | message.destinationName = topicName; 500 | wireMessage.payloadMessage = message; 501 | break; 502 | 503 | case MESSAGE_TYPE.PUBACK: 504 | case MESSAGE_TYPE.PUBREC: 505 | case MESSAGE_TYPE.PUBREL: 506 | case MESSAGE_TYPE.PUBCOMP: 507 | case MESSAGE_TYPE.UNSUBACK: 508 | wireMessage.messageIdentifier = readUint16(input, pos); 509 | break; 510 | 511 | case MESSAGE_TYPE.SUBACK: 512 | wireMessage.messageIdentifier = readUint16(input, pos); 513 | pos += 2; 514 | wireMessage.returnCode = input.subarray(pos, endPos); 515 | break; 516 | 517 | default: 518 | ; 519 | } 520 | 521 | return [wireMessage,endPos]; 522 | } 523 | 524 | function writeUint16(input, buffer, offset) { 525 | buffer[offset++] = input >> 8; //MSB 526 | buffer[offset++] = input % 256; //LSB 527 | return offset; 528 | } 529 | 530 | function writeString(input, utf8Length, buffer, offset) { 531 | offset = writeUint16(utf8Length, buffer, offset); 532 | stringToUTF8(input, buffer, offset); 533 | return offset + utf8Length; 534 | } 535 | 536 | function readUint16(buffer, offset) { 537 | return 256*buffer[offset] + buffer[offset+1]; 538 | } 539 | 540 | /** 541 | * Encodes an MQTT Multi-Byte Integer 542 | * @private 543 | */ 544 | function encodeMBI(number) { 545 | var output = new Array(1); 546 | var numBytes = 0; 547 | 548 | do { 549 | var digit = number % 128; 550 | number = number >> 7; 551 | if (number > 0) { 552 | digit |= 0x80; 553 | } 554 | output[numBytes++] = digit; 555 | } while ( (number > 0) && (numBytes<4) ); 556 | 557 | return output; 558 | } 559 | 560 | /** 561 | * Takes a String and calculates its length in bytes when encoded in UTF8. 562 | * @private 563 | */ 564 | function UTF8Length(input) { 565 | var output = 0; 566 | for (var i = 0; i 0x7FF) 570 | { 571 | // Surrogate pair means its a 4 byte character 572 | if (0xD800 <= charCode && charCode <= 0xDBFF) 573 | { 574 | i++; 575 | output++; 576 | } 577 | output +=3; 578 | } 579 | else if (charCode > 0x7F) 580 | output +=2; 581 | else 582 | output++; 583 | } 584 | return output; 585 | } 586 | 587 | /** 588 | * Takes a String and writes it into an array as UTF8 encoded bytes. 589 | * @private 590 | */ 591 | function stringToUTF8(input, output, start) { 592 | var pos = start; 593 | for (var i = 0; i>6 & 0x1F | 0xC0; 610 | output[pos++] = charCode & 0x3F | 0x80; 611 | } else if (charCode <= 0xFFFF) { 612 | output[pos++] = charCode>>12 & 0x0F | 0xE0; 613 | output[pos++] = charCode>>6 & 0x3F | 0x80; 614 | output[pos++] = charCode & 0x3F | 0x80; 615 | } else { 616 | output[pos++] = charCode>>18 & 0x07 | 0xF0; 617 | output[pos++] = charCode>>12 & 0x3F | 0x80; 618 | output[pos++] = charCode>>6 & 0x3F | 0x80; 619 | output[pos++] = charCode & 0x3F | 0x80; 620 | }; 621 | } 622 | return output; 623 | } 624 | 625 | function parseUTF8(input, offset, length) { 626 | var output = ""; 627 | var utf16; 628 | var pos = offset; 629 | 630 | while (pos < offset+length) 631 | { 632 | var byte1 = input[pos++]; 633 | if (byte1 < 128) 634 | utf16 = byte1; 635 | else 636 | { 637 | var byte2 = input[pos++]-128; 638 | if (byte2 < 0) 639 | throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16),""])); 640 | if (byte1 < 0xE0) // 2 byte character 641 | utf16 = 64*(byte1-0xC0) + byte2; 642 | else 643 | { 644 | var byte3 = input[pos++]-128; 645 | if (byte3 < 0) 646 | throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16)])); 647 | if (byte1 < 0xF0) // 3 byte character 648 | utf16 = 4096*(byte1-0xE0) + 64*byte2 + byte3; 649 | else 650 | { 651 | var byte4 = input[pos++]-128; 652 | if (byte4 < 0) 653 | throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16), byte4.toString(16)])); 654 | if (byte1 < 0xF8) // 4 byte character 655 | utf16 = 262144*(byte1-0xF0) + 4096*byte2 + 64*byte3 + byte4; 656 | else // longer encodings are not supported 657 | throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16), byte4.toString(16)])); 658 | } 659 | } 660 | } 661 | 662 | if (utf16 > 0xFFFF) // 4 byte character - express as a surrogate pair 663 | { 664 | utf16 -= 0x10000; 665 | output += String.fromCharCode(0xD800 + (utf16 >> 10)); // lead character 666 | utf16 = 0xDC00 + (utf16 & 0x3FF); // trail character 667 | } 668 | output += String.fromCharCode(utf16); 669 | } 670 | return output; 671 | } 672 | 673 | /** 674 | * Repeat keepalive requests, monitor responses. 675 | * @ignore 676 | */ 677 | var Pinger = function(client, window, keepAliveInterval) { 678 | this._client = client; 679 | this._window = window; 680 | this._keepAliveInterval = keepAliveInterval*1000; 681 | this.isReset = false; 682 | 683 | var pingReq = new WireMessage(MESSAGE_TYPE.PINGREQ).encode(); 684 | 685 | var doTimeout = function (pinger) { 686 | return function () { 687 | return doPing.apply(pinger); 688 | }; 689 | }; 690 | 691 | /** @ignore */ 692 | var doPing = function() { 693 | if (!this.isReset) { 694 | this._client._trace("Pinger.doPing", "Timed out"); 695 | this._client._disconnected( ERROR.PING_TIMEOUT.code , format(ERROR.PING_TIMEOUT)); 696 | } else { 697 | this.isReset = false; 698 | this._client._trace("Pinger.doPing", "send PINGREQ"); 699 | this._client.socket.send(pingReq); 700 | this.timeout = this._window.setTimeout(doTimeout(this), this._keepAliveInterval); 701 | } 702 | } 703 | 704 | this.reset = function() { 705 | this.isReset = true; 706 | this._window.clearTimeout(this.timeout); 707 | if (this._keepAliveInterval > 0) 708 | this.timeout = setTimeout(doTimeout(this), this._keepAliveInterval); 709 | } 710 | 711 | this.cancel = function() { 712 | this._window.clearTimeout(this.timeout); 713 | } 714 | }; 715 | 716 | /** 717 | * Monitor request completion. 718 | * @ignore 719 | */ 720 | var Timeout = function(client, window, timeoutSeconds, action, args) { 721 | this._window = window; 722 | if (!timeoutSeconds) 723 | timeoutSeconds = 30; 724 | 725 | var doTimeout = function (action, client, args) { 726 | return function () { 727 | return action.apply(client, args); 728 | }; 729 | }; 730 | this.timeout = setTimeout(doTimeout(action, client, args), timeoutSeconds * 1000); 731 | 732 | this.cancel = function() { 733 | this._window.clearTimeout(this.timeout); 734 | } 735 | }; 736 | 737 | /* 738 | * Internal implementation of the Websockets MQTT V3.1 client. 739 | * 740 | * @name Paho.MQTT.ClientImpl @constructor 741 | * @param {String} host the DNS nameof the webSocket host. 742 | * @param {Number} port the port number for that host. 743 | * @param {String} clientId the MQ client identifier. 744 | */ 745 | var ClientImpl = function (uri, host, port, path, clientId) { 746 | // Check dependencies are satisfied in this browser. 747 | if (!("WebSocket" in global && global["WebSocket"] !== null)) { 748 | throw new Error(format(ERROR.UNSUPPORTED, ["WebSocket"])); 749 | } 750 | if (!("localStorage" in global && global["localStorage"] !== null)) { 751 | throw new Error(format(ERROR.UNSUPPORTED, ["localStorage"])); 752 | } 753 | if (!("ArrayBuffer" in global && global["ArrayBuffer"] !== null)) { 754 | throw new Error(format(ERROR.UNSUPPORTED, ["ArrayBuffer"])); 755 | } 756 | this._trace("Paho.MQTT.Client", uri, host, port, path, clientId); 757 | 758 | this.host = host; 759 | this.port = port; 760 | this.path = path; 761 | this.uri = uri; 762 | this.clientId = clientId; 763 | 764 | // Local storagekeys are qualified with the following string. 765 | // The conditional inclusion of path in the key is for backward 766 | // compatibility to when the path was not configurable and assumed to 767 | // be /mqtt 768 | this._localKey=host+":"+port+(path!="/mqtt"?":"+path:"")+":"+clientId+":"; 769 | 770 | // Create private instance-only message queue 771 | // Internal queue of messages to be sent, in sending order. 772 | this._msg_queue = []; 773 | 774 | // Messages we have sent and are expecting a response for, indexed by their respective message ids. 775 | this._sentMessages = {}; 776 | 777 | // Messages we have received and acknowleged and are expecting a confirm message for 778 | // indexed by their respective message ids. 779 | this._receivedMessages = {}; 780 | 781 | // Internal list of callbacks to be executed when messages 782 | // have been successfully sent over web socket, e.g. disconnect 783 | // when it doesn't have to wait for ACK, just message is dispatched. 784 | this._notify_msg_sent = {}; 785 | 786 | // Unique identifier for SEND messages, incrementing 787 | // counter as messages are sent. 788 | this._message_identifier = 1; 789 | 790 | // Used to determine the transmission sequence of stored sent messages. 791 | this._sequence = 0; 792 | 793 | 794 | // Load the local state, if any, from the saved version, only restore state relevant to this client. 795 | for (var key in localStorage) 796 | if ( key.indexOf("Sent:"+this._localKey) == 0 797 | || key.indexOf("Received:"+this._localKey) == 0) 798 | this.restore(key); 799 | }; 800 | 801 | // Messaging Client public instance members. 802 | ClientImpl.prototype.host; 803 | ClientImpl.prototype.port; 804 | ClientImpl.prototype.path; 805 | ClientImpl.prototype.uri; 806 | ClientImpl.prototype.clientId; 807 | 808 | // Messaging Client private instance members. 809 | ClientImpl.prototype.socket; 810 | /* true once we have received an acknowledgement to a CONNECT packet. */ 811 | ClientImpl.prototype.connected = false; 812 | /* The largest message identifier allowed, may not be larger than 2**16 but 813 | * if set smaller reduces the maximum number of outbound messages allowed. 814 | */ 815 | ClientImpl.prototype.maxMessageIdentifier = 65536; 816 | ClientImpl.prototype.connectOptions; 817 | ClientImpl.prototype.hostIndex; 818 | ClientImpl.prototype.onConnectionLost; 819 | ClientImpl.prototype.onMessageDelivered; 820 | ClientImpl.prototype.onMessageArrived; 821 | ClientImpl.prototype.traceFunction; 822 | ClientImpl.prototype._msg_queue = null; 823 | ClientImpl.prototype._connectTimeout; 824 | /* The sendPinger monitors how long we allow before we send data to prove to the server that we are alive. */ 825 | ClientImpl.prototype.sendPinger = null; 826 | /* The receivePinger monitors how long we allow before we require evidence that the server is alive. */ 827 | ClientImpl.prototype.receivePinger = null; 828 | 829 | ClientImpl.prototype.receiveBuffer = null; 830 | 831 | ClientImpl.prototype._traceBuffer = null; 832 | ClientImpl.prototype._MAX_TRACE_ENTRIES = 100; 833 | 834 | ClientImpl.prototype.connect = function (connectOptions) { 835 | var connectOptionsMasked = this._traceMask(connectOptions, "password"); 836 | this._trace("Client.connect", connectOptionsMasked, this.socket, this.connected); 837 | 838 | if (this.connected) 839 | throw new Error(format(ERROR.INVALID_STATE, ["already connected"])); 840 | if (this.socket) 841 | throw new Error(format(ERROR.INVALID_STATE, ["already connected"])); 842 | 843 | this.connectOptions = connectOptions; 844 | 845 | if (connectOptions.uris) { 846 | this.hostIndex = 0; 847 | this._doConnect(connectOptions.uris[0]); 848 | } else { 849 | this._doConnect(this.uri); 850 | } 851 | 852 | }; 853 | 854 | ClientImpl.prototype.subscribe = function (filter, subscribeOptions) { 855 | this._trace("Client.subscribe", filter, subscribeOptions); 856 | 857 | if (!this.connected) 858 | throw new Error(format(ERROR.INVALID_STATE, ["not connected"])); 859 | 860 | var wireMessage = new WireMessage(MESSAGE_TYPE.SUBSCRIBE); 861 | wireMessage.topics=[filter]; 862 | if (subscribeOptions.qos != undefined) 863 | wireMessage.requestedQos = [subscribeOptions.qos]; 864 | else 865 | wireMessage.requestedQos = [0]; 866 | 867 | if (subscribeOptions.onSuccess) { 868 | wireMessage.onSuccess = function(grantedQos) {subscribeOptions.onSuccess({invocationContext:subscribeOptions.invocationContext,grantedQos:grantedQos});}; 869 | } 870 | 871 | if (subscribeOptions.onFailure) { 872 | wireMessage.onFailure = function(errorCode) {subscribeOptions.onFailure({invocationContext:subscribeOptions.invocationContext,errorCode:errorCode});}; 873 | } 874 | 875 | if (subscribeOptions.timeout) { 876 | wireMessage.timeOut = new Timeout(this, window, subscribeOptions.timeout, subscribeOptions.onFailure 877 | , [{invocationContext:subscribeOptions.invocationContext, 878 | errorCode:ERROR.SUBSCRIBE_TIMEOUT.code, 879 | errorMessage:format(ERROR.SUBSCRIBE_TIMEOUT)}]); 880 | } 881 | 882 | // All subscriptions return a SUBACK. 883 | this._requires_ack(wireMessage); 884 | this._schedule_message(wireMessage); 885 | }; 886 | 887 | /** @ignore */ 888 | ClientImpl.prototype.unsubscribe = function(filter, unsubscribeOptions) { 889 | this._trace("Client.unsubscribe", filter, unsubscribeOptions); 890 | 891 | if (!this.connected) 892 | throw new Error(format(ERROR.INVALID_STATE, ["not connected"])); 893 | 894 | var wireMessage = new WireMessage(MESSAGE_TYPE.UNSUBSCRIBE); 895 | wireMessage.topics = [filter]; 896 | 897 | if (unsubscribeOptions.onSuccess) { 898 | wireMessage.callback = function() {unsubscribeOptions.onSuccess({invocationContext:unsubscribeOptions.invocationContext});}; 899 | } 900 | if (unsubscribeOptions.timeout) { 901 | wireMessage.timeOut = new Timeout(this, window, unsubscribeOptions.timeout, unsubscribeOptions.onFailure 902 | , [{invocationContext:unsubscribeOptions.invocationContext, 903 | errorCode:ERROR.UNSUBSCRIBE_TIMEOUT.code, 904 | errorMessage:format(ERROR.UNSUBSCRIBE_TIMEOUT)}]); 905 | } 906 | 907 | // All unsubscribes return a SUBACK. 908 | this._requires_ack(wireMessage); 909 | this._schedule_message(wireMessage); 910 | }; 911 | 912 | ClientImpl.prototype.send = function (message) { 913 | this._trace("Client.send", message); 914 | 915 | if (!this.connected) 916 | throw new Error(format(ERROR.INVALID_STATE, ["not connected"])); 917 | 918 | wireMessage = new WireMessage(MESSAGE_TYPE.PUBLISH); 919 | wireMessage.payloadMessage = message; 920 | 921 | if (message.qos > 0) 922 | this._requires_ack(wireMessage); 923 | else if (this.onMessageDelivered) 924 | this._notify_msg_sent[wireMessage] = this.onMessageDelivered(wireMessage.payloadMessage); 925 | this._schedule_message(wireMessage); 926 | }; 927 | 928 | ClientImpl.prototype.disconnect = function () { 929 | this._trace("Client.disconnect"); 930 | 931 | if (!this.socket) 932 | throw new Error(format(ERROR.INVALID_STATE, ["not connecting or connected"])); 933 | 934 | wireMessage = new WireMessage(MESSAGE_TYPE.DISCONNECT); 935 | 936 | // Run the disconnected call back as soon as the message has been sent, 937 | // in case of a failure later on in the disconnect processing. 938 | // as a consequence, the _disconected call back may be run several times. 939 | this._notify_msg_sent[wireMessage] = scope(this._disconnected, this); 940 | 941 | this._schedule_message(wireMessage); 942 | }; 943 | 944 | ClientImpl.prototype.getTraceLog = function () { 945 | if ( this._traceBuffer !== null ) { 946 | this._trace("Client.getTraceLog", new Date()); 947 | this._trace("Client.getTraceLog in flight messages", this._sentMessages.length); 948 | for (var key in this._sentMessages) 949 | this._trace("_sentMessages ",key, this._sentMessages[key]); 950 | for (var key in this._receivedMessages) 951 | this._trace("_receivedMessages ",key, this._receivedMessages[key]); 952 | 953 | return this._traceBuffer; 954 | } 955 | }; 956 | 957 | ClientImpl.prototype.startTrace = function () { 958 | if ( this._traceBuffer === null ) { 959 | this._traceBuffer = []; 960 | } 961 | this._trace("Client.startTrace", new Date(), version); 962 | }; 963 | 964 | ClientImpl.prototype.stopTrace = function () { 965 | delete this._traceBuffer; 966 | }; 967 | 968 | ClientImpl.prototype._doConnect = function (wsurl) { 969 | // When the socket is open, this client will send the CONNECT WireMessage using the saved parameters. 970 | if (this.connectOptions.useSSL) { 971 | var uriParts = wsurl.split(":"); 972 | uriParts[0] = "wss"; 973 | wsurl = uriParts.join(":"); 974 | } 975 | this.connected = false; 976 | if (this.connectOptions.mqttVersion < 4) { 977 | this.socket = new WebSocket(wsurl, ["mqttv3.1"]); 978 | } else { 979 | this.socket = new WebSocket(wsurl, ["mqtt"]); 980 | } 981 | this.socket.binaryType = 'arraybuffer'; 982 | 983 | this.socket.onopen = scope(this._on_socket_open, this); 984 | this.socket.onmessage = scope(this._on_socket_message, this); 985 | this.socket.onerror = scope(this._on_socket_error, this); 986 | this.socket.onclose = scope(this._on_socket_close, this); 987 | 988 | this.sendPinger = new Pinger(this, window, this.connectOptions.keepAliveInterval); 989 | this.receivePinger = new Pinger(this, window, this.connectOptions.keepAliveInterval); 990 | 991 | this._connectTimeout = new Timeout(this, window, this.connectOptions.timeout, this._disconnected, [ERROR.CONNECT_TIMEOUT.code, format(ERROR.CONNECT_TIMEOUT)]); 992 | }; 993 | 994 | 995 | // Schedule a new message to be sent over the WebSockets 996 | // connection. CONNECT messages cause WebSocket connection 997 | // to be started. All other messages are queued internally 998 | // until this has happened. When WS connection starts, process 999 | // all outstanding messages. 1000 | ClientImpl.prototype._schedule_message = function (message) { 1001 | this._msg_queue.push(message); 1002 | // Process outstanding messages in the queue if we have an open socket, and have received CONNACK. 1003 | if (this.connected) { 1004 | this._process_queue(); 1005 | } 1006 | }; 1007 | 1008 | ClientImpl.prototype.store = function(prefix, wireMessage) { 1009 | var storedMessage = {type:wireMessage.type, messageIdentifier:wireMessage.messageIdentifier, version:1}; 1010 | 1011 | switch(wireMessage.type) { 1012 | case MESSAGE_TYPE.PUBLISH: 1013 | if(wireMessage.pubRecReceived) 1014 | storedMessage.pubRecReceived = true; 1015 | 1016 | // Convert the payload to a hex string. 1017 | storedMessage.payloadMessage = {}; 1018 | var hex = ""; 1019 | var messageBytes = wireMessage.payloadMessage.payloadBytes; 1020 | for (var i=0; i= 2) { 1063 | var x = parseInt(hex.substring(0, 2), 16); 1064 | hex = hex.substring(2, hex.length); 1065 | byteStream[i++] = x; 1066 | } 1067 | var payloadMessage = new Paho.MQTT.Message(byteStream); 1068 | 1069 | payloadMessage.qos = storedMessage.payloadMessage.qos; 1070 | payloadMessage.destinationName = storedMessage.payloadMessage.destinationName; 1071 | if (storedMessage.payloadMessage.duplicate) 1072 | payloadMessage.duplicate = true; 1073 | if (storedMessage.payloadMessage.retained) 1074 | payloadMessage.retained = true; 1075 | wireMessage.payloadMessage = payloadMessage; 1076 | 1077 | break; 1078 | 1079 | default: 1080 | throw Error(format(ERROR.INVALID_STORED_DATA, [key, value])); 1081 | } 1082 | 1083 | if (key.indexOf("Sent:"+this._localKey) == 0) { 1084 | wireMessage.payloadMessage.duplicate = true; 1085 | this._sentMessages[wireMessage.messageIdentifier] = wireMessage; 1086 | } else if (key.indexOf("Received:"+this._localKey) == 0) { 1087 | this._receivedMessages[wireMessage.messageIdentifier] = wireMessage; 1088 | } 1089 | }; 1090 | 1091 | ClientImpl.prototype._process_queue = function () { 1092 | var message = null; 1093 | // Process messages in order they were added 1094 | var fifo = this._msg_queue.reverse(); 1095 | 1096 | // Send all queued messages down socket connection 1097 | while ((message = fifo.pop())) { 1098 | this._socket_send(message); 1099 | // Notify listeners that message was successfully sent 1100 | if (this._notify_msg_sent[message]) { 1101 | this._notify_msg_sent[message](); 1102 | delete this._notify_msg_sent[message]; 1103 | } 1104 | } 1105 | }; 1106 | 1107 | /** 1108 | * Expect an ACK response for this message. Add message to the set of in progress 1109 | * messages and set an unused identifier in this message. 1110 | * @ignore 1111 | */ 1112 | ClientImpl.prototype._requires_ack = function (wireMessage) { 1113 | var messageCount = Object.keys(this._sentMessages).length; 1114 | if (messageCount > this.maxMessageIdentifier) 1115 | throw Error ("Too many messages:"+messageCount); 1116 | 1117 | while(this._sentMessages[this._message_identifier] !== undefined) { 1118 | this._message_identifier++; 1119 | } 1120 | wireMessage.messageIdentifier = this._message_identifier; 1121 | this._sentMessages[wireMessage.messageIdentifier] = wireMessage; 1122 | if (wireMessage.type === MESSAGE_TYPE.PUBLISH) { 1123 | this.store("Sent:", wireMessage); 1124 | } 1125 | if (this._message_identifier === this.maxMessageIdentifier) { 1126 | this._message_identifier = 1; 1127 | } 1128 | }; 1129 | 1130 | /** 1131 | * Called when the underlying websocket has been opened. 1132 | * @ignore 1133 | */ 1134 | ClientImpl.prototype._on_socket_open = function () { 1135 | // Create the CONNECT message object. 1136 | var wireMessage = new WireMessage(MESSAGE_TYPE.CONNECT, this.connectOptions); 1137 | wireMessage.clientId = this.clientId; 1138 | this._socket_send(wireMessage); 1139 | }; 1140 | 1141 | /** 1142 | * Called when the underlying websocket has received a complete packet. 1143 | * @ignore 1144 | */ 1145 | ClientImpl.prototype._on_socket_message = function (event) { 1146 | this._trace("Client._on_socket_message", event.data); 1147 | // Reset the receive ping timer, we now have evidence the server is alive. 1148 | this.receivePinger.reset(); 1149 | var messages = this._deframeMessages(event.data); 1150 | for (var i = 0; i < messages.length; i+=1) { 1151 | this._handleMessage(messages[i]); 1152 | } 1153 | } 1154 | 1155 | ClientImpl.prototype._deframeMessages = function(data) { 1156 | var byteArray = new Uint8Array(data); 1157 | if (this.receiveBuffer) { 1158 | var newData = new Uint8Array(this.receiveBuffer.length+byteArray.length); 1159 | newData.set(this.receiveBuffer); 1160 | newData.set(byteArray,this.receiveBuffer.length); 1161 | byteArray = newData; 1162 | delete this.receiveBuffer; 1163 | } 1164 | try { 1165 | var offset = 0; 1166 | var messages = []; 1167 | while(offset < byteArray.length) { 1168 | var result = decodeMessage(byteArray,offset); 1169 | var wireMessage = result[0]; 1170 | offset = result[1]; 1171 | if (wireMessage !== null) { 1172 | messages.push(wireMessage); 1173 | } else { 1174 | break; 1175 | } 1176 | } 1177 | if (offset < byteArray.length) { 1178 | this.receiveBuffer = byteArray.subarray(offset); 1179 | } 1180 | } catch (error) { 1181 | this._disconnected(ERROR.INTERNAL_ERROR.code , format(ERROR.INTERNAL_ERROR, [error.message,error.stack.toString()])); 1182 | return; 1183 | } 1184 | return messages; 1185 | } 1186 | 1187 | ClientImpl.prototype._handleMessage = function(wireMessage) { 1188 | 1189 | this._trace("Client._handleMessage", wireMessage); 1190 | 1191 | try { 1192 | switch(wireMessage.type) { 1193 | case MESSAGE_TYPE.CONNACK: 1194 | this._connectTimeout.cancel(); 1195 | 1196 | // If we have started using clean session then clear up the local state. 1197 | if (this.connectOptions.cleanSession) { 1198 | for (var key in this._sentMessages) { 1199 | var sentMessage = this._sentMessages[key]; 1200 | localStorage.removeItem("Sent:"+this._localKey+sentMessage.messageIdentifier); 1201 | } 1202 | this._sentMessages = {}; 1203 | 1204 | for (var key in this._receivedMessages) { 1205 | var receivedMessage = this._receivedMessages[key]; 1206 | localStorage.removeItem("Received:"+this._localKey+receivedMessage.messageIdentifier); 1207 | } 1208 | this._receivedMessages = {}; 1209 | } 1210 | // Client connected and ready for business. 1211 | if (wireMessage.returnCode === 0) { 1212 | this.connected = true; 1213 | // Jump to the end of the list of uris and stop looking for a good host. 1214 | if (this.connectOptions.uris) 1215 | this.hostIndex = this.connectOptions.uris.length; 1216 | } else { 1217 | this._disconnected(ERROR.CONNACK_RETURNCODE.code , format(ERROR.CONNACK_RETURNCODE, [wireMessage.returnCode, CONNACK_RC[wireMessage.returnCode]])); 1218 | break; 1219 | } 1220 | 1221 | // Resend messages. 1222 | var sequencedMessages = new Array(); 1223 | for (var msgId in this._sentMessages) { 1224 | if (this._sentMessages.hasOwnProperty(msgId)) 1225 | sequencedMessages.push(this._sentMessages[msgId]); 1226 | } 1227 | 1228 | // Sort sentMessages into the original sent order. 1229 | var sequencedMessages = sequencedMessages.sort(function(a,b) {return a.sequence - b.sequence;} ); 1230 | for (var i=0, len=sequencedMessages.length; i 1515 | * Most applications will create just one Client object and then call its connect() method, 1516 | * however applications can create more than one Client object if they wish. 1517 | * In this case the combination of host, port and clientId attributes must be different for each Client object. 1518 | *

1519 | * The send, subscribe and unsubscribe methods are implemented as asynchronous JavaScript methods 1520 | * (even though the underlying protocol exchange might be synchronous in nature). 1521 | * This means they signal their completion by calling back to the application, 1522 | * via Success or Failure callback functions provided by the application on the method in question. 1523 | * Such callbacks are called at most once per method invocation and do not persist beyond the lifetime 1524 | * of the script that made the invocation. 1525 | *

1526 | * In contrast there are some callback functions, most notably onMessageArrived, 1527 | * that are defined on the {@link Paho.MQTT.Client} object. 1528 | * These may get called multiple times, and aren't directly related to specific method invocations made by the client. 1529 | * 1530 | * @name Paho.MQTT.Client 1531 | * 1532 | * @constructor 1533 | * 1534 | * @param {string} host - the address of the messaging server, as a fully qualified WebSocket URI, as a DNS name or dotted decimal IP address. 1535 | * @param {number} port - the port number to connect to - only required if host is not a URI 1536 | * @param {string} path - the path on the host to connect to - only used if host is not a URI. Default: '/mqtt'. 1537 | * @param {string} clientId - the Messaging client identifier, between 1 and 23 characters in length. 1538 | * 1539 | * @property {string} host - read only the server's DNS hostname or dotted decimal IP address. 1540 | * @property {number} port - read only the server's port. 1541 | * @property {string} path - read only the server's path. 1542 | * @property {string} clientId - read only used when connecting to the server. 1543 | * @property {function} onConnectionLost - called when a connection has been lost. 1544 | * after a connect() method has succeeded. 1545 | * Establish the call back used when a connection has been lost. The connection may be 1546 | * lost because the client initiates a disconnect or because the server or network 1547 | * cause the client to be disconnected. The disconnect call back may be called without 1548 | * the connectionComplete call back being invoked if, for example the client fails to 1549 | * connect. 1550 | * A single response object parameter is passed to the onConnectionLost callback containing the following fields: 1551 | *

    1552 | *
  1. errorCode 1553 | *
  2. errorMessage 1554 | *
1555 | * @property {function} onMessageDelivered called when a message has been delivered. 1556 | * All processing that this Client will ever do has been completed. So, for example, 1557 | * in the case of a Qos=2 message sent by this client, the PubComp flow has been received from the server 1558 | * and the message has been removed from persistent storage before this callback is invoked. 1559 | * Parameters passed to the onMessageDelivered callback are: 1560 | *
    1561 | *
  1. {@link Paho.MQTT.Message} that was delivered. 1562 | *
1563 | * @property {function} onMessageArrived called when a message has arrived in this Paho.MQTT.client. 1564 | * Parameters passed to the onMessageArrived callback are: 1565 | *
    1566 | *
  1. {@link Paho.MQTT.Message} that has arrived. 1567 | *
1568 | */ 1569 | var Client = function (host, port, path, clientId) { 1570 | 1571 | var uri; 1572 | 1573 | if (typeof host !== "string") 1574 | throw new Error(format(ERROR.INVALID_TYPE, [typeof host, "host"])); 1575 | 1576 | if (arguments.length == 2) { 1577 | // host: must be full ws:// uri 1578 | // port: clientId 1579 | clientId = port; 1580 | uri = host; 1581 | var match = uri.match(/^(wss?):\/\/((\[(.+)\])|([^\/]+?))(:(\d+))?(\/.*)$/); 1582 | if (match) { 1583 | host = match[4]||match[2]; 1584 | port = parseInt(match[7]); 1585 | path = match[8]; 1586 | } else { 1587 | throw new Error(format(ERROR.INVALID_ARGUMENT,[host,"host"])); 1588 | } 1589 | } else { 1590 | if (arguments.length == 3) { 1591 | clientId = path; 1592 | path = "/mqtt"; 1593 | } 1594 | if (typeof port !== "number" || port < 0) 1595 | throw new Error(format(ERROR.INVALID_TYPE, [typeof port, "port"])); 1596 | if (typeof path !== "string") 1597 | throw new Error(format(ERROR.INVALID_TYPE, [typeof path, "path"])); 1598 | 1599 | var ipv6AddSBracket = (host.indexOf(":") != -1 && host.slice(0,1) != "[" && host.slice(-1) != "]"); 1600 | uri = "ws://"+(ipv6AddSBracket?"["+host+"]":host)+":"+port+path; 1601 | } 1602 | 1603 | var clientIdLength = 0; 1604 | for (var i = 0; i 65535) 1612 | throw new Error(format(ERROR.INVALID_ARGUMENT, [clientId, "clientId"])); 1613 | 1614 | var client = new ClientImpl(uri, host, port, path, clientId); 1615 | this._getHost = function() { return host; }; 1616 | this._setHost = function() { throw new Error(format(ERROR.UNSUPPORTED_OPERATION)); }; 1617 | 1618 | this._getPort = function() { return port; }; 1619 | this._setPort = function() { throw new Error(format(ERROR.UNSUPPORTED_OPERATION)); }; 1620 | 1621 | this._getPath = function() { return path; }; 1622 | this._setPath = function() { throw new Error(format(ERROR.UNSUPPORTED_OPERATION)); }; 1623 | 1624 | this._getURI = function() { return uri; }; 1625 | this._setURI = function() { throw new Error(format(ERROR.UNSUPPORTED_OPERATION)); }; 1626 | 1627 | this._getClientId = function() { return client.clientId; }; 1628 | this._setClientId = function() { throw new Error(format(ERROR.UNSUPPORTED_OPERATION)); }; 1629 | 1630 | this._getOnConnectionLost = function() { return client.onConnectionLost; }; 1631 | this._setOnConnectionLost = function(newOnConnectionLost) { 1632 | if (typeof newOnConnectionLost === "function") 1633 | client.onConnectionLost = newOnConnectionLost; 1634 | else 1635 | throw new Error(format(ERROR.INVALID_TYPE, [typeof newOnConnectionLost, "onConnectionLost"])); 1636 | }; 1637 | 1638 | this._getOnMessageDelivered = function() { return client.onMessageDelivered; }; 1639 | this._setOnMessageDelivered = function(newOnMessageDelivered) { 1640 | if (typeof newOnMessageDelivered === "function") 1641 | client.onMessageDelivered = newOnMessageDelivered; 1642 | else 1643 | throw new Error(format(ERROR.INVALID_TYPE, [typeof newOnMessageDelivered, "onMessageDelivered"])); 1644 | }; 1645 | 1646 | this._getOnMessageArrived = function() { return client.onMessageArrived; }; 1647 | this._setOnMessageArrived = function(newOnMessageArrived) { 1648 | if (typeof newOnMessageArrived === "function") 1649 | client.onMessageArrived = newOnMessageArrived; 1650 | else 1651 | throw new Error(format(ERROR.INVALID_TYPE, [typeof newOnMessageArrived, "onMessageArrived"])); 1652 | }; 1653 | 1654 | this._getTrace = function() { return client.traceFunction; }; 1655 | this._setTrace = function(trace) { 1656 | if(typeof trace === "function"){ 1657 | client.traceFunction = trace; 1658 | }else{ 1659 | throw new Error(format(ERROR.INVALID_TYPE, [typeof trace, "onTrace"])); 1660 | } 1661 | }; 1662 | 1663 | /** 1664 | * Connect this Messaging client to its server. 1665 | * 1666 | * @name Paho.MQTT.Client#connect 1667 | * @function 1668 | * @param {Object} connectOptions - attributes used with the connection. 1669 | * @param {number} connectOptions.timeout - If the connect has not succeeded within this 1670 | * number of seconds, it is deemed to have failed. 1671 | * The default is 30 seconds. 1672 | * @param {string} connectOptions.userName - Authentication username for this connection. 1673 | * @param {string} connectOptions.password - Authentication password for this connection. 1674 | * @param {Paho.MQTT.Message} connectOptions.willMessage - sent by the server when the client 1675 | * disconnects abnormally. 1676 | * @param {Number} connectOptions.keepAliveInterval - the server disconnects this client if 1677 | * there is no activity for this number of seconds. 1678 | * The default value of 60 seconds is assumed if not set. 1679 | * @param {boolean} connectOptions.cleanSession - if true(default) the client and server 1680 | * persistent state is deleted on successful connect. 1681 | * @param {boolean} connectOptions.useSSL - if present and true, use an SSL Websocket connection. 1682 | * @param {object} connectOptions.invocationContext - passed to the onSuccess callback or onFailure callback. 1683 | * @param {function} connectOptions.onSuccess - called when the connect acknowledgement 1684 | * has been received from the server. 1685 | * A single response object parameter is passed to the onSuccess callback containing the following fields: 1686 | *
    1687 | *
  1. invocationContext as passed in to the onSuccess method in the connectOptions. 1688 | *
1689 | * @config {function} [onFailure] called when the connect request has failed or timed out. 1690 | * A single response object parameter is passed to the onFailure callback containing the following fields: 1691 | *
    1692 | *
  1. invocationContext as passed in to the onFailure method in the connectOptions. 1693 | *
  2. errorCode a number indicating the nature of the error. 1694 | *
  3. errorMessage text describing the error. 1695 | *
1696 | * @config {Array} [hosts] If present this contains either a set of hostnames or fully qualified 1697 | * WebSocket URIs (ws://example.com:1883/mqtt), that are tried in order in place 1698 | * of the host and port paramater on the construtor. The hosts are tried one at at time in order until 1699 | * one of then succeeds. 1700 | * @config {Array} [ports] If present the set of ports matching the hosts. If hosts contains URIs, this property 1701 | * is not used. 1702 | * @throws {InvalidState} if the client is not in disconnected state. The client must have received connectionLost 1703 | * or disconnected before calling connect for a second or subsequent time. 1704 | */ 1705 | this.connect = function (connectOptions) { 1706 | connectOptions = connectOptions || {} ; 1707 | validate(connectOptions, {timeout:"number", 1708 | userName:"string", 1709 | password:"string", 1710 | willMessage:"object", 1711 | keepAliveInterval:"number", 1712 | cleanSession:"boolean", 1713 | useSSL:"boolean", 1714 | invocationContext:"object", 1715 | onSuccess:"function", 1716 | onFailure:"function", 1717 | hosts:"object", 1718 | ports:"object", 1719 | mqttVersion:"number"}); 1720 | 1721 | // If no keep alive interval is set, assume 60 seconds. 1722 | if (connectOptions.keepAliveInterval === undefined) 1723 | connectOptions.keepAliveInterval = 60; 1724 | 1725 | if (connectOptions.mqttVersion > 4 || connectOptions.mqttVersion < 3) { 1726 | throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.mqttVersion, "connectOptions.mqttVersion"])); 1727 | } 1728 | 1729 | if (connectOptions.mqttVersion === undefined) { 1730 | connectOptions.mqttVersionExplicit = false; 1731 | connectOptions.mqttVersion = 4; 1732 | } else { 1733 | connectOptions.mqttVersionExplicit = true; 1734 | } 1735 | 1736 | //Check that if password is set, so is username 1737 | if (connectOptions.password === undefined && connectOptions.userName !== undefined) 1738 | throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.password, "connectOptions.password"])) 1739 | 1740 | if (connectOptions.willMessage) { 1741 | if (!(connectOptions.willMessage instanceof Message)) 1742 | throw new Error(format(ERROR.INVALID_TYPE, [connectOptions.willMessage, "connectOptions.willMessage"])); 1743 | // The will message must have a payload that can be represented as a string. 1744 | // Cause the willMessage to throw an exception if this is not the case. 1745 | connectOptions.willMessage.stringPayload; 1746 | 1747 | if (typeof connectOptions.willMessage.destinationName === "undefined") 1748 | throw new Error(format(ERROR.INVALID_TYPE, [typeof connectOptions.willMessage.destinationName, "connectOptions.willMessage.destinationName"])); 1749 | } 1750 | if (typeof connectOptions.cleanSession === "undefined") 1751 | connectOptions.cleanSession = true; 1752 | if (connectOptions.hosts) { 1753 | 1754 | if (!(connectOptions.hosts instanceof Array) ) 1755 | throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.hosts, "connectOptions.hosts"])); 1756 | if (connectOptions.hosts.length <1 ) 1757 | throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.hosts, "connectOptions.hosts"])); 1758 | 1759 | var usingURIs = false; 1760 | for (var i = 0; i 1809 | * @param {object} subscribeOptions - used to control the subscription 1810 | * 1811 | * @param {number} subscribeOptions.qos - the maiximum qos of any publications sent 1812 | * as a result of making this subscription. 1813 | * @param {object} subscribeOptions.invocationContext - passed to the onSuccess callback 1814 | * or onFailure callback. 1815 | * @param {function} subscribeOptions.onSuccess - called when the subscribe acknowledgement 1816 | * has been received from the server. 1817 | * A single response object parameter is passed to the onSuccess callback containing the following fields: 1818 | *
    1819 | *
  1. invocationContext if set in the subscribeOptions. 1820 | *
1821 | * @param {function} subscribeOptions.onFailure - called when the subscribe request has failed or timed out. 1822 | * A single response object parameter is passed to the onFailure callback containing the following fields: 1823 | *
    1824 | *
  1. invocationContext - if set in the subscribeOptions. 1825 | *
  2. errorCode - a number indicating the nature of the error. 1826 | *
  3. errorMessage - text describing the error. 1827 | *
1828 | * @param {number} subscribeOptions.timeout - which, if present, determines the number of 1829 | * seconds after which the onFailure calback is called. 1830 | * The presence of a timeout does not prevent the onSuccess 1831 | * callback from being called when the subscribe completes. 1832 | * @throws {InvalidState} if the client is not in connected state. 1833 | */ 1834 | this.subscribe = function (filter, subscribeOptions) { 1835 | if (typeof filter !== "string") 1836 | throw new Error("Invalid argument:"+filter); 1837 | subscribeOptions = subscribeOptions || {} ; 1838 | validate(subscribeOptions, {qos:"number", 1839 | invocationContext:"object", 1840 | onSuccess:"function", 1841 | onFailure:"function", 1842 | timeout:"number" 1843 | }); 1844 | if (subscribeOptions.timeout && !subscribeOptions.onFailure) 1845 | throw new Error("subscribeOptions.timeout specified with no onFailure callback."); 1846 | if (typeof subscribeOptions.qos !== "undefined" 1847 | && !(subscribeOptions.qos === 0 || subscribeOptions.qos === 1 || subscribeOptions.qos === 2 )) 1848 | throw new Error(format(ERROR.INVALID_ARGUMENT, [subscribeOptions.qos, "subscribeOptions.qos"])); 1849 | client.subscribe(filter, subscribeOptions); 1850 | }; 1851 | 1852 | /** 1853 | * Unsubscribe for messages, stop receiving messages sent to destinations described by the filter. 1854 | * 1855 | * @name Paho.MQTT.Client#unsubscribe 1856 | * @function 1857 | * @param {string} filter - describing the destinations to receive messages from. 1858 | * @param {object} unsubscribeOptions - used to control the subscription 1859 | * @param {object} unsubscribeOptions.invocationContext - passed to the onSuccess callback 1860 | or onFailure callback. 1861 | * @param {function} unsubscribeOptions.onSuccess - called when the unsubscribe acknowledgement has been received from the server. 1862 | * A single response object parameter is passed to the 1863 | * onSuccess callback containing the following fields: 1864 | *
    1865 | *
  1. invocationContext - if set in the unsubscribeOptions. 1866 | *
1867 | * @param {function} unsubscribeOptions.onFailure called when the unsubscribe request has failed or timed out. 1868 | * A single response object parameter is passed to the onFailure callback containing the following fields: 1869 | *
    1870 | *
  1. invocationContext - if set in the unsubscribeOptions. 1871 | *
  2. errorCode - a number indicating the nature of the error. 1872 | *
  3. errorMessage - text describing the error. 1873 | *
1874 | * @param {number} unsubscribeOptions.timeout - which, if present, determines the number of seconds 1875 | * after which the onFailure callback is called. The presence of 1876 | * a timeout does not prevent the onSuccess callback from being 1877 | * called when the unsubscribe completes 1878 | * @throws {InvalidState} if the client is not in connected state. 1879 | */ 1880 | this.unsubscribe = function (filter, unsubscribeOptions) { 1881 | if (typeof filter !== "string") 1882 | throw new Error("Invalid argument:"+filter); 1883 | unsubscribeOptions = unsubscribeOptions || {} ; 1884 | validate(unsubscribeOptions, {invocationContext:"object", 1885 | onSuccess:"function", 1886 | onFailure:"function", 1887 | timeout:"number" 1888 | }); 1889 | if (unsubscribeOptions.timeout && !unsubscribeOptions.onFailure) 1890 | throw new Error("unsubscribeOptions.timeout specified with no onFailure callback."); 1891 | client.unsubscribe(filter, unsubscribeOptions); 1892 | }; 1893 | 1894 | /** 1895 | * Send a message to the consumers of the destination in the Message. 1896 | * 1897 | * @name Paho.MQTT.Client#send 1898 | * @function 1899 | * @param {string|Paho.MQTT.Message} topic - mandatory The name of the destination to which the message is to be sent. 1900 | * - If it is the only parameter, used as Paho.MQTT.Message object. 1901 | * @param {String|ArrayBuffer} payload - The message data to be sent. 1902 | * @param {number} qos The Quality of Service used to deliver the message. 1903 | *
1904 | *
0 Best effort (default). 1905 | *
1 At least once. 1906 | *
2 Exactly once. 1907 | *
1908 | * @param {Boolean} retained If true, the message is to be retained by the server and delivered 1909 | * to both current and future subscriptions. 1910 | * If false the server only delivers the message to current subscribers, this is the default for new Messages. 1911 | * A received message has the retained boolean set to true if the message was published 1912 | * with the retained boolean set to true 1913 | * and the subscrption was made after the message has been published. 1914 | * @throws {InvalidState} if the client is not connected. 1915 | */ 1916 | this.send = function (topic,payload,qos,retained) { 1917 | var message ; 1918 | 1919 | if(arguments.length == 0){ 1920 | throw new Error("Invalid argument."+"length"); 1921 | 1922 | }else if(arguments.length == 1) { 1923 | 1924 | if (!(topic instanceof Message) && (typeof topic !== "string")) 1925 | throw new Error("Invalid argument:"+ typeof topic); 1926 | 1927 | message = topic; 1928 | if (typeof message.destinationName === "undefined") 1929 | throw new Error(format(ERROR.INVALID_ARGUMENT,[message.destinationName,"Message.destinationName"])); 1930 | client.send(message); 1931 | 1932 | }else { 1933 | //parameter checking in Message object 1934 | message = new Message(payload); 1935 | message.destinationName = topic; 1936 | if(arguments.length >= 3) 1937 | message.qos = qos; 1938 | if(arguments.length >= 4) 1939 | message.retained = retained; 1940 | client.send(message); 1941 | } 1942 | }; 1943 | 1944 | /** 1945 | * Normal disconnect of this Messaging client from its server. 1946 | * 1947 | * @name Paho.MQTT.Client#disconnect 1948 | * @function 1949 | * @throws {InvalidState} if the client is already disconnected. 1950 | */ 1951 | this.disconnect = function () { 1952 | client.disconnect(); 1953 | }; 1954 | 1955 | /** 1956 | * Get the contents of the trace log. 1957 | * 1958 | * @name Paho.MQTT.Client#getTraceLog 1959 | * @function 1960 | * @return {Object[]} tracebuffer containing the time ordered trace records. 1961 | */ 1962 | this.getTraceLog = function () { 1963 | return client.getTraceLog(); 1964 | } 1965 | 1966 | /** 1967 | * Start tracing. 1968 | * 1969 | * @name Paho.MQTT.Client#startTrace 1970 | * @function 1971 | */ 1972 | this.startTrace = function () { 1973 | client.startTrace(); 1974 | }; 1975 | 1976 | /** 1977 | * Stop tracing. 1978 | * 1979 | * @name Paho.MQTT.Client#stopTrace 1980 | * @function 1981 | */ 1982 | this.stopTrace = function () { 1983 | client.stopTrace(); 1984 | }; 1985 | 1986 | this.isConnected = function() { 1987 | return client.connected; 1988 | }; 1989 | }; 1990 | 1991 | Client.prototype = { 1992 | get host() { return this._getHost(); }, 1993 | set host(newHost) { this._setHost(newHost); }, 1994 | 1995 | get port() { return this._getPort(); }, 1996 | set port(newPort) { this._setPort(newPort); }, 1997 | 1998 | get path() { return this._getPath(); }, 1999 | set path(newPath) { this._setPath(newPath); }, 2000 | 2001 | get clientId() { return this._getClientId(); }, 2002 | set clientId(newClientId) { this._setClientId(newClientId); }, 2003 | 2004 | get onConnectionLost() { return this._getOnConnectionLost(); }, 2005 | set onConnectionLost(newOnConnectionLost) { this._setOnConnectionLost(newOnConnectionLost); }, 2006 | 2007 | get onMessageDelivered() { return this._getOnMessageDelivered(); }, 2008 | set onMessageDelivered(newOnMessageDelivered) { this._setOnMessageDelivered(newOnMessageDelivered); }, 2009 | 2010 | get onMessageArrived() { return this._getOnMessageArrived(); }, 2011 | set onMessageArrived(newOnMessageArrived) { this._setOnMessageArrived(newOnMessageArrived); }, 2012 | 2013 | get trace() { return this._getTrace(); }, 2014 | set trace(newTraceFunction) { this._setTrace(newTraceFunction); } 2015 | 2016 | }; 2017 | 2018 | /** 2019 | * An application message, sent or received. 2020 | *

2021 | * All attributes may be null, which implies the default values. 2022 | * 2023 | * @name Paho.MQTT.Message 2024 | * @constructor 2025 | * @param {String|ArrayBuffer} payload The message data to be sent. 2026 | *

2027 | * @property {string} payloadString read only The payload as a string if the payload consists of valid UTF-8 characters. 2028 | * @property {ArrayBuffer} payloadBytes read only The payload as an ArrayBuffer. 2029 | *

2030 | * @property {string} destinationName mandatory The name of the destination to which the message is to be sent 2031 | * (for messages about to be sent) or the name of the destination from which the message has been received. 2032 | * (for messages received by the onMessage function). 2033 | *

2034 | * @property {number} qos The Quality of Service used to deliver the message. 2035 | *

2036 | *
0 Best effort (default). 2037 | *
1 At least once. 2038 | *
2 Exactly once. 2039 | *
2040 | *

2041 | * @property {Boolean} retained If true, the message is to be retained by the server and delivered 2042 | * to both current and future subscriptions. 2043 | * If false the server only delivers the message to current subscribers, this is the default for new Messages. 2044 | * A received message has the retained boolean set to true if the message was published 2045 | * with the retained boolean set to true 2046 | * and the subscrption was made after the message has been published. 2047 | *

2048 | * @property {Boolean} duplicate read only If true, this message might be a duplicate of one which has already been received. 2049 | * This is only set on messages received from the server. 2050 | * 2051 | */ 2052 | var Message = function (newPayload) { 2053 | var payload; 2054 | if ( typeof newPayload === "string" 2055 | || newPayload instanceof ArrayBuffer 2056 | || newPayload instanceof Int8Array 2057 | || newPayload instanceof Uint8Array 2058 | || newPayload instanceof Int16Array 2059 | || newPayload instanceof Uint16Array 2060 | || newPayload instanceof Int32Array 2061 | || newPayload instanceof Uint32Array 2062 | || newPayload instanceof Float32Array 2063 | || newPayload instanceof Float64Array 2064 | ) { 2065 | payload = newPayload; 2066 | } else { 2067 | throw (format(ERROR.INVALID_ARGUMENT, [newPayload, "newPayload"])); 2068 | } 2069 | 2070 | this._getPayloadString = function () { 2071 | if (typeof payload === "string") 2072 | return payload; 2073 | else 2074 | return parseUTF8(payload, 0, payload.length); 2075 | }; 2076 | 2077 | this._getPayloadBytes = function() { 2078 | if (typeof payload === "string") { 2079 | var buffer = new ArrayBuffer(UTF8Length(payload)); 2080 | var byteStream = new Uint8Array(buffer); 2081 | stringToUTF8(payload, byteStream, 0); 2082 | 2083 | return byteStream; 2084 | } else { 2085 | return payload; 2086 | }; 2087 | }; 2088 | 2089 | var destinationName = undefined; 2090 | this._getDestinationName = function() { return destinationName; }; 2091 | this._setDestinationName = function(newDestinationName) { 2092 | if (typeof newDestinationName === "string") 2093 | destinationName = newDestinationName; 2094 | else 2095 | throw new Error(format(ERROR.INVALID_ARGUMENT, [newDestinationName, "newDestinationName"])); 2096 | }; 2097 | 2098 | var qos = 0; 2099 | this._getQos = function() { return qos; }; 2100 | this._setQos = function(newQos) { 2101 | if (newQos === 0 || newQos === 1 || newQos === 2 ) 2102 | qos = newQos; 2103 | else 2104 | throw new Error("Invalid argument:"+newQos); 2105 | }; 2106 | 2107 | var retained = false; 2108 | this._getRetained = function() { return retained; }; 2109 | this._setRetained = function(newRetained) { 2110 | if (typeof newRetained === "boolean") 2111 | retained = newRetained; 2112 | else 2113 | throw new Error(format(ERROR.INVALID_ARGUMENT, [newRetained, "newRetained"])); 2114 | }; 2115 | 2116 | var duplicate = false; 2117 | this._getDuplicate = function() { return duplicate; }; 2118 | this._setDuplicate = function(newDuplicate) { duplicate = newDuplicate; }; 2119 | }; 2120 | 2121 | Message.prototype = { 2122 | get payloadString() { return this._getPayloadString(); }, 2123 | get payloadBytes() { return this._getPayloadBytes(); }, 2124 | 2125 | get destinationName() { return this._getDestinationName(); }, 2126 | set destinationName(newDestinationName) { this._setDestinationName(newDestinationName); }, 2127 | 2128 | get qos() { return this._getQos(); }, 2129 | set qos(newQos) { this._setQos(newQos); }, 2130 | 2131 | get retained() { return this._getRetained(); }, 2132 | set retained(newRetained) { this._setRetained(newRetained); }, 2133 | 2134 | get duplicate() { return this._getDuplicate(); }, 2135 | set duplicate(newDuplicate) { this._setDuplicate(newDuplicate); } 2136 | }; 2137 | 2138 | // Module contents. 2139 | return { 2140 | Client: Client, 2141 | Message: Message 2142 | }; 2143 | })(window); 2144 | -------------------------------------------------------------------------------- /mqtt/web-interface/style.css: -------------------------------------------------------------------------------- 1 | .bulb { 2 | width: 216px; 3 | height: 305px; 4 | display: block; 5 | margin-top: 20px; 6 | margin-left: auto; 7 | margin-right: auto 8 | } 9 | 10 | img { 11 | position: absolute; 12 | } 13 | 14 | img.intensity { 15 | opacity: 0; 16 | } 17 | -------------------------------------------------------------------------------- /mqtt/web-interface/webpanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arduino/cloud-examples/fd19106aa900df5f591f50b4bb61ed1f7545df77/mqtt/web-interface/webpanel.png --------------------------------------------------------------------------------