Changed from UDP to HTTP

Implemented access point, station mode and basic web configuration page
Actual lighting control is completely broken
This commit is contained in:
Mark van Renswoude 2018-01-01 19:56:07 +01:00
parent 3099dd8a0e
commit f87a8b6eb7
126 changed files with 3851 additions and 10947 deletions

7
.gitignore vendored
View File

@ -1,9 +1,4 @@
.pioenvs
.piolibdeps
src/credentials.h
*.sublime-workspace
web/node_modules/
web/update/
src/version.h
web/version.js
web/static/bower_components/
node_modules

57
DEVELOPING.md Normal file
View File

@ -0,0 +1,57 @@
# Stairs
This Stairs firmware was developed using [PlatformIO Core](http://platformio.org/). You can probably use the PlatformIO IDE as well, although I have no experience using it, so this guide will only use the command line tools.
## Programming the ESP8266
You can either use an ESP8266 module with built-in USB like the Wemos D1, a programming fixture (my method of choice, search for "esp8266 fixture" on Google or AliExpress) or wire it up yourself using a CH340 or FTDI USB-to-serial module.
To upload the code, open a console, go to the Stairs folder and run:
```
platformio run -t upload
```
It should auto-detect the USB COM port.
## Frontend development
The frontend is compiled into C++ source files so that all the files can be served directly from the ESP8266, since there is no internet connection when running in access point mode. These steps are performed by a [Gulp script](https://gulpjs.com/). The Gulp script also updates the version based on the [GitVersion](http://gitversion.readthedocs.io/en/stable/) of the working copy.
Note that GitVersion requires Windows, so some changes are probably required if you want to build on a different platform.
To get started:
1. Install [Node.js](https://nodejs.org/en/)
1. Install the [GitVersion command line](http://gitversion.readthedocs.io/en/stable/usage/command-line/) tool
1. Open a command line and navigate to the Stairs folder
1. Run ```npm update``` to install all the dependencies
### Compiling the assets
Run ```gulp``` to compile the SASS files, and embed the CSS, JavaScript, images and HTML into C++ header files located in the src\assets folder.
You may need to run ```npm install -g gulp``` to install Gulp into the global Node packages.
### Development server
To make it easier to develop the frontend, a development server is included which serves the webpages and acts as a mock service for the API.
To start the development server, run:
```node devserver.js```
You can now open the frontend on [http://localhost:3000/](http://localhost:3000/).
If you make any changes to the SCSS files, make sure to run ```gulp compileSass``` and ```gulp compileJS``` to update the CSS/JS files so your changes are visible in the development server. To keep gulp running and watch for changes in the SCSS and JS files, run ```gulp watch```
## Building and/or uploading
To rebuild all the assets and compile or upload the source in one go, two tasks have been added to the gulpfile.js:
1. ```gulp build``` first runs all the tasks run by a regular ```gulp```, then builds the source code using ```platformio run```
1. ```gulp upload``` is similar, but executes ```platformio run -t upload``` to directly upload the newly compiled source to the ESP8266

17
README.md Normal file
View File

@ -0,0 +1,17 @@
# Stairs
ESP8266 firmware for controlling up to 16 LED strips on a flight of stairs.
## Features
- Configurable using WiFi (can act as an access point or connect to a router)
- Turn on or off at specific times
- Turn on when movement is detected by connecting one or two PIR sensors
- ReST API for configuration and controlling the lights
Most notably it does not support RGB LED strips out of the box, but feel free to add support if you're up to the task!
## Further reading
- [Wiring information](WIRING.md)
- [Programming the ESP8266 and/or modifying the source](DEVELOPING.md)

View File

@ -5,18 +5,8 @@
"path": ".",
"file_exclude_patterns": ["*.sublime-project"]
}
]/*,
"build_systems":
[
{
"name": "PlatformIO - Build",
"cmd": ["platformio", "run"],
"working_dir": "$project_path"
},
{
"name": "PlatformIO - Upload",
"cmd": ["platformio", "run", "--target", "upload"],
"working_dir": "$project_path"
}
]*/
],
"completions":[
["t", "{{ \\$t('${1:}') }}"]
]
}

4
WIRING.md Normal file
View File

@ -0,0 +1,4 @@
## Bill of materials
1. ESP8266 module (I based mine on a vanilla ESP8266 ESP-12F, but friendlier modules like the Wemos D1 should work as well)
1. PCA9685 16-channel PWM module

View File

@ -1,3 +0,0 @@
& .\updateversion.ps1
& platformio run
Copy-Item .\.pioenvs\esp12e\firmware.bin .\web\update\

View File

@ -1,97 +0,0 @@
caseBottom();
$fa = 1;
$fs = 1;
module caseBottom()
{
innerX = 80;
innerY = 70;
innerZ = 35;
wallThickness = 2;
totalX = innerX + (2 * wallThickness);
totalY = innerY + (2 * wallThickness);
totalZ = innerZ + wallThickness;
difference()
{
cube([totalX, totalY, totalZ]);
translate([wallThickness, wallThickness, wallThickness])
cube([innerX, innerY, totalZ]);
// Hole for the LED cables
translate([-1, totalY / 2, 25])
rotate([0, 90, 0])
cylinder(d = 15, h = wallThickness + 2);
// Hole for the power cable
translate([62, totalY + 1, wallThickness + 2.5])
rotate([90, 0, 0])
cylinder(d = 5, h = wallThickness + 2);
}
translate([wallThickness, wallThickness, wallThickness])
{
translate([4, 4, 0])
PCA9685Mount();
translate([40, 20, 0])
ESP8266PlusPowerMount();
}
}
module PCA9685Mount()
{
totalX = 25.5;
totalY = 62.5;
pinDistanceX = 19;
pinDistanceY = 56;
pinDiameter = 2.3;
pinHeight = 3;
supportDiameter = 4;
supportHeight = 4;
offsetX = (totalX - pinDistanceX) / 2;
offsetY = (totalY - pinDistanceY) / 2;
for (x = [offsetX, offsetX + pinDistanceX])
for (y = [offsetY, offsetY + pinDistanceY])
translate([x, y, 0])
{
cylinder(d = supportDiameter, h = supportHeight);
translate([0, 0, supportHeight])
cylinder(d = pinDiameter, h = pinHeight);
}
}
// I didn't put any actual mount points in the perfboard,
// so I'll settle for some corner pieces to align it and
// use the ultimate maker's friend: hot glue.
module ESP8266PlusPowerMount()
{
innerX = 34;
innerY = 35;
cornerSize = 6;
cornerThickness = 2;
cornerHeight = 2;
totalX = innerX + (2 * cornerThickness);
totalY = innerY + (2 * cornerThickness);
difference()
{
cube([totalX, totalY, cornerHeight]);
translate([cornerThickness, cornerThickness, -1])
cube([innerX, innerY, cornerHeight + 2]);
translate([-1, cornerSize, -1])
cube([totalX + 2, totalY - (2 * cornerSize), cornerHeight + 2]);
translate([cornerSize, -1, -1])
cube([totalX - (2 * cornerSize), totalY + 2, cornerHeight + 2]);
}
}

60
devserver.js Normal file
View File

@ -0,0 +1,60 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
const express = require('express');
const app = express();
app.use(express.static('web'));
app.use(express.static('web/dist'));
app.get('/api/version', function(req, res)
{
res.send({
systemID: 'dev-server',
version: 'dev-server'
});
});
app.get('/api/connection', function(req, res)
{
res.send({
hostname: 'dev-server',
accesspoint: true,
station: true,
ssid: 'MyWiFiSSID',
password: 'supersecret',
dhcp: true,
ip: '192.168.1.234',
subnetmask: '255.255.255.0',
gateway: '192.168.1.0'
});
});
app.get('/api/connection/status', function(req, res)
{
res.send({
"ap": {
"enabled": true,
"ip": "192.168.4.1"
},
"station": {
"enabled": true,
"status": 1,
"ip": "0.0.0.0"
}
});
});
app.post('/api/connection', function(req, res)
{
res.sendStatus(200);
});
app.listen(3000, function()
{
console.log('Development server listening on port 3000')
console.log('Press Ctrl-C to stop')
});

View File

@ -1,170 +0,0 @@
The Stairs firmware on the ESP8266 can be accessed using a custom light-weight UDP protocol. It is not intended to be accessed directly from the internet, and thus there is no security on the device itself. This is by design. Authentication should in my opinion be handled by a device with more processing power, such as a Raspberry Pi.
A Node.js application is included which provides a ReST interface. It is also not intended to be accessible from the internet, and does not provide any authentication either!
Protocol
========
The default port for UDP communication is 3126. Every request message will result in a response message which is either an error, the requested information or a confirmation of the newly stored data. Each message should be a separate packet.
16-bit (word) values are expected in little endian order (least significant byte first).
Request
-------
The first byte of a request is the command. Further data depends on the command.
| Command | Name |
| ------- | ---- |
| 0x01 | Ping |
| 0x03 | GetMode |
| 0x04 | SetMode |
| 0x05 | GetRange |
| 0x06 | SetRange |
| 0xFF | UpdateFirmware |
Response
--------
A response is sent to the source address and port and starts with the Reply command.
| Command | Name |
| ------- | ---- |
| 0x02 | Reply |
The second byte is the request command for which this reply is intended, or Error if the request command was not recognized or contained invalid parameters.
| Command | Name |
| ------- | ---- |
| 0x00 | Error |
In the case of an Error, the third byte will be the actual request command (or unrecognized value).
### Ping
A no-op command which can be used to tell if the device is responding. Returns the number of steps.
Input parameters:<br>
_none_
Output parameters:<br>
**steps** (byte): The number of steps.
### GetMode
Returns the current mode.
Input parameters:<br>
_none_
Output parameters:<br>
**mode** (byte): The identifier of the current mode. See Modes below.<br>
**data** (0..n bytes): The parameters specific to the current mode. See Modes below.
### SetMode
Changed the current mode.
Input parameters:<br>
**mode** (byte): The identifier of the current mode.<br>
**data** (0..n bytes): The parameters specific to the current mode.
Output parameters:<br>
_Same as input parameters_
### GetRange
Gets the current range configuration. Each step has it's own parameters which adjust the PWM curve, which can be used to compensate for the differences in LED strips or signal strength.
The ranges are stored on the ESP8266's filesystem and will be restored after a power loss.
Input parameters:<br>
_none_
Output parameters:<br>
*useScaling* (byte): 0 (off) or 1 (on), default 1. If enabled, the brightness value will be converted to a PWM value using an exponential function. If disabled, the brightness is used as is (but still accounting for rangeStart/rangeEnd).
_repeated for each step:_<br>
*rangeStart* (word): value in range 0 (off) to 4095 (fully on), default 0. Determines the minimum PWM on value for a brightness of 1.
*rangeEnd* (word): value in range 0 (off) to 4095 (fully on), default 4094. Determines the maximum PWM on value for a brightness of 4094.
### SetRange
Sets the current range configuration.
Input parameters:<br>
_See GetRange_
Output parameters:<br>
_Same as input parameters_
### UpdateFirmware
Updates the firmware over WiFi. This functionality may be limited in the configuration which is hardcoded into the firmware. There are three modes of operation:
1. Disabled, firmware can not be updated over WiFi
2. Enabled with a hardcoded URL. You may request an update check but any source provided will be ignored.
3. Enabled with the URL as input parameters.
You can only request an update once every 5 seconds (by default), otherwise an error will be returned.
Please note that the entire packet must not exceed 254 bytes or the remainder will be discarded.
For further information on implementing an update server, see [Arduino ESP8266's HTTPUpdate reference](https://github.com/esp8266/Arduino/blob/master/doc/ota_updates/readme.md#advanced-updater-1).
Input parameters:<br>
_If enabled_
*port* (word): the port on which the HTTP update server runs
*host* (null-terminated string): the host name or IP address on which the HTTP update server runs
*path* (null-terminated string): the path to
Output parameters:<br>
1 if succesful, 0 if no updates are available.
Modes
=====
| Mode | Name |
| ---- | ---- |
| 0x01 | Static |
| 0x02 | Custom |
| 0x03 | Alternate |
| 0x04 | Slide |
### Static
Sets all steps to the same brightness.
Parameters:<br>
**brightness** (word): value in range 0 (off) to 4095 (fully on).
**easeTime** (word): the time in milliseconds to ease into the new brightness value (only applies if the mode was already set to static before).
### Custom
Sets the brightness for each of the steps individually.
Parameters:<br>
**brightness** (word[stepCount]): array of brightness values in range 0 - 4095. The number of values must be equal to the number of steps are reported in the Ping response. Bottom step first.
### Alternate
Alternates between even and odd steps being lit. Bring out our next contestant!
Parameters:<br>
**interval** (word): The time each set of steps is lit in milliseconds.<br>
**brightness** (word): value in range 0 (off) to 4095 (fully on).
### Slide
Lights one step at a time, moving up or down.
Parameters:<br>
**interval** (word): How long each step is lit before moving to the next.<br>
**brightness** (word): value in range 0 (off) to 4095 (fully on).
**direction** (byte): Determines the starting step / direction. Either Bottom/Up (0) or Top/Down (1).<br>
**fadeOutTime** (word): If greater than 0 each step will fade out instead of turning off instantly after moving to the next. Specified in milliseconds.

168
gulp-cppstringify.js Normal file
View File

@ -0,0 +1,168 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
'use strict';
// Borrowed heavily from gulp-concat:
// https://github.com/contra/gulp-concat/
//
// It's very much hardcoded for the ESP8266 Arduino at the moment,
// but feel free to hack away at it if you need it for other purposes!
var through = require('through2');
var path = require('path');
var File = require('vinyl');
var _ = require('lodash');
var Readable = require('stream').Readable;
function escapeContent(content, lineLength)
{
var lineRegexp = new RegExp('(.{1,' + (lineLength - 1) + '}[^\\\\])', 'g');
return content
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\r?\n/g, '\\r\\n')
.replace(lineRegexp, ' "$1"\r\n')
.replace(/\r\n$/, '');
};
function escapeContentAsByteArray(content, lineLength)
{
var bytesPerLine = Math.floor(lineLength / 5);
var lineRegexp = new RegExp('((?:0x..,){1,' + bytesPerLine + '})', 'g');
return content
.replace(/(.{2})/g, '0x$1,')
.replace(lineRegexp, ' $1\r\n')
.replace(/,\r\n$/, '');
};
function encodeFile(file, opts)
{
var variableName;
if (opts.map.hasOwnProperty(file.relative))
variableName = opts.map[file.relative];
else
variableName = file.relative.replace(/[^a-zA-Z0-9_]/g, '_');
if (variableName === null)
return '';
variableName = opts.variablePrefix + variableName;
var escapedContent;
var output;
if (opts.byteArray)
{
escapedContent = escapeContentAsByteArray(file.contents.toString('hex'), opts.lineLength);
output = "const uint8_t " + variableName + "[] PROGMEM = {\r\n" + escapedContent + "};\r\n\r\n";
}
else
{
escapedContent = escapeContent(file.contents.toString('utf-8'), opts.lineLength);
output = "const char " + variableName + "[] PROGMEM = \r\n" + escapedContent + ";\r\n\r\n";
}
return output;
}
module.exports = function(file, opts)
{
if (!file)
throw new Error('gulp-cppstringify: Missing file option');
opts = _.extend({
map: [],
headerDefineName: '__Embedded',
variablePrefix: 'Embedded',
lineLength: 100,
byteArray: false
}, opts || {});
var fileName;
var latestFile = false;
var latestMod = 0;
var output = null;
if (typeof file === 'string')
fileName = file;
else if (typeof file.path === 'string')
fileName = path.basename(file.path);
else
throw new Error('gulp-cppstringify: Missing path in file options');
function bufferContents(file, enc, cb)
{
if (file.isNull())
{
cb();
return;
}
if (file.isStream())
{
this.emit('error', new Error('gulp-cppstringify: Streaming not supported'));
cb();
return;
}
if (!latestMod || file.stat && file.stat.mtime > latestMod)
{
latestFile = file;
latestMod = file.stat && file.stat.mtime;
}
if (output == null)
{
output = new Readable();
output._read = function noop() {};
output.push("#ifndef " + opts.headerDefineName + "\r\n");
output.push("#define " + opts.headerDefineName + "\r\n\r\n");
output.push("#include <pgmspace.h>\r\n\r\n");
}
output.push(encodeFile(file, opts));
cb();
}
function endStream(cb)
{
if (!latestFile)
{
cb();
return;
}
var headerFile;
if (typeof file === 'string')
{
headerFile = latestFile.clone({contents: false});
headerFile.path = path.join(latestFile.base, file);
}
else
headerFile = new File(file);
output.push("#endif\r\n");
output.push(null);
headerFile.contents = output;
this.push(headerFile);
cb();
}
return through.obj(bufferContents, endStream);
};

244
gulpfile.js Normal file
View File

@ -0,0 +1,244 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
'use strict';
const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');
const cppstringify = require('./gulp-cppstringify');
const fs = require('fs');
const plumber = require('gulp-plumber');
const sass = require('gulp-sass');
const cleanCSS = require('gulp-clean-css');
const watch = require('gulp-debounced-watch');
const uglify = require('gulp-uglify');
const concat = require('gulp-concat');
const print = require('gulp-print');
const config = {
assetsPath: 'web/',
distPath: 'web/dist/',
outputPath: 'src/assets/'
};
const HTMLMap = {
'index.html': 'Index'
};
const JSMap = {
'bundle.js': 'BundleJS'
};
const CSSMap = {
'bundle.css': 'BundleCSS'
};
// There is an issue in the AsyncWebServer where it's apparantly running
// out of memory on simultaneous requests. We'll work around it by
// merging all the JS into one big file.
//
// https://github.com/me-no-dev/ESPAsyncWebServer/issues/256
const JSSrc = [
'node_modules/axios/dist/axios.min.js',
'node_modules/vue/dist/vue.min.js',
'node_modules/vue-i18n/dist/vue-i18n.min.js',
'web/lang.js',
'web/app.js'
];
const SCSSSrc = [
'web/site.scss'
]
gulp.task('default',
[
'embedAssets'
],
function(){});
gulp.task('watch',
[
'compileScss',
'compileJS'
],
function()
{
watch(config.assetsPath + '*.scss', function() { gulp.start('compileScss'); });
watch(config.assetsPath + '*.js', function() { gulp.start('compileJS'); });
});
gulp.task('embedHTML', function()
{
return gulp.src(config.assetsPath + '*.html')
.pipe(print(function(filepath) { return 'HTML: ' + filepath }))
.pipe(htmlmin({
collapseWhitespace: true,
removeComments: true,
minifyCSS: true,
minifyJS: true
}))
.pipe(cppstringify('html.h', {
headerDefineName: '__assets_html',
map: HTMLMap
}))
.pipe(gulp.dest(config.outputPath));
});
gulp.task('compileScss', function()
{
return gulp.src(SCSSSrc)
.pipe(plumber({
errorHandler: function (error)
{
console.log(error.toString());
this.emit('end');
}}))
.pipe(print(function(filepath) { return 'SCSS: ' + filepath }))
.pipe(sass({
includePaths: ['node_modules/milligram/src']
}))
.pipe(cleanCSS({compatibility: 'ie9'}))
.pipe(concat('bundle.css'))
.pipe(gulp.dest(config.distPath));
});
gulp.task('compileJS', function()
{
return gulp.src(JSSrc)
.pipe(plumber({
errorHandler: function (error)
{
console.log(error.toString());
this.emit('end');
}}))
.pipe(print(function(filepath) { return 'JS: ' + filepath }))
.pipe(concat('bundle.js'))
.pipe(uglify())
.pipe(gulp.dest(config.distPath));
});
gulp.task('embedJS', ['compileJS'], function()
{
return gulp.src([config.distPath + 'bundle.js'])
.pipe(cppstringify('js.h', {
headerDefineName: '__assets_js',
map: JSMap
}))
.pipe(gulp.dest(config.outputPath));
});
gulp.task('embedCSS', ['compileScss'], function()
{
return gulp.src([config.distPath + 'bundle.css'])
.pipe(cppstringify('css.h', {
headerDefineName: '__embed_css',
map: CSSMap
}))
.pipe(gulp.dest(config.outputPath));
});
gulp.task('embedVersion', function()
{
var versionData = '';
const cmd = spawn('gitversion');
cmd.stdout.on('data', function(data)
{
versionData += data;
});
cmd.stderr.on('data', function(data)
{
console.log(data.toString().trim());
});
cmd.on('exit', function(code)
{
if (code != 0) return;
var version = JSON.parse(versionData);
var headerFile = "#ifndef __assets_version\r\n";
headerFile += "#define __assets_version\r\n\r\n";
headerFile += "const uint8_t VersionMajor = " + version.Major + ";\r\n";
headerFile += "const uint8_t VersionMinor = " + version.Minor + ";\r\n";
headerFile += "const uint8_t VersionPatch = " + version.Patch + ";\r\n";
headerFile += "const uint8_t VersionMetadata = " + version.BuildMetaData + ";\r\n";
headerFile += "const char VersionBranch[] = \"" + version.BranchName + "\";\r\n";
headerFile += "const char VersionSha[] = \"" + version.Sha + "\";\r\n";
headerFile += "const char VersionSemVer[] = \"" + version.SemVer + "\";\r\n";
headerFile += "const char VersionFullSemVer[] = \"" + version.FullSemVer + "\";\r\n";
headerFile += "const char VersionCommitDate[] = \"" + version.CommitDate + "\";\r\n";
headerFile += "\r\n#endif\r\n";
fs.writeFile(config.outputPath + 'version.h', headerFile, function(err)
{
if (err) throw err;
});
});
});
gulp.task('embedAssets', ['embedHTML', 'embedJS', 'embedCSS', 'embedVersion'], function() { })
// PlatformIO
const spawn = require('child_process').spawn;
const argv = require('yargs').argv;
var platformio = function(target)
{
var args = ['run'];
if ("e" in argv)
{
args.push('-e');
args.push(argv.e);
}
if ("p" in argv)
{
args.push('--upload-port');
args.push(argv.p);
}
if (target)
{
args.push('-t');
args.push(target);
}
const cmd = spawn('platformio', args);
cmd.stdout.on('data', function(data)
{
console.log(data.toString().trim());
});
cmd.stderr.on('data', function(data)
{
console.log(data.toString().trim());
});
}
gulp.task('upload', ['embedHTML', 'embedAssets'], function() { platformio('upload'); });
gulp.task('build', ['embedHTML', 'embedAssets'], function() { platformio(false); });

40
package.json Normal file
View File

@ -0,0 +1,40 @@
{
"name": "stairs",
"version": "2.0.0",
"description": "Stairs",
"main": "gulpfile.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "node devserver.js"
},
"repository": {
"type": "git",
"url": "https://git.x2software.net/pub/Stairs.git"
},
"author": "Mark van Renswoude <mark@x2software.net>",
"license": "Unlicense",
"devDependencies": {
"axios": "^0.17.1",
"child_process": "^1.0.2",
"express": "^4.16.2",
"gulp": "^3.9.1",
"gulp-clean-css": "^3.9.0",
"gulp-concat": "^2.6.1",
"gulp-debounced-watch": "^1.0.4",
"gulp-htmlmin": "^3.0.0",
"gulp-plumber": "^1.1.0",
"gulp-print": "^2.0.1",
"gulp-sass": "^3.1.0",
"gulp-uglify": "^3.0.0",
"lodash": "^4.17.4",
"milligram": "^1.3.0",
"path": "^0.12.7",
"through2": "^2.0.3",
"vinyl": "^2.1.0",
"vue": "^2.5.13",
"yargs": "^10.0.3"
},
"dependencies": {
"vue-i18n": "^7.3.3"
}
}

View File

@ -9,7 +9,11 @@
; http://docs.platformio.org/page/projectconf.html
[env:esp12e]
platform = espressif8266_stage
platform = https://github.com/platformio/platform-espressif8266.git#feature/stage
board = esp12e
framework = arduino
upload_speed = 115200
upload_speed = 115200
lib_deps =
Hash
ArduinoJson
ESP Async WebServer

111
src/assets/css.h Normal file
View File

@ -0,0 +1,111 @@
#ifndef __embed_css
#define __embed_css
#include <pgmspace.h>
const char EmbeddedBundleCSS[] PROGMEM =
"*,:after,:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#606c76;fo"
"nt-family:Roboto,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.6em;font-weight:300;letter-"
"spacing:.01em;line-height:1.6}blockquote{border-left:.3rem solid #404040;margin-left:0;margin-right:"
"0;padding:1rem 1.5rem}blockquote :last-child{margin-bottom:0}.button,button,input[type=button],input"
"[type=reset],input[type=submit]{background-color:#06f;border:.1rem solid #06f;border-radius:.4rem;co"
"lor:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-s"
"pacing:.1rem;line-height:3.8rem;padding:0 3rem;text-align:center;text-decoration:none;text-transform"
":uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type=butto"
"n]:focus,input[type=button]:hover,input[type=reset]:focus,input[type=reset]:hover,input[type=submit]"
":focus,input[type=submit]:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}."
"button[disabled],button[disabled],input[type=button][disabled],input[type=reset][disabled],input[typ"
"e=submit][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button"
"[disabled]:focus,button[disabled]:hover,input[type=button][disabled]:focus,input[type=button][disabl"
"ed]:hover,input[type=reset][disabled]:focus,input[type=reset][disabled]:hover,input[type=submit][dis"
"abled]:focus,input[type=submit][disabled]:hover{background-color:#06f;border-color:#06f}.button.butt"
"on-outline,button.button-outline,input[type=button].button-outline,input[type=reset].button-outline,"
"input[type=submit].button-outline{background-color:transparent;color:#06f}.button.button-outline:foc"
"us,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type=b"
"utton].button-outline:focus,input[type=button].button-outline:hover,input[type=reset].button-outline"
":focus,input[type=reset].button-outline:hover,input[type=submit].button-outline:focus,input[type=sub"
"mit].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.bu"
"tton-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:"
"focus,button.button-outline[disabled]:hover,input[type=button].button-outline[disabled]:focus,input["
"type=button].button-outline[disabled]:hover,input[type=reset].button-outline[disabled]:focus,input[t"
"ype=reset].button-outline[disabled]:hover,input[type=submit].button-outline[disabled]:focus,input[ty"
"pe=submit].button-outline[disabled]:hover{border-color:inherit;color:#06f}.button.button-clear,butto"
"n.button-clear,input[type=button].button-clear,input[type=reset].button-clear,input[type=submit].but"
"ton-clear{background-color:transparent;border-color:transparent;color:#06f}.button.button-clear:focu"
"s,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type=button]."
"button-clear:focus,input[type=button].button-clear:hover,input[type=reset].button-clear:focus,input["
"type=reset].button-clear:hover,input[type=submit].button-clear:focus,input[type=submit].button-clear"
":hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disa"
"bled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-c"
"lear[disabled]:hover,input[type=button].button-clear[disabled]:focus,input[type=button].button-clear"
"[disabled]:hover,input[type=reset].button-clear[disabled]:focus,input[type=reset].button-clear[disab"
"led]:hover,input[type=submit].button-clear[disabled]:focus,input[type=submit].button-clear[disabled]"
":hover{color:#06f}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:."
"2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:.3rem solid #06f;overflow-y:hidden}"
"pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:.1"
"rem solid #f4f5f6;margin:3rem 0}input[type=email],input[type=number],input[type=password],input[type"
"=search],input[type=tel],input[type=text],input[type=url],select,textarea{appearance:none;background"
"-color:transparent;border:.1rem solid #404040;border-radius:.4rem;box-shadow:none;box-sizing:inherit"
";height:3.8rem;padding:.6rem 1rem;width:100%}input[type=email]:focus,input[type=number]:focus,input["
"type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[typ"
"e=url]:focus,select:focus,textarea:focus{border-color:#06f;outline:0}select{background:url('data:ima"
"ge/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"14\" viewBox=\"0 0 29 14\" width="
"\"29\"><path fill=\"#d1d1d1\" d=\"M9.37727 3.625l5.08154 6.93523L19.54036 3.625\"/></svg>') center r"
"ight no-repeat;padding-right:3rem}select:focus{background-image:url('data:image/svg+xml;utf8,<svg xm"
"lns=\"http://www.w3.org/2000/svg\" height=\"14\" viewBox=\"0 0 29 14\" width=\"29\"><path fill=\"#9b"
"4dca\" d=\"M9.37727 3.625l5.08154 6.93523L19.54036 3.625\"/></svg>')}textarea{min-height:6.5rem}labe"
"l,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;"
"padding:0}input[type=checkbox],input[type=radio]{display:inline}.label-inline{display:inline-block;f"
"ont-weight:400;margin-left:.5rem}.container{margin:0 auto;max-width:112rem;padding:0 2rem;position:r"
"elative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{"
"padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-item"
"s:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretc"
"h{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 aut"
"o;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column"
".column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-"
"offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-50{margin-le"
"ft:50%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column"
".column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-"
"offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{f"
"lex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,."
"row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-w"
"idth:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-w"
"idth:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .co"
"lumn.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .co"
"lumn.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .colum"
"n .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width"
":40rem){.row{flex-direction:row;margin-left:-1rem;width:calc(100% + 2rem)}.row .column{margin-bottom"
":inherit;padding:0 1rem}}a{color:#06f;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{li"
"st-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font"
"-size:90%;margin:1.5rem 0 1.5rem 3rem}ol{list-style:decimal inside}ul{list-style:circle inside}.butt"
"on,button,dd,dt,li{margin-bottom:1rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote"
",dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;width:100%}td,th{borde"
"r-bottom:.1rem solid #e1e1e1;padding:1.2rem 1.5rem;text-align:left}td:first-child,th:first-child{pad"
"ding-left:0}td:last-child,th:last-child{padding-right:0}b,strong{font-weight:700}p{margin-top:0}h1,h"
"2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2rem;margin-top:0}h1{font-size:4.6"
"rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font"
"-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line"
"-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{"
"clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right}[v-cloak]{displ"
"ay:none}body{background-color:#000;color:#fff;font-family:Verdana,Arial,sans-serif;font-size:10pt;pa"
"dding-bottom:3rem}@media screen and (min-width:768px){body{padding-top:3rem}}input,textarea{color:#f"
"ff}#container{background-color:#202020;margin-top:2rem;padding:1rem;box-shadow:0 0 50px #fcf6cf;bord"
"er:solid 1px #000}@media screen and (min-width:768px){#container{width:768px;margin-left:auto;margin"
"-right:auto}}.header{position:relative}.header img{float:left;margin-right:1rem}.header .wifistatus{"
"position:absolute;right:0;top:0}.header .wifistatus .indicator{display:inline-block;width:1rem;heigh"
"t:1rem;border-radius:50%;margin-right:.5rem}.header .wifistatus .indicator[data-status=connected]{ba"
"ckground-color:#396}.header .wifistatus .indicator[data-status=disconnected]{border:solid 1px grey}."
"header .wifistatus .indicator[data-status=connecting]{background-color:#f93}.header .wifistatus .ind"
"icator[data-status=error]{background-color:#c00}h1{font-size:16pt;margin:0}h2{color:silver;font-size"
":10pt;margin:0}h3{color:grey;background-color:#282828;font-size:14pt;border-bottom:solid 1px grey}.v"
"ersion{color:grey;font-size:8pt;text-align:center;margin-top:2rem}.tabs{clear:both;margin-top:3rem}."
"tabs .button{background-color:#404040;color:#fff!important;border-color:grey}.tabs .button.button-ou"
"tline{background-color:transparent}input[disabled]{cursor:not-allowed;color:grey;background-color:#2"
"62626}.label-inline{margin-right:2rem}.hint{display:block;font-size:8pt;color:grey;margin-bottom:1.5"
"rem}.loading{margin-top:3rem;text-align:center}.suboptions{margin-left:5rem}.buttons{text-align:cent"
"er}.slider{-webkit-appearance:none;width:100%;height:.5rem;border-radius:.25rem;background:#404040;o"
"utline:0}.slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:2rem;height:2re"
"m;border-radius:50%;background:#fcf6cf;cursor:pointer}.slider::-moz-range-thumb{width:2rem;height:2r"
"em;border-radius:50%;background:#fcf6cf;cursor:pointer}";
#endif

59
src/assets/html.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef __assets_html
#define __assets_html
#include <pgmspace.h>
const char EmbeddedIndex[] PROGMEM =
"<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><title></title><meta name=\"theme-color\" content"
"=\"#000000\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><link rel=\"styl"
"esheet\" href=\"bundle.css\"><script src=\"bundle.js\"></script></head><body><div id=\"app\"><div v-"
"cloak><div id=\"container\"><div class=\"header\"><img src=\"data:image/png;base64,iVBORw0KGgoAAAANS"
"UhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXBJREFUeNrsWdENgjAQL"
"cYBcAPcACdQN4AN2MC4gRsYJ9ENdAPYADaADepdUhM1qFjurgp9ScMHgd713V3ftUp5eHgMF1rrGEau6VHD2HMbH5qJOLHra+fkz"
"bsYRshM8pLTgUIgSgvuMMoYw+iMYTr6QhNYMrNiNywILlyVKdcyyPsmcRsyU50kgHtQQu2AdNJFpDkAK4I/LIWMb2AsIBcq0iRGe"
"QGPTZfV6QE0+gDGF2rosGEgMQxIAhnZAiPN84upRf0/OlpsLCBp3yq0chgtCUUZrRw6QDO3EWHSqF9tarZaSKJXeJDdbQlsE0KD6"
"JN/KoRsGhxXKClCKHJIfkThwMWhA6dBSolRijkJOd1ZUv9yQ9OpqbHpiaUVaEbZE7tIIjoBKXysos1c4V8ebLEdbv2bcMsE7gjuB"
"dvXRSJ4F+/wqIXXrIGwmX3zwacLDheNO91OjLQKd14VMDCnYgCxVjI3NTe1mSoPD49x4SrAAG9qPn4eovCMAAAAAElFTkSuQmCC"
"\"><h1>{{ $t('title') }}</h1><h2>{{ version.systemID !== null ? $t('systemID') + ': ' + version.syst"
"emID : '' }}</h2><div class=\"wifistatus\"><div class=\"connection\"><div class=\"indicator\" :data-"
"status=\"wifiStatus.ap.enabled ? 'connected' : 'disconnected'\"></div>{{ $t('wifiStatus.accesspoint."
"title') }} {{ wifiStatus.ap.enabled ? wifiStatus.ap.ip : $t('wifiStatus.accesspoint.disabled') }}</d"
"iv><div class=\"connection\"><div class=\"indicator\" :data-status=\"getWiFiStationStatus()\"></div>"
"{{ $t('wifiStatus.stationmode.title') }} {{ getWiFiStationStatusText() }}</div></div></div><div v-if"
"=\"loading\" class=\"loading\">{{ $t('loading') }} {{ loadingIndicator }}</div><div v-if=\"!loading"
"\"><div class=\"tabs\"><button class=\"button\" :class=\"{ 'button-outline': activeTab != 'status' }"
"\" @click=\"activeTab = 'status'\">{{ $t('status.tabTitle') }}</button> <button class=\"button\" :cl"
"ass=\"{ 'button-outline': activeTab != 'triggers' }\" @click=\"activeTab = 'triggers'\">{{ $t('trigg"
"ers.tabTitle') }}</button> <button class=\"button\" :class=\"{ 'button-outline': activeTab != 'conne"
"ction' }\" @click=\"activeTab = 'connection'\">{{ $t('connection.tabTitle') }}</button></div><div v-"
"if=\"activeTab == 'status'\"><h3>{{ $t('status.title') }}</h3><div class=\"slidecontainer\" v-for=\""
"(step, index) in steps\">{{ index + 1 }} <input type=\"range\" min=\"0\" max=\"100\" class=\"slider"
"\" v-model=\"step.value\"> {{ step.value }}</div></div><div v-if=\"activeTab == 'triggers'\"><form @"
"submit.prevent=\"applyTriggers\"><fieldset><h3>{{ $t('triggers.timeTitle') }}</h3></fieldset><fields"
"et><h3>{{ $t('triggers.motionTitle') }}</h3></fieldset></form></div><div v-if=\"activeTab == 'connec"
"tion'\"><form @submit.prevent=\"applyConnection\"><fieldset><h3>{{ $t('connection.title') }}</h3><in"
"put type=\"checkbox\" id=\"accesspoint\" v-model=\"connection.accesspoint\"><label class=\"label-inl"
"ine\" for=\"accesspoint\">{{ $t('connection.accesspoint') }}</label><span class=\"hint\">{{ $t('conn"
"ection.accesspointHint') }}</span> <input type=\"checkbox\" id=\"station\" v-model=\"connection.stat"
"ion\"><label class=\"label-inline\" for=\"station\">{{ $t('connection.stationmode') }}</label><span "
"class=\"hint\">{{ $t('connection.stationmodeHint') }}</span><label for=\"ssid\">{{ $t('connection.ss"
"id') }}</label><input type=\"text\" id=\"ssid\" v-model=\"connection.ssid\" :disabled=\"!connection."
"station\"><label for=\"password\">{{ $t('connection.password') }}</label><input type=\"password\" id"
"=\"password\" v-model=\"connection.password\" :disabled=\"!connection.station\"> <input type=\"check"
"box\" id=\"dhcp\" v-model=\"connection.dhcp\" :disabled=\"!connection.station\"><label class=\"label"
"-inline\" for=\"dhcp\">{{ $t('connection.dhcp') }}</label><span class=\"hint\">{{ $t('connection.dhc"
"pHint') }}</span><div class=\"suboptions\"><label for=\"ip\">{{ $t('connection.ipaddress') }}</label"
"><input type=\"text\" id=\"ip\" v-model=\"connection.ip\" :disabled=\"!connection.station || connect"
"ion.dhcp\"><label for=\"subnetmask\">{{ $t('connection.subnetmask') }}</label><input type=\"text\" i"
"d=\"subnetmask\" v-model=\"connection.subnetmask\" :disabled=\"!connection.station || connection.dhc"
"p\"><label for=\"gateway\">{{ $t('connection.gateway') }}</label><input type=\"text\" id=\"gateway\""
" v-model=\"connection.gateway\" :disabled=\"!connection.station || connection.dhcp\"></div><label fo"
"r=\"hostname\">{{ $t('connection.hostname') }}</label><input type=\"text\" :placeholder=\"$t('connec"
"tion.hostnamePlaceholder')\" id=\"hostname\" v-model=\"connection.hostname\" :disabled=\"!connection"
".station\"><div class=\"buttons\"><input class=\"button-primary\" type=\"submit\" :disabled=\"saving"
"\" :value=\"saving ? $t('applyButtonSaving') : $t('applyButton')\"></div></fieldset></form></div></d"
"iv><div class=\"clearfix\"></div></div><div class=\"version\">{{ $t('copyright') }}<br>{{ version.ve"
"rsion !== null ? $t('firmwareVersion') + version.version : '' }}</div></div></div><script language="
"\"javascript\">console.log(\"Initializing...\"),startApp()</script></body></html>";
#endif

32
src/assets/images.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef __assets_images
#define __assets_images
#include <pgmspace.h>
const uint8_t EmbeddedLogo[] PROGMEM = {
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x30,
0x00,0x00,0x00,0x30,0x08,0x06,0x00,0x00,0x00,0x57,0x02,0xf9,0x87,0x00,0x00,0x00,0x19,0x74,0x45,0x58,
0x74,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x00,0x41,0x64,0x6f,0x62,0x65,0x20,0x49,0x6d,0x61,0x67,
0x65,0x52,0x65,0x61,0x64,0x79,0x71,0xc9,0x65,0x3c,0x00,0x00,0x01,0x70,0x49,0x44,0x41,0x54,0x78,0xda,
0xec,0x59,0xd1,0x0d,0x82,0x30,0x10,0x2d,0xc6,0x01,0x70,0x03,0xdc,0x00,0x27,0x50,0x37,0x80,0x0d,0xd8,
0xc0,0xb8,0x81,0x1b,0x18,0x27,0xd1,0x0d,0x74,0x03,0xd8,0x00,0x36,0x80,0x0d,0xea,0x5d,0x52,0x13,0x35,
0xa8,0x58,0xee,0xae,0x0a,0x7d,0x49,0xc3,0x07,0x81,0xde,0xf5,0xdd,0x5d,0xdf,0xb5,0x4a,0x79,0x78,0x78,
0x0c,0x17,0x5a,0xeb,0x18,0x46,0xae,0xe9,0x51,0xc3,0xd8,0x73,0x1b,0x1f,0x9a,0x89,0x38,0xb1,0xeb,0x6b,
0xe7,0xe4,0xcd,0xbb,0x18,0x46,0xc8,0x4c,0xf2,0x92,0xd3,0x81,0x42,0x20,0x4a,0x0b,0xee,0x30,0xca,0x18,
0xc3,0xe8,0x8c,0x61,0x3a,0xfa,0x42,0x13,0x58,0x32,0xb3,0x62,0x37,0x2c,0x08,0x2e,0x5c,0x95,0x29,0xd7,
0x32,0xc8,0xfb,0x26,0x71,0x1b,0x32,0x53,0x9d,0x24,0x80,0x7b,0x50,0x42,0xed,0x80,0x74,0xd2,0x45,0xa4,
0x39,0x00,0x2b,0x82,0x3f,0x2c,0x85,0x8c,0x6f,0x60,0x2c,0x20,0x17,0x2a,0xd2,0x24,0x46,0x79,0x01,0x8f,
0x4d,0x97,0xd5,0xe9,0x01,0x34,0xfa,0x00,0xc6,0x17,0x6a,0xe8,0xb0,0x61,0x20,0x31,0x0c,0x48,0x02,0x19,
0xd9,0x02,0x23,0xcd,0xf3,0x8b,0xa9,0x45,0xfd,0x3f,0x3a,0x5a,0x6c,0x2c,0x20,0x69,0xdf,0x2a,0xb4,0x72,
0x18,0x2d,0x09,0x45,0x19,0xad,0x1c,0x3a,0x40,0x33,0xb7,0x11,0x61,0xd2,0xa8,0x5f,0x6d,0x6a,0xb6,0x5a,
0x48,0xa2,0x57,0x78,0x90,0xdd,0x6d,0x09,0x6c,0x13,0x42,0x83,0xe8,0x93,0x7f,0x2a,0x84,0x6c,0x1a,0x1c,
0x57,0x28,0x29,0x42,0x28,0x72,0x48,0x7e,0x44,0xe1,0xc0,0xc5,0xa1,0x03,0xa7,0x41,0x4a,0x89,0x51,0x8a,
0x39,0x09,0x39,0xdd,0x59,0x52,0xff,0x72,0x43,0xd3,0xa9,0xa9,0xb1,0xe9,0x89,0xa5,0x15,0x68,0x46,0xd9,
0x13,0xbb,0x48,0x22,0x3a,0x01,0x29,0x7c,0xac,0xa2,0xcd,0x5c,0xe1,0x5f,0x1e,0x6c,0xb1,0x1d,0x6e,0xfd,
0x9b,0x70,0xcb,0x04,0xee,0x08,0xee,0x05,0xdb,0xd7,0x45,0x22,0x78,0x17,0xef,0xf0,0xa8,0x85,0xd7,0xac,
0x81,0xb0,0x99,0x7d,0xf3,0xc1,0xa7,0x0b,0x0e,0x17,0x8d,0x3b,0xdd,0x4e,0x8c,0xb4,0x0a,0x77,0x5e,0x15,
0x30,0x30,0xa7,0x62,0x00,0xb1,0x56,0x32,0x37,0x35,0x37,0xb5,0x99,0x2a,0x0f,0x0f,0x8f,0x71,0xe1,0x2a,
0xc0,0x00,0x6f,0x6a,0x3e,0x7e,0x1e,0xa2,0xf0,0x8c,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,
0x60,0x82};
#endif

1248
src/assets/js.h Normal file

File diff suppressed because it is too large Load Diff

14
src/assets/version.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef __assets_version
#define __assets_version
const uint8_t VersionMajor = 2;
const uint8_t VersionMinor = 0;
const uint8_t VersionPatch = 0;
const uint8_t VersionMetadata = 0;
const char VersionBranch[] = "release/2.0";
const char VersionSha[] = "3099dd8a0e2e5fa771e6a864a1daa83de5998df0";
const char VersionSemVer[] = "2.0.0-beta.1";
const char VersionFullSemVer[] = "2.0.0-beta.1+0";
const char VersionCommitDate[] = "2017-10-05";
#endif

26
src/charproperties.cpp Normal file
View File

@ -0,0 +1,26 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#include "charproperties.h"
#include <cstddef>
#include <string.h>
#include "debug.h"
void CharProperties::assignChar(char** field, const char* newValue)
{
if (*field != NULL)
delete *field;
if (newValue != NULL)
{
// Include the terminating null character
size_t length = strlen(newValue) + 1;
*field = new char[length];
strncpy(*field, newValue, length);
}
else
*field = NULL;
}

18
src/charproperties.h Normal file
View File

@ -0,0 +1,18 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#ifndef __charproperties
#define __charproperties
#include <stdint.h>
class CharProperties
{
protected:
void assignChar(char** field, const char* newValue);
};
#endif

View File

@ -1,26 +1,20 @@
#ifndef __Config
#define __Config
#ifndef __config
#define __config
#include <Arduino.h>
#include <stdint.h>
#include "credentials.h"
#define SerialDebug
static const uint32_t SerialDebugBaudrate = 115200;
static const uint32_t SerialDebugStartupDelay = 2000;
//#define SerialDebug
// The name of this device on the network
static const char* WiFiHostname = "Stairs";
// The number of steps (assumed to be <= 16, as the code currently only controls 1 PCA9685 board)
static const uint8_t StepCount = 14;
// The port number on which the UDP server listens
static const uint16_t UDPPort = 3126;
static const char* ConnectionSettingsFile = "/settings.json";
static const char* DefaultAPSSIDPrefix = "Stairs-";
static const uint32_t StationModeTimeout = 30000;
/*
// Pins for the I2C bus
static const uint8_t PinSDA = 13;
static const uint8_t PinSCL = 12;
@ -29,28 +23,6 @@ static const uint8_t PinSCL = 12;
// I2C address and PWM frequency of the PCA9685 board
static const uint8_t PWMDriverAddress = 0x40;
static const uint16_t PWMDriverPWMFrequency = 1600;
// Determines if OTA firmware updates are enabled
// 0 - Disabled
// 1 - Enabled (fixed URL)
// 2 - Enabled (use URL in command)
static const uint8_t OTAUpdateEnabled = 2;
static const char* OTAUpdateFixedHost = "";
static const uint16_t OTAUpdateFixedPort = 80;
static const char* OTAUpdateFixedPath = "/";
// The minimum amount of time (in milliseconds) between update requests
static const uint32_t OTAUpdateThrottle = 5000;
#ifdef SerialDebug
#define _d(msg) Serial.print(msg)
#define _dln(msg) Serial.println(msg)
#else
#define _d(msg) do { } while (0)
#define _dln(msg) do { } while (0)
#endif
*/
#endif

View File

@ -1,3 +0,0 @@
// Create a copy of this file called "credentials.h"
static const char* WiFiSSID = "example";
static const char* WiFiPassword = "example";

17
src/debug.cpp Normal file
View File

@ -0,0 +1,17 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#include "debug.h"
void _dinit()
{
#ifdef SerialDebug
Serial.begin(SerialDebugBaudrate);
Serial.setDebugOutput(true);
delay(SerialDebugStartupDelay);
#endif
}

24
src/debug.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#ifndef __serialdebug
#define __serialdebug
#include "config.h"
#include <Arduino.h>
void _dinit();
#ifdef SerialDebug
#define _d(msg) Serial.print(msg)
#define _dln(msg) Serial.println(msg)
#else
#define _d(msg) do { } while (0)
#define _dln(msg) do { } while (0)
#endif
#endif

15
src/global.cpp Normal file
View File

@ -0,0 +1,15 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#include "global.h"
ConnectionSettings* connectionSettings = new ConnectionSettings();
bool connectionSettingsChanged = false;
uint32_t currentTime;
IPAddress emptyIP(0, 0, 0, 0);

21
src/global.h Normal file
View File

@ -0,0 +1,21 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#ifndef __global
#define __global
#include <stdint.h>
#include <stdbool.h>
#include <IPAddress.h>
#include "settings/connection.h"
extern ConnectionSettings* connectionSettings;
extern bool connectionSettingsChanged;
extern uint32_t currentTime;
extern IPAddress emptyIP;
#endif

View File

@ -1,28 +1,225 @@
/*
* Stairs lighting
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#include <stdint.h>
#include <Stream.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ESP8266httpUpdate.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
extern "C" {
#include <user_interface.h>
}
#include "config.h"
#include "protocol.h"
#include "components\PCA9685.h"
//#include "modes\adc.h"
#include "modes\alternate.h"
#include "modes\custom.h"
#include "modes\slide.h"
#include "modes\static.h"
#include "stairs.h"
#include "version.h"
#include "debug.h"
#include "settings/connection.h"
#include "global.h"
#include "server/static.h"
#include "server/api.h"
PCA9685* pwmDriver;
Stairs* stairs;
WiFiUDP udpServer;
ADC_MODE(ADC_VCC);
// Forward declarations
void initWiFi();
#ifdef SerialDebug
void wifiEvent(WiFiEvent_t event);
#endif
void updateLED();
void startServer();
void stopServer();
void handleNotFound(AsyncWebServerRequest* request);
AsyncWebServer server(80);
bool accessPoint = false;
bool stationMode = false;
bool forceAccessPoint = false;
uint32_t stationModeStart = 0;
void setup()
{
_dinit();
currentTime = millis();
if (!SPIFFS.begin())
_dln("Setup :: failed to mount file system");
connectionSettings->read();
_dln("Setup :: initializing WiFi");
WiFi.persistent(false);
WiFi.mode(WIFI_OFF);
#ifdef SerialDebug
// onEvent is already deprecated, but since I'm only using it
// for debug purposes we'll see how long it lasts...
WiFi.onEvent(wifiEvent);
_d("WiFi :: MAC address: ");
_dln(WiFi.macAddress());
#endif
initWiFi();
_dln("Setup :: registering routes");
registerStaticRoutes(&server);
registerAPIRoutes(&server);
_dln("Setup :: starting HTTP server");
server.onNotFound(handleNotFound);
server.begin();
}
void loop()
{
currentTime = millis();
if (connectionSettingsChanged)
{
_dln("Loop :: connection settings changed");
initWiFi();
connectionSettingsChanged = false;
}
if (stationModeStart > 0)
{
bool isConnected = WiFi.status() == WL_CONNECTED;
if (isConnected)
{
_d("WiFi :: connected, IP address: ");
_dln(WiFi.localIP());
stationModeStart = 0;
}
else if (stationMode && accessPoint &&
currentTime - stationModeStart >= StationModeTimeout)
{
_dln("WiFi :: unable to connect, switching off station mode, status:");
_dln(WiFi.status());
#ifdef SerialDebug
WiFi.printDiag(Serial);
#endif
// Connecting to access point is taking too long and is blocking
// the access point mode, stop trying
stationMode = false;
WiFi.disconnect();
WiFi.mode(WIFI_AP);
}
}
updateLED();
}
void initWiFi()
{
WiFi.disconnect();
WiFi.softAPdisconnect();
accessPoint = connectionSettings->flag(AccessPoint) || forceAccessPoint;
stationMode = connectionSettings->flag(StationMode) && connectionSettings->ssid() != NULL;
WiFi.mode(accessPoint && stationMode ? WIFI_AP_STA :
accessPoint ? WIFI_AP :
stationMode ? WIFI_STA :
WIFI_OFF);
if (accessPoint)
{
_dln("WiFi :: starting access point");
String ssidString = DefaultAPSSIDPrefix + String(ESP.getChipId(), HEX);
if (WiFi.softAP((const char *)ssidString.c_str()))
{
_d("WiFi :: IP address: ");
_dln(WiFi.softAPIP());
}
else
_d("WiFi :: failed to start soft access point");
}
if (stationMode)
{
_d("WiFi :: starting station mode to: ");
_dln(connectionSettings->ssid());
stationModeStart = currentTime;
if (WiFi.begin(connectionSettings->ssid(), connectionSettings->password()))
{
if (connectionSettings->flag(DHCP))
// I've had the same issue as described here with config(0, 0, 0):
// https://stackoverflow.com/questions/40069654/how-to-clear-static-ip-configuration-and-start-dhcp
wifi_station_dhcpc_start();
else
WiFi.config(connectionSettings->ip(), connectionSettings->gateway(), connectionSettings->subnetMask());
}
else
_d("WiFi :: failed to start station mode");
}
}
#ifdef SerialDebug
void wifiEvent(WiFiEvent_t event)
{
switch (event)
{
case WIFI_EVENT_STAMODE_CONNECTED:
_dln("WiFi:: station mode: connected"); break;
case WIFI_EVENT_STAMODE_DISCONNECTED:
_dln("WiFi:: station mode: disconnected"); break;
case WIFI_EVENT_STAMODE_AUTHMODE_CHANGE:
_dln("WiFi:: station mode: authmode change"); break;
case WIFI_EVENT_STAMODE_GOT_IP:
_dln("WiFi:: station mode: got IP");
_dln(WiFi.localIP());
break;
case WIFI_EVENT_STAMODE_DHCP_TIMEOUT:
_dln("WiFi:: station mode: DHCP timeout"); break;
case WIFI_EVENT_SOFTAPMODE_STACONNECTED:
_dln("WiFi:: soft AP mode: station connected"); break;
case WIFI_EVENT_SOFTAPMODE_STADISCONNECTED:
_dln("WiFi:: soft AP mode: station disconnected"); break;
}
}
#endif
void updateLED()
{
//while (WiFi.status() != WL_CONNECTED)
//{
//}
}
void handleNotFound(AsyncWebServerRequest *request)
{
_d("HTTP :: not found: "); _dln(request->url());
request->send(404);
}
/*
uint8_t currentModeIdentifier;
IMode* currentMode;
@ -362,4 +559,5 @@ void setCurrentMode(IMode* mode, uint8_t identifier)
void handleCurrentMode()
{
currentMode->tick(stairs, currentTime);
}
}
*/

View File

@ -1,27 +0,0 @@
#include "alternate.h"
#include <Stream.h>
void AlternateMode::init(IStairs* stairs, uint32_t currentTime)
{
stairs->setAll(0);
this->lastChange = currentTime;
this->even = false;
}
void AlternateMode::tick(IStairs* stairs, uint32_t currentTime)
{
if (currentTime - this->lastChange < this->parameters.interval)
return;
this->lastChange = currentTime;
this->even = !this->even;
uint8_t stepCount = stairs->getCount();
for (uint8_t step = 0; step < stepCount; step++)
{
stairs->set(step, ((step % 2) == 0) == this->even ? this->parameters.brightness : 0);
}
}

View File

@ -1,33 +0,0 @@
#ifndef __AlternateMode
#define __AlternateMode
#include <stdint.h>
#include "base.h"
#include "../config.h"
struct AlternateModeParameters
{
uint16_t interval;
uint16_t brightness;
};
class AlternateMode : public BaseMode<AlternateModeParameters>
{
private:
uint32_t lastChange;
bool even = false;
public:
AlternateMode()
{
parameters.interval = 500;
parameters.brightness = IStairs::On;
}
void init(IStairs* stairs, uint32_t currentTime);
void tick(IStairs* stairs, uint32_t currentTime);
};
#endif

View File

@ -1,32 +0,0 @@
#ifndef __BaseMode
#define __BaseMode
#include <stdint.h>
#include <Stream.h>
#include "../config.h"
#include "../mode.h"
template <class T>
class BaseMode : public IMode
{
protected:
T parameters;
public:
virtual void read(uint8_t* data)
{
_d("Reading parameters, size ");
_dln(sizeof(T));
memcpy(&this->parameters, data, sizeof(T));
}
virtual void write(Stream* stream)
{
_d("Writing parameters, size ");
_dln(sizeof(T));
stream->write((uint8_t*)&this->parameters, sizeof(T));
}
};
#endif

View File

@ -1,29 +0,0 @@
#include "custom.h"
#include <stdint.h>
void CustomMode::read(uint8_t* data)
{
// The packet is zeroed before we get our hands on it and
// the size should also be larger as noted in main.cpp,
// so a straight-up copy should be safe.
memcpy(this->values, data, sizeof(this->values));
}
void CustomMode::write(Stream* stream)
{
stream->write((uint8_t*)&this->values, sizeof(this->values));
}
void CustomMode::init(IStairs* stairs, uint32_t currentTime)
{
for (uint8_t step = 0; step < StepCount; step++)
stairs->set(step, this->values[step]);
}
void CustomMode::tick(IStairs* stairs, uint32_t currentTime)
{
}

View File

@ -1,21 +0,0 @@
#ifndef __CustomMode
#define __CustomMode
#include <stdint.h>
#include "base.h"
#include "../config.h"
class CustomMode : public IMode
{
private:
uint16_t values[StepCount];
public:
void read(uint8_t* data);
void write(Stream* stream);
void init(IStairs* stairs, uint32_t currentTime);
void tick(IStairs* stairs, uint32_t currentTime);
};
#endif

View File

@ -1,15 +0,0 @@
#ifndef __SlideMode
#define __SlideMode
#include <stdint.h>
#include "base.h"
#include "../config.h"
class SlideMode : public IMode
{
private:
uint16_t interval;
bool up;
};
#endif

View File

@ -1,52 +0,0 @@
#include "static.h"
void StaticMode::init(IStairs* stairs, uint32_t currentTime)
{
_dln("Initializing static mode:");
_d("currentBrightness: "); _dln(this->currentBrightness);
_d("brightness: "); _dln(this->parameters.brightness);
_d("easeTime: "); _dln(this->parameters.easeTime);
if (this->parameters.easeTime > 0 && this->parameters.brightness != this->currentBrightness)
{
_dln("Easing...");
this->easeStartTime = currentTime;
this->easeStartBrightness = currentBrightness;
if (this->parameters.brightness > this->currentBrightness)
this->easeState = Up;
else
this->easeState = Down;
}
else
{
_dln("Updating immediately...");
this->easeState = None;
stairs->setAll(this->parameters.brightness);
this->currentBrightness = this->parameters.brightness;
}
}
void StaticMode::tick(IStairs* stairs, uint32_t currentTime)
{
if (this->easeState == None)
return;
uint32_t elapsedTime = currentTime - this->easeStartTime;
uint32_t diff = this->easeState == Up ? this->parameters.brightness - this->easeStartBrightness : this->easeStartBrightness - this->parameters.brightness;
uint32_t delta = (diff * elapsedTime) / this->parameters.easeTime;
this->currentBrightness = this->easeState == Up ? this->easeStartBrightness + delta : this->easeStartBrightness - delta;
if (elapsedTime >= this->parameters.easeTime)
{
this->currentBrightness = this->parameters.brightness;
this->easeState = None;
}
stairs->setAll(this->currentBrightness);
}

View File

@ -1,45 +0,0 @@
#ifndef __StaticMode
#define __StaticMode
#include <stdint.h>
#include "base.h"
#include "../config.h"
struct StaticModeParameters
{
uint16_t brightness;
uint16_t easeTime;
};
enum EaseState
{
None,
Up,
Down
};
class StaticMode : public BaseMode<StaticModeParameters>
{
private:
uint16_t currentBrightness;
uint32_t easeStartTime;
uint16_t easeStartBrightness;
EaseState easeState;
public:
StaticMode()
{
parameters.brightness = 0;
parameters.easeTime = 0;
easeState = None;
currentBrightness = 0;
}
void init(IStairs* stairs, uint32_t currentTime);
void tick(IStairs* stairs, uint32_t currentTime);
};
#endif

101
src/server/api.cpp Normal file
View File

@ -0,0 +1,101 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#include "api.h"
#include <ArduinoJson.h>
#include <IPAddress.h>
#include <ESP8266WiFi.h>
#include "../assets/version.h"
#include "../debug.h"
#include "../global.h"
#include "../settings/connection.h"
void handleVersion(AsyncWebServerRequest *request)
{
_dln("API :: version");
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(2));
JsonObject& root = jsonBuffer.createObject();
root["systemID"] = String(ESP.getChipId(), HEX);
root["version"] = String(VersionFullSemVer) + " sha." + String(VersionSha);
AsyncResponseStream *response = request->beginResponseStream("application/json");
root.printTo(*response);
request->send(response);
}
void handleConnectionStatus(AsyncWebServerRequest *request)
{
_dln("API :: connection status");
WiFiMode_t mode = WiFi.getMode();
DynamicJsonBuffer jsonBuffer((2 * JSON_OBJECT_SIZE(2)) + JSON_OBJECT_SIZE(3));
JsonObject& root = jsonBuffer.createObject();
JsonObject& ap = root.createNestedObject("ap");
ap["enabled"] = (mode == WIFI_AP || mode == WIFI_AP_STA);
ap["ip"] = WiFi.softAPIP().toString();
JsonObject& station = root.createNestedObject("station");
station["enabled"] = (mode == WIFI_STA || mode == WIFI_AP_STA);
station["status"] = (uint8_t)WiFi.status();
station["ip"] = WiFi.localIP().toString();
AsyncResponseStream *response = request->beginResponseStream("application/json");
root.printTo(*response);
request->send(response);
}
void handleGetConnection(AsyncWebServerRequest *request)
{
_dln("API :: get connection");
AsyncResponseStream *response = request->beginResponseStream("application/json");
connectionSettings->toJson(*response);
request->send(response);
}
void handlePostConnection(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
{
_dln("API :: post connection");
bool changed;
if (connectionSettings->fromJson((char*)data, &changed))
{
connectionSettings->write();
if (changed)
connectionSettingsChanged = true;
request->send(200);
}
else
request->send(400);
}
void devNullRequest(AsyncWebServerRequest *request) { }
void devNullFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) { }
void registerAPIRoutes(AsyncWebServer* server)
{
server->on("/api/version", HTTP_GET, handleVersion);
server->on("/api/connection/status", HTTP_GET, handleConnectionStatus);
server->on("/api/connection", HTTP_GET, handleGetConnection);
server->on("/api/connection", HTTP_POST, devNullRequest, devNullFileUpload, handlePostConnection);
}

13
src/server/api.h Normal file
View File

@ -0,0 +1,13 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#ifndef __server_api
#define __server_api
#include <ESPAsyncWebServer.h>
void registerAPIRoutes(AsyncWebServer* server);
#endif

35
src/server/static.cpp Normal file
View File

@ -0,0 +1,35 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#include "static.h"
#include "../debug.h"
#include "../assets/html.h"
#include "../assets/js.h"
#include "../assets/css.h"
#include "../assets/images.h"
void handleStatic(AsyncWebServerRequest *request, const String& contentType, PGM_P content)
{
_d("HTTP :: static: "); _dln(request->url());
request->send_P(200, contentType, content);
}
void registerStaticRoutes(AsyncWebServer* server)
{
server->on("/", HTTP_GET, [](AsyncWebServerRequest *request) { handleStatic(request, "text/html", EmbeddedIndex); });
server->on("/bundle.js", HTTP_GET, [](AsyncWebServerRequest *request) { handleStatic(request, "text/javascript", EmbeddedBundleJS); });
server->on("/bundle.css", HTTP_GET, [](AsyncWebServerRequest *request) { handleStatic(request, "text/css", EmbeddedBundleCSS); });
server->on("/logo.png", HTTP_GET, [](AsyncWebServerRequest *request)
{
_d("HTTP :: static: "); _dln(request->url());
AsyncWebServerResponse *response = request->beginResponse_P(200, "image/png", EmbeddedLogo, sizeof(EmbeddedLogo));
request->send(response);
});
}

14
src/server/static.h Normal file
View File

@ -0,0 +1,14 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#ifndef __server_static
#define __server_static
#include <ESPAsyncWebServer.h>
void registerStaticRoutes(AsyncWebServer* server);
#endif

149
src/settings/connection.cpp Normal file
View File

@ -0,0 +1,149 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#include "connection.h"
#include <ArduinoJson.h>
#include <FS.h>
#include "../debug.h"
#include "../global.h"
#include "../config.h"
void ConnectionSettings::read()
{
_dln("ConnectionSettings :: opening file");
File settingsFile = SPIFFS.open(ConnectionSettingsFile, "r");
if (!settingsFile)
{
_dln("ConnectionSettings :: failed to open file");
return;
}
size_t size = settingsFile.size();
if (size > 1024)
{
_dln("ConnectionSettings :: file size is too large");
return;
}
if (size == 0)
{
_dln("ConnectionSettings :: zero size file");
return;
}
std::unique_ptr<char[]> buf(new char[size]);
settingsFile.readBytes(buf.get(), size);
_dln(buf.get());
if (fromJson(buf.get()))
_dln("ConnectionSettings :: read from file");
else
_dln("ConnectionSettings :: failed to parse file");
}
void ConnectionSettings::write()
{
_dln("ConnectionSettings :: opening file for writing");
File settingsFile = SPIFFS.open(ConnectionSettingsFile, "w");
if (!settingsFile)
{
_dln("ConnectionSettings:: failed to open file for writing");
return;
}
toJson(settingsFile);
_dln("ConnectionSettings:: written to file");
}
void ConnectionSettings::toJson(Print &print)
{
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(9));
JsonObject& root = jsonBuffer.createObject();
root["hostname"] = hostname();
root["accesspoint"] = flag(AccessPoint);
root["station"] = flag(StationMode);
root["ssid"] = ssid();
root["password"] = password();
root["dhcp"] = flag(DHCP);
root["ip"] = ip() != 0 ? ip().toString() : "";
root["subnetmask"] = subnetMask() != 0 ? subnetMask().toString() : "";
root["gateway"] = gateway() != 0 ? gateway().toString() : "";
root.printTo(print);
}
bool ConnectionSettings::fromJson(char* data)
{
return fromJson(data, NULL);
}
bool ConnectionSettings::fromJson(char* data, bool* changed)
{
if (changed != NULL)
*changed = false;
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(9) + 250);
JsonObject& root = jsonBuffer.parseObject(data);
if (!root.success())
return false;
IPAddress jsonIP;
IPAddress jsonSubnetMask;
IPAddress jsonGateway;
const char* jsonHostname = root["hostname"];
bool jsonAccessPoint = root["accesspoint"];
bool jsonStation = root["station"];
const char* jsonSSID = root["ssid"];
const char* jsonPassword = root["password"];
bool jsonDHCP = root["dhcp"];
const char* jsonIPText = root["ip"];
const char* jsonSubnetMaskText = root["subnetmask"];
const char* jsonGatewayText = root["gateway"];
if (jsonIPText == NULL || !jsonIP.fromString(jsonIPText)) jsonIP = emptyIP;
if (jsonSubnetMaskText == NULL || !jsonSubnetMask.fromString(jsonSubnetMaskText)) jsonSubnetMask = emptyIP;
if (jsonGatewayText == NULL || !jsonGateway.fromString(jsonGatewayText)) jsonGateway = emptyIP;
if (!(jsonAccessPoint || jsonStation))
jsonAccessPoint = true;
if ((jsonHostname != hostname()) ||
(jsonAccessPoint != flag(AccessPoint)) ||
(jsonStation != flag(StationMode)) ||
(jsonSSID != ssid()) ||
(jsonPassword != password()) ||
(jsonDHCP != flag(DHCP)) ||
(jsonIP != ip()) ||
(jsonSubnetMask != subnetMask()) ||
(jsonGateway != gateway()))
{
hostname(jsonHostname);
flag(AccessPoint, jsonAccessPoint);
flag(StationMode, jsonStation);
ssid(jsonSSID);
password(jsonPassword);
flag(DHCP, jsonDHCP);
ip(jsonIP);
subnetMask(jsonSubnetMask);
gateway(jsonGateway);
if (changed != NULL)
*changed = true;
}
return true;
}

73
src/settings/connection.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#ifndef __settingsconnection
#define __settingsconnection
#include <stdint.h>
#include <stdbool.h>
#include <IPAddress.h>
#include "../charproperties.h"
enum ConnectionSettingsFlags
{
AccessPoint = 1,
StationMode = 2,
DHCP = 4
};
class ConnectionSettings : CharProperties
{
private:
char* mHostname = NULL;
uint8_t mFlags = AccessPoint | DHCP;
char* mSSID = NULL;
char* mPassword = NULL;
IPAddress mIP = (uint32_t)0;
IPAddress mSubnetMask = (uint32_t)0;
IPAddress mGateway = (uint32_t)0;
public:
void read();
void write();
void toJson(Print &print);
bool fromJson(char* data);
bool fromJson(char* data, bool* changed);
char* hostname() { return mHostname; }
void hostname(const char* value) { assignChar(&mHostname, value); }
bool flag(ConnectionSettingsFlags flag) { return (mFlags & flag) != 0; }
void flag(ConnectionSettingsFlags flag, bool enabled)
{
if (enabled)
mFlags |= flag;
else
mFlags &= ~flag;
}
char* ssid() { return mSSID; }
void ssid(const char* value) { assignChar(&mSSID, value); }
char* password() { return mPassword; }
void password(const char* value) { assignChar(&mPassword, value); }
IPAddress ip() { return mIP; }
void ip(IPAddress value) { mIP = value; }
IPAddress subnetMask() { return mSubnetMask; }
void subnetMask(IPAddress value) { mSubnetMask = value; }
IPAddress gateway() { return mGateway; }
void gateway(IPAddress value) { mGateway = value; }
};
#endif

View File

@ -1,6 +1,7 @@
#include "stairs.h"
#include <Math.h>
#include <FS.h>
#include "stairs.h"
#include "debug.h"
@ -19,11 +20,13 @@ void Stairs::init(PCA9685* pwmDriver)
{
this->useScaling = false;
/*
for (uint8_t i = 0; i < StepCount; i++)
{
this->ranges[i].start = IStairs::Off;
this->ranges[i].end = IStairs::On;
}
*/
this->pwmDriver = pwmDriver;
@ -35,7 +38,7 @@ void Stairs::init(PCA9685* pwmDriver)
uint8_t Stairs::getCount()
{
return StepCount;
return 0;//StepCount;
}
@ -49,8 +52,10 @@ void Stairs::setAll(uint16_t brightness)
{
//pwmDriver->setAll(this->getPWMValue(brightness));
/*
for (uint8_t step = 0; step < StepCount; step++)
pwmDriver->setPWM(step, this->getPWMValue(step, brightness));
*/
}
@ -63,7 +68,7 @@ uint16_t Stairs::getPWMValue(uint8_t step, uint16_t brightness)
return brightness;
}
if (step < 0 || step >= StepCount)
if (step < 0 || step >= getCount())
{
_dln("Step out of bounds, returning input");
return brightness;
@ -141,7 +146,7 @@ void Stairs::writeRange()
Header header;
header.version = 1;
header.useScaling = this->useScaling;
header.rangeCount = StepCount;
header.rangeCount = getCount();
f.write((uint8_t*)&header, sizeof(Header));
f.write((uint8_t*)&this->ranges, sizeof(this->ranges));

View File

@ -2,8 +2,8 @@
#define __Stairs
#include "components/PCA9685.h"
#include "modes/base.h"
#include "config.h"
#include "mode.h"
struct Range
@ -19,7 +19,7 @@ class Stairs : public IStairs
PCA9685* pwmDriver;
bool useScaling;
Range ranges[StepCount];
Range ranges[16];
protected:
void readRange();

View File

@ -1,23 +0,0 @@
$output = & GitVersion /output json /nofetch
if ($LASTEXITCODE -ne 0) {
Write-Verbose "$output"
throw "GitVersion failed with exit code: $LASTEXITCODE"
}
$version = $output | ConvertFrom-Json
@"
#ifndef __Version
#define __Version
static const char* FirmwareVersion = "{0}";
#endif
"@ -f $version.FullSemVer | Out-File -Encoding UTF8 .\src\version.h
@"
module.exports =
{{
Version: "{0}"
}};
"@ -f $version.FullSemVer | Out-File -Encoding UTF8 .\web\version.js

View File

@ -1,2 +0,0 @@
& .\updateversion.ps1
& platformio run --target upload

View File

@ -1,3 +0,0 @@
{
"directory": "static/bower_components"
}

View File

@ -1,160 +1,248 @@
var fs = require('fs');
var md5File = require('md5-file');
var express = require('express');
var semverUtils = require('semver-utils')
var client = require('./client');
var httpPort = 3127;
var stairsHost = '10.138.2.25';
var stairsUdpPort = 3126;
var firmwareFile = './update/firmware.bin';
var alwaysUpdate = true;
function requireNoCache(filename)
function startApp()
{
delete require.cache[require.resolve(filename)];
return require(filename);
}
function isNewer(version1, version2)
{
if (alwaysUpdate) return true;
if (version1.major > version2.major) return true;
if (version1.major < version2.major) return false;
if (version1.minor > version2.minor) return true;
if (version1.minor < version2.minor) return false;
if (version1.patch > version2.patch) return true;
if (version1.patch < version2.patch) return false;
if (parseInt(version1.build, 10) > parseInt(version2.build, 10)) return true;
return false;
}
client.init(stairsHost, stairsUdpPort);
var app = express();
app.get('/ping', function(req, res)
{
client.ping(function(data, error)
{
if (error)
res.status(500);
res.send(data);
var i18n = new VueI18n({
locale: navigator.language,
fallbackLocale: 'en',
messages: messages
});
});
app.get('/getMode', function(req, res)
{
client.getMode(function(data, error)
{
if (error)
res.status(500);
var app = new Vue({
el: '#app',
res.send(data);
});
});
i18n: i18n,
app.get('/setMode/:mode', function(req, res)
{
client.setMode(req.params.mode, req.query, function(data, error)
{
if (error)
res.status(500);
data: {
loading: true,
saving: false,
loadingIndicator: '|',
res.send(data);
});
});
activeTab: 'status',
app.get('/getRange', function(req, res)
{
client.getRange(function(data, error)
{
if (error)
res.status(500);
version: {
systemID: 'loading...',
version: 'loading...',
},
res.send(data);
});
});
wifiStatus: {
ap: {
enabled: false,
ip: '0.0.0.0'
},
station: {
enabled: false,
status: 0,
ip: '0.0.0.0'
}
},
app.get('/setRange', function(req, res)
{
client.setRange(req.query, function(data, error)
{
if (error)
res.status(500);
connection: {
hostname: null,
accesspoint: true,
station: false,
ssid: null,
password: null,
dhcp: true,
ip: null,
subnetmask: null,
gateway: null
},
res.send(data);
});
});
steps: [
{ value: 50 },
{ value: 0 },
{ value: 0 },
{ value: 0 },
{ value: 0 },
{ value: 70 },
{ value: 0 },
{ value: 0 },
{ value: 0 },
{ value: 0 },
{ value: 25 },
{ value: 0 },
{ value: 0 },
{ value: 0 }
]
},
app.get('/updateFirmware', function(req, res)
{
client.updateFirmware(req.query, function(data, error)
{
if (error)
res.status(500);
res.send(data);
});
})
app.get('/checkUpdate', function(req, res)
{
if (!fs.existsSync(firmwareFile))
{
console.log('checkUpdate: ' + firmwareFile + ' not found!');
res.sendStatus(304);
return;
}
var version = requireNoCache('./version.js');
var deviceVersion = semverUtils.parse(req.headers['x-esp8266-version']);
var localVersion = semverUtils.parse(version.Version);
console.log('checkUpdate:');
console.log(' Device version = ' + semverUtils.stringify(deviceVersion));
console.log(' Local version = ' + semverUtils.stringify(localVersion));
if (isNewer(localVersion, deviceVersion))
{
console.log('Sending update');
md5File(firmwareFile, function(err, hash)
created: function()
{
if (err)
var self = this;
document.title = i18n.t('title');
self.startLoadingIndicator();
self.updateWiFiStatus();
setInterval(self.updateWiFiStatus, 5000);
axios.get('/api/version')
.then(function(response)
{
if (typeof response.data == 'object')
self.version = response.data;
})
.catch(function(error)
{
console.log(error);
});
axios.all([
axios.get('/api/connection')
.then(function(response)
{
if (typeof response.data == 'object')
self.connection = response.data;
})
.catch(function(error)
{
console.log(error);
})/*,
axios.get('/api/actions')
.then(function(response)
{
if (typeof response.data == 'object')
self.actions = response.data;
})
.catch(function(error)
{
console.log(error);
})*/
])
.then(axios.spread(function(acct, perms) {
self.stopLoadingIndicator();
self.loading = false;
}));
},
methods: {
applyConnection: function()
{
res.sendStatus(500);
return;
var self = this;
if (self.saving) return;
self.saving = true;
axios.post('/api/connection', {
hostname: self.connection.hostname,
accesspoint: self.connection.accesspoint,
station: self.connection.station,
ssid: self.connection.ssid,
password: self.connection.password,
dhcp: self.connection.dhcp,
ip: self.connection.ip,
subnetmask: self.connection.subnetmask,
gateway: self.connection.gateway,
})
.then(function(response)
{
})
.catch(function(error)
{
console.log(error);
})
.then(function()
{
self.saving = false;
})
},
startLoadingIndicator: function()
{
var self = this;
self.loadingStage = 0;
self.loadingTimer = setInterval(function()
{
self.loadingStage++;
console.log(self.loadingStage);
switch (self.loadingStage)
{
case 1: self.loadingIndicator = '/'; break;
case 2: self.loadingIndicator = '-'; break;
case 3: self.loadingIndicator = '\\'; break;
case 4: self.loadingIndicator = '|'; self.loadingStage = 0; break;
}
}, 250);
},
stopLoadingIndicator: function()
{
clearInterval(this.loadingTimer);
},
getWiFiStationStatus: function()
{
if (!this.wifiStatus.station.enabled)
return 'disconnected';
switch (this.wifiStatus.station.status)
{
case 0: // WL_IDLE_STATUS
case 2: // WL_SCAN_COMPLETED
return 'connecting';
case 1: // WL_NO_SSID_AVAIL
case 4: // WL_CONNECT_FAILED
case 5: // WL_CONNECTION_LOST
return 'error';
case 3: // WL_CONNECTED
return 'connected';
case 6: // WL_DISCONNECTED
default:
return 'disconnected';
}
},
getWiFiStationStatusText: function()
{
if (!this.wifiStatus.station.enabled)
return i18n.t('wifiStatus.stationmode.disabled');
switch (this.wifiStatus.station.status)
{
case 0: // WL_IDLE_STATUS
return i18n.t('wifiStatus.stationmode.idle');
case 1: // WL_NO_SSID_AVAIL
return i18n.t('wifiStatus.stationmode.noSSID');
case 2: // WL_SCAN_COMPLETED
return i18n.t('wifiStatus.stationmode.scanCompleted');
case 3: // WL_CONNECTED
return this.wifiStatus.station.ip;
case 4: // WL_CONNECT_FAILED
return i18n.t('wifiStatus.stationmode.connectFailed');
case 5: // WL_CONNECTION_LOST
return i18n.t('wifiStatus.stationmode.connectionLost');
case 6: // WL_DISCONNECTED
default:
return i18n.t('wifiStatus.stationmode.disconnected');
}
},
updateWiFiStatus: function()
{
var self = this;
if (self.saving) return;
axios.get('/api/connection/status')
.then(function(response)
{
if (typeof response.data == 'object')
self.wifiStatus = response.data;
})
.catch(function(error)
{
console.log(error);
});
}
res.set('Content-Length', fs.statSync(firmwareFile).size);
res.set('x-MD5', hash);
res.download(firmwareFile);
});
}
else
{
console.log('No update required');
res.sendStatus(304);
}
});
app.use(express.static(__dirname + '/static'));
app.listen(httpPort, function ()
{
console.log('Stairs ReST service running on port ' + httpPort);
});
}
});
}

View File

@ -1,26 +0,0 @@
{
"name": "stairs",
"description": "Stairs lighting project",
"main": "index.html",
"authors": [
"Mark van Renswoude"
],
"license": "ISC",
"homepage": "",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"src/bower_components"
],
"dependencies": {
"knockout": "^3.4.2",
"jquery": "^3.2.1",
"crossroads": "^0.12.2",
"hasher": "^1.2.0",
"requirejs": "^2.3.3",
"text": "requirejs/text#^2.0.15",
"bootstrap": "v4.0.0-alpha.6",
"nprogress": "^0.2.0"
}
}

View File

@ -1,342 +0,0 @@
var dgram = require('dgram');
var protocol = require('./protocol');
var BufferReader = require('buffer-reader');
var responseHandlers = {};
function registerResponseHandler(command, callback)
{
if (!responseHandlers.hasOwnProperty(command))
responseHandlers[command] = [callback];
else
responseHandlers[command].push(callback);
}
function callResponseHandlers(command, reader, error)
{
if (!responseHandlers.hasOwnProperty(command))
return;
newHandlers = [];
responseHandlers[command].forEach(function(callback)
{
if (!callback(reader, error))
newHandlers.push(callback);
});
responseHandlers[command] = newHandlers;
}
var serverHost = '';
var serverPort = 0;
var client = dgram.createSocket('udp4');
client.on('message', function (message, remote)
{
console.log(message.toString('hex'));
if (message.length < 2)
return;
var reader = new BufferReader(message);
if (reader.nextInt8() !== protocol.Command.Reply)
return;
var command = reader.nextInt8();
if (command === protocol.Command.Error)
callResponseHandlers(reader.nextInt8(), reader, true)
else
callResponseHandlers(command, reader, false);
});
function requestResponse(buffer, callback, withTimeout)
{
if (buffer === null || buffer.length == 0) return;
console.log('> ' + buffer.toString('hex'));
var command = buffer.readInt8(0);
var cancelled = false;
if (typeof(withTimeout) == 'undefined') withTimeout = true;
if (withTimeout)
{
var timeout = setTimeout(function()
{
cancelled = true;
callback(null, true);
clearTimeout(timeout);
}, 2000);
}
registerResponseHandler(command, function(reader, error)
{
if (cancelled) return;
if (withTimeout) clearTimeout(timeout);
callback(reader, error);
return true;
});
client.send(buffer, 0, buffer.length, serverPort, serverHost, function(err, bytes)
{
if (err)
onError();
});
}
function readModeData(mode, reader)
{
switch (mode)
{
case protocol.Mode.Static:
return {
brightness: reader.nextInt16LE(),
easeTime: reader.nextInt16LE()
};
case protocol.Mode.Custom:
var values = [];
while (reader.tell() < reader.buf.length)
values.push(reader.nextInt16LE());
return {
brightness: values
};
case protocol.Mode.Alternate:
return {
interval: reader.nextInt16LE(),
brightness: reader.nextInt16LE()
};
case protocol.Mode.Slide:
return {
interval: reader.nextInt16LE(),
brightness: reader.nextInt16LE(),
direction: reader.nextInt8(),
fadeOutTime: reader.nextInt16LE()
};
}
return null;
}
function readRangeData(reader)
{
var data = { useScaling: reader.nextInt8() == 1, values: [] };
while (reader.tell() < reader.buf.length)
data.values.push({ start: reader.nextInt16LE(), end: reader.nextInt16LE() });
return data;
}
function lsb(value) { return value & 0xFF; }
function msb(value) { return (value >> 8) & 0xFF; }
function getBrightness(value)
{
if (typeof(value) == 'string' && value.substr(-1) === '%')
return (Number(value.substr(0, value.length - 1)) * 4096 / 100);
return Number(value) || 0;
}
function writeModeData(mode, data)
{
switch (mode)
{
case protocol.Mode.Static:
var brightness = getBrightness(data.brightness);
return new Buffer([protocol.Command.SetMode, mode, lsb(brightness), msb(brightness), lsb(500), msb(500)]);
case protocol.Mode.Custom:
var brightness = typeof(data.brightness) !== 'undefined' ? data.brightness.split(',') : [];
var valueCount = Math.min(16, brightness.length);
var buffer = Buffer.alloc(2 + (valueCount * 2));
buffer.writeUInt8(protocol.Command.SetMode, 0);
buffer.writeUInt8(mode, 1);
for (var index = 0; index < valueCount; index++)
buffer.writeUInt16LE(getBrightness(brightness[index]), 2 + (index * 2));
return buffer;
case protocol.Mode.Alternate:
var brightness = getBrightness(data.brightness);
if (typeof(data.interval) == 'undefined') data.interval = 500;
return new Buffer([protocol.Command.SetMode, mode,
lsb(data.interval), msb(data.interval),
lsb(brightness), msb(brightness)]);
case protocol.Mode.Slide:
var brightness = getBrightness(data.brightness);
if (typeof(data.interval) == 'undefined') data.interval = 500;
if (typeof(data.direction) == 'undefined') data.direction = 0;
if (typeof(data.fadeOutTime) == 'undefined') data.fadeOutTime = 0;
return new Buffer([protocol.Command.SetMode, mode,
lsb(data.interval), msb(data.interval),
lsb(brightness), msb(brightness),
data.direction,
lsb(data.fadeOutTime), msb(data.fadeOutTime)]);
}
}
function writeRangeData(data)
{
var start = typeof(data.start) !== 'undefined' ? data.start.split(',') : [];
var end = typeof(data.end) !== 'undefined' ? data.end.split(',') : [];
var valueCount = Math.min(16, start.length, end.length);
var buffer = Buffer.alloc(2 + (valueCount * 4));
buffer.writeUInt8(protocol.Command.SetRange, 0);
buffer.writeUInt8(data.useScaling ? 1 : 0, 1);
for (var index = 0; index < valueCount; index++)
{
buffer.writeUInt16LE(getBrightness(start[index]), 2 + (index * 4));
buffer.writeUInt16LE(getBrightness(end[index]), 4 + (index * 4));
}
return buffer;
}
module.exports =
{
init: function(host, port)
{
serverHost = host;
serverPort = port;
},
ping: function(callback)
{
requestResponse(new Buffer([protocol.Command.Ping]),
function(reader, error)
{
if (!error)
{
callback(
{
stepCount: reader.nextInt8()
}, false);
}
else
callback(null, true);
});
},
getMode: function(callback)
{
requestResponse(new Buffer([protocol.Command.GetMode]),
function(reader, error)
{
if (!error)
{
var data = { mode: reader.nextInt8() };
data.data = readModeData(data.mode, reader);
callback(data, false);
}
else
callback(null, true);
});
},
setMode: function(mode, data, callback)
{
if (!protocol.Mode.hasOwnProperty(mode))
return;
requestResponse(writeModeData(protocol.Mode[mode], data),
function(reader, error)
{
if (!error)
{
var data = { mode: reader.nextInt8() };
data.data = readModeData(data.mode, reader);
callback(data, false);
}
else
callback(null, true);
});
},
getRange: function(callback)
{
requestResponse(new Buffer([protocol.Command.GetRange]),
function(reader, error)
{
if (!error)
{
callback(readRangeData(reader), false);
}
else
callback(null, true);
});
},
setRange: function(data, callback)
{
requestResponse(writeRangeData(data),
function(reader, error)
{
if (!error)
{
callback(readRangeData(reader), false);
}
else
callback(null, true);
});
},
updateFirmware: function(data, callback)
{
if (typeof(data.host) == 'undefined') data.host = '';
if (typeof(data.port) == 'undefined') data.port = 80;
if (typeof(data.path) == 'undefined') data.path = '';
var buffer = Buffer.alloc(1 + (data.host.length + 1) + 2 + (data.path.length + 1));
buffer.writeUInt8(protocol.Command.UpdateFirmware, 0);
var position = 1;
buffer.writeUInt16LE(data.port, position);
position += 2;
buffer.write(data.host, position);
position += data.host.length;
buffer.writeUInt8(0, position);
position++;
buffer.write(data.path, position);
position += data.path.length;
buffer.writeUInt8(0, position);
requestResponse(buffer,
function(reader, error)
{
if (!error)
{
var data = { hasUpdates: reader.nextInt8() == 1 };
callback(data, false);
}
else
callback(null, true);
}, false);
}
}

1
web/dist/bundle.css vendored Normal file

File diff suppressed because one or more lines are too long

1
web/dist/bundle.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,96 +0,0 @@
'use strict';
var gulp = require('gulp');
var ts = require('gulp-typescript');
var uglify = require('gulp-uglify');
var sass = require('gulp-sass');
var cleanCSS = require('gulp-clean-css');
var concat = require('gulp-concat');
var watch = require('gulp-debounced-watch');
var plumber = require('gulp-plumber');
var config =
{
dest: 'static/assets/dist/',
typescriptBase: 'static/assets/ts/',
sassBase: 'static/assets/sass/',
assets: ['static/assets/ts/**/*.html', 'static/assets/js/**/*.js']
};
config.typescriptSrc = config.typescriptBase + '**/*.ts';
config.sassSrc = config.sassBase + '**/*.scss';
gulp.task('default',
[
'compileTypescript',
'compileSass',
'copyAssets'
],
function(){});
gulp.task('watch',
[
'compileTypescript',
'compileSass',
'copyAssets'
],
function()
{
watch(config.typescriptSrc, function() { gulp.start('compileTypescript'); });
watch(config.sassSrc, function() { gulp.start('compileSass'); });
watch(config.assets, function() { gulp.start('copyAssets'); });
});
gulp.task('compileTypescript', function()
{
return gulp.src(config.typescriptSrc, { base: config.typescriptBase })
.pipe(plumber({
errorHandler: function (error)
{
console.log(error.message);
this.emit('end');
}}))
.pipe(ts(
{
noImplicitAny: true,
removeComments: true,
preserveConstEnums: true,
sourceMap: true,
module: 'amd'
}))
.pipe(uglify())
.pipe(gulp.dest(config.dest));
});
gulp.task('compileSass', function()
{
return gulp.src(config.sassSrc)
.pipe(plumber({
errorHandler: function (error)
{
console.log(error.message);
this.emit('end');
}}))
.pipe(sass())
.pipe(concat('bundle.css'))
.pipe(cleanCSS())
.pipe(gulp.dest(config.dest));
});
gulp.task('copyAssets', function()
{
return gulp.src(config.assets)
.pipe(plumber({
errorHandler: function (error)
{
console.log(error.message);
this.emit('end');
}}))
.pipe(gulp.dest(config.dest));
});

124
web/index.html Normal file
View File

@ -0,0 +1,124 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<meta name="theme-color" content="#000000">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="bundle.css">
<script src="bundle.js"></script>
</head>
<body>
<div id="app">
<div v-cloak>
<div id="container">
<div class="header">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXBJREFUeNrsWdENgjAQLcYBcAPcACdQN4AN2MC4gRsYJ9ENdAPYADaADepdUhM1qFjurgp9ScMHgd713V3ftUp5eHgMF1rrGEau6VHD2HMbH5qJOLHra+fkzbsYRshM8pLTgUIgSgvuMMoYw+iMYTr6QhNYMrNiNywILlyVKdcyyPsmcRsyU50kgHtQQu2AdNJFpDkAK4I/LIWMb2AsIBcq0iRGeQGPTZfV6QE0+gDGF2rosGEgMQxIAhnZAiPN84upRf0/OlpsLCBp3yq0chgtCUUZrRw6QDO3EWHSqF9tarZaSKJXeJDdbQlsE0KD6JN/KoRsGhxXKClCKHJIfkThwMWhA6dBSolRijkJOd1ZUv9yQ9OpqbHpiaUVaEbZE7tIIjoBKXysos1c4V8ebLEdbv2bcMsE7gjuBdvXRSJ4F+/wqIXXrIGwmX3zwacLDheNO91OjLQKd14VMDCnYgCxVjI3NTe1mSoPD49x4SrAAG9qPn4eovCMAAAAAElFTkSuQmCC" />
<h1>{{ $t('title') }}</h1>
<h2>{{ version.systemID !== null ? $t('systemID') + ': ' + version.systemID : '' }}</h2>
<div class="wifistatus">
<div class="connection">
<div class="indicator" :data-status="wifiStatus.ap.enabled ? 'connected' : 'disconnected'"></div> {{ $t('wifiStatus.accesspoint.title') }} {{ wifiStatus.ap.enabled ? wifiStatus.ap.ip : $t('wifiStatus.accesspoint.disabled') }}
</div>
<div class="connection">
<div class="indicator" :data-status="getWiFiStationStatus()"></div> {{ $t('wifiStatus.stationmode.title') }} {{ getWiFiStationStatusText() }}
</div>
</div>
</div>
<div v-if="loading" class="loading">
{{ $t('loading') }} {{ loadingIndicator }}
</div>
<div v-if="!loading">
<div class="tabs">
<button class="button" :class="{ 'button-outline': activeTab != 'status' }" @click="activeTab = 'status'">{{ $t('status.tabTitle') }}</button>
<button class="button" :class="{ 'button-outline': activeTab != 'triggers' }" @click="activeTab = 'triggers'">{{ $t('triggers.tabTitle') }}</button>
<button class="button" :class="{ 'button-outline': activeTab != 'connection' }" @click="activeTab = 'connection'">{{ $t('connection.tabTitle') }}</button>
</div>
<div v-if="activeTab == 'status'">
<h3>{{ $t('status.title') }}</h3>
<div class="slidecontainer" v-for="(step, index) in steps">
{{ index + 1 }}
<input type="range" min="0" max="100" class="slider" v-model="step.value">
{{ step.value }}
</div>
</div>
<div v-if="activeTab == 'triggers'">
<form @submit.prevent="applyTriggers">
<fieldset>
<h3>{{ $t('triggers.timeTitle') }}</h3>
</fieldset>
<fieldset>
<h3>{{ $t('triggers.motionTitle') }}</h3>
</fieldset>
</form>
</div>
<div v-if="activeTab == 'connection'">
<form @submit.prevent="applyConnection">
<fieldset>
<h3>{{ $t('connection.title') }}</h3>
<input type="checkbox" id="accesspoint" v-model="connection.accesspoint">
<label class="label-inline" for="accesspoint">{{ $t('connection.accesspoint') }}</label>
<span class="hint">{{ $t('connection.accesspointHint') }}</span>
<input type="checkbox" id="station" v-model="connection.station">
<label class="label-inline" for="station">{{ $t('connection.stationmode') }}</label>
<span class="hint">{{ $t('connection.stationmodeHint') }}</span>
<label for="ssid">{{ $t('connection.ssid') }}</label>
<input type="text" id="ssid" v-model="connection.ssid" :disabled="!connection.station">
<label for="password">{{ $t('connection.password') }}</label>
<input type="password" id="password" v-model="connection.password" :disabled="!connection.station">
<input type="checkbox" id="dhcp" v-model="connection.dhcp" :disabled="!connection.station">
<label class="label-inline" for="dhcp">{{ $t('connection.dhcp') }}</label>
<span class="hint">{{ $t('connection.dhcpHint') }}</span>
<div class="suboptions">
<label for="ip">{{ $t('connection.ipaddress') }}</label>
<input type="text" id="ip" v-model="connection.ip" :disabled="!connection.station || connection.dhcp">
<label for="subnetmask">{{ $t('connection.subnetmask') }}</label>
<input type="text" id="subnetmask" v-model="connection.subnetmask" :disabled="!connection.station || connection.dhcp">
<label for="gateway">{{ $t('connection.gateway') }}</label>
<input type="text" id="gateway" v-model="connection.gateway" :disabled="!connection.station || connection.dhcp">
</div>
<label for="hostname">{{ $t('connection.hostname') }}</label>
<input type="text" :placeholder="$t('connection.hostnamePlaceholder')" id="hostname" v-model="connection.hostname" :disabled="!connection.station">
<div class="buttons">
<input class="button-primary" type="submit" :disabled="saving" :value="saving ? $t('applyButtonSaving') : $t('applyButton')">
</div>
</fieldset>
</form>
</div>
</div>
<div class="clearfix"></div>
</div>
<div class="version">
{{ $t('copyright') }}<br>
{{ version.version !== null ? $t('firmwareVersion') + version.version : '' }}
</div>
</div>
</div>
<script language="javascript">
console.log('Initializing...');
startApp();
</script>
</body>
</html>

127
web/lang.js Normal file
View File

@ -0,0 +1,127 @@
var messages = {
en: {
title: 'Stairs',
systemID: 'System ID',
firmwareVersion: 'Firmware version: ',
copyright: 'Copyright © 2017 Mark van Renswoude',
loading: 'Please wait, loading configuration...',
applyButton: 'Apply',
applyButtonSaving: 'Saving...',
wifiStatus: {
accesspoint: {
title: 'AP: ',
disabled: 'Disabled'
},
stationmode: {
title: 'WiFi: ',
disabled: 'Disabled',
idle: 'Idle',
noSSID: 'SSID not found',
scanCompleted: 'Scan completed',
connectFailed: 'Failed to connect',
connectionLost: 'Connection lost',
disconnected: 'Disconnected'
}
},
status: {
tabTitle: 'Status',
title: 'Current status'
},
triggers: {
tabTitle: 'Triggers',
timeTitle: 'Time',
motionTitle: 'Motion'
},
connection: {
tabTitle: 'Connection',
title: 'Connection parameters',
accesspoint: 'Enable access point',
accesspointHint: 'Allows for a direct connection from your device to this Stairs module for configuration purposes. The Stairs configuration is available on http://192.168.1.4/ when you are connected to it. Turn it off as soon as station mode is configured, as it is not secured in any way. You can always turn this option back on by pushing the access point button until the LED lights up.',
stationmode: 'Enable station mode',
stationmodeHint: 'Connect this Stairs module to your own WiFi router. Please enter the SSID, password and further configuration below.',
ssid: 'SSID',
password: 'Password',
dhcp: 'Use DHCP',
dhcpHint: 'Automatically assigns an IP address to this Stairs module. You probably want to keep this on unless you know what you\'re doing.',
ipaddress: 'IP address',
subnetmask: 'Subnet mask',
gateway: 'Gateway',
hostname: 'Hostname',
hostnamePlaceholder: 'Default: mac address'
}
},
nl: {
title: 'Trap',
systemID: 'Systeem ID',
firmwareVersion: 'Firmware versie: ',
copyright: 'Copyright © 2017 Mark van Renswoude',
loading: 'Een ogenblik geduld, bezig met laden van configuratie...',
applyButton: 'Apply',
applyButtonSaving: 'Saving...',
wifiStatus: {
accesspoint: {
title: 'AP: ',
disabled: 'Uitgeschakeld'
},
stationmode: {
title: 'WiFi: ',
disabled: 'Uitgeschakeld',
idle: 'Slaapstand',
noSSID: 'SSID niet gevonden',
scanCompleted: 'Scan afgerond',
connectFailed: 'Kan geen verbinding maken',
connectionLost: 'Verbinding verloren',
disconnected: 'Niet verbonden'
}
},
status: {
tabTitle: 'Status',
title: 'Huidige status'
},
triggers: {
tabTitle: 'Triggers',
timeTitle: 'Tijd',
motionTitle: 'Beweging'
},
connection: {
tabTitle: 'Verbinding',
title: 'Verbinding configuratie',
accesspoint: 'Access point inschakelen',
accesspointhint: 'Maakt het mogelijk om een directe connectie vanaf een apparaat naar deze Trap module te maken om de module te configureren. De Trap module is te benaderen via http://192.168.1.4/ nadat je connectie hebt gemaakt. Schakel deze optie uit na het configureren, aangezien deze niet beveiligd is. Je kunt deze optie ook inschakelen door op de Access point knop te drukken totdat de LED aan gaat.',
stationmode: 'Verbinding met WiFi maken',
stationmodehint: 'Verbind deze Trap module aan je eigen WiFi router. Vul hieronder het SSID en wachtwoord in, en configureer eventuel de overige opties.',
ssid: 'SSID',
password: 'Wachtwoord',
dhcp: 'Gebruik DHCP',
dhcphint: 'Automatisch een IP adres toewijzen aan deze Trap module. Waarschijnlijk wil je deze optie aan laten, tenzij je weet waar je mee bezig bent.',
ipaddress: 'IP adres',
subnetmask: 'Subnet masker',
gateway: 'Gateway',
hostname: 'Hostnaam',
hostnamePlaceholder: 'Standaard: mac adres'
}
}
}

333
web/logo.ai Normal file
View File

@ -0,0 +1,333 @@
%PDF-1.5 %âãÏÓ
1 0 obj <</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R 21 0 R]/Order 22 0 R/RBGroups[]>>/OCGs[5 0 R 21 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 9212/Subtype/XML/Type/Metadata>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
<xmp:CreatorTool>Adobe Illustrator CS6 (Windows)</xmp:CreatorTool>
<xmp:CreateDate>2017-12-30T16:13+01:00</xmp:CreateDate>
<xmp:MetadataDate>2017-12-30T16:17:16+01:00</xmp:MetadataDate>
<xmp:ModifyDate>2017-12-30T16:17:16+01:00</xmp:ModifyDate>
<xmp:Thumbnails>
<rdf:Alt>
<rdf:li rdf:parseType="Resource">
<xmpGImg:width>248</xmpGImg:width>
<xmpGImg:height>256</xmpGImg:height>
<xmpGImg:format>JPEG</xmpGImg:format>
<xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAD4AwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FX//2Q==</xmpGImg:image>
</rdf:li>
</rdf:Alt>
</xmp:Thumbnails>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
<xmpTPg:NPages>1</xmpTPg:NPages>
<xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
<xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
<xmpTPg:MaxPageSize rdf:parseType="Resource">
<stDim:w>512.000000</stDim:w>
<stDim:h>512.000000</stDim:h>
<stDim:unit>Points</stDim:unit>
</xmpTPg:MaxPageSize>
<xmpTPg:SwatchGroups>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Default Swatch Group</xmpG:groupName>
<xmpG:groupType>0</xmpG:groupType>
</rdf:li>
</rdf:Seq>
</xmpTPg:SwatchGroups>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:format>application/pdf</dc:format>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
<illustrator:Type>Document</illustrator:Type>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#">
<xmpMM:DocumentID>xmp.did:89DEF0EC73EDE7119CCADB31B93B2005</xmpMM:DocumentID>
<xmpMM:InstanceID>uuid:b03a2483-4f32-4465-b083-e0550ab05b88</xmpMM:InstanceID>
<xmpMM:OriginalDocumentID>xmp.did:89DEF0EC73EDE7119CCADB31B93B2005</xmpMM:OriginalDocumentID>
<xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
<xmpMM:DerivedFrom rdf:parseType="Resource"/>
<xmpMM:History>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:89DEF0EC73EDE7119CCADB31B93B2005</stEvt:instanceID>
<stEvt:when>2017-12-30T16:13:01+01:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CS6 (Windows)</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
</rdf:Seq>
</xmpMM:History>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
endstream endobj 3 0 obj <</Count 1/Kids[7 0 R]/Type/Pages>> endobj 7 0 obj <</ArtBox[72.1367 53.875 458.887 458.125]/BleedBox[0.0 0.0 512.0 512.0]/Contents 23 0 R/LastModified(D:20171230161716+02'00')/MediaBox[0.0 0.0 512.0 512.0]/Parent 3 0 R/PieceInfo<</Illustrator 24 0 R>>/Resources<</ExtGState<</GS0 25 0 R>>/Properties<</MC0 21 0 R>>>>/Thumb 26 0 R/TrimBox[0.0 0.0 512.0 512.0]/Type/Page>> endobj 23 0 obj <</Filter/FlateDecode/Length 177>>stream
H‰”Á
Â0 †ïyŠ¼Àº&M¶õj•<6A>0dîàˆxqÂôàëÛ
º¦ ¡¥)ßßÐr°ì‚ÅÕ: L`Q‰_«HÛí¼aª} *†±Ù"”í`ñ|‡)¶6VdÄáºFfÂãévnØ8'ñ|<7C>úEÞÿàûÿó]•ûD yšó¿L9{¼7\Q<>âr ¥g¹…1ÄŠñ) V5º€¿íM.Wÿ!7]üŠž CÕPt
endstream endobj 26 0 obj <</BitsPerComponent 8/ColorSpace 27 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 64/Length 40/Width 64>>stream
8;Z]L!=]#/!5bE.$"(^o%O_;W!8uZ9(]Y:<E5V~>
endstream endobj 27 0 obj [/Indexed/DeviceRGB 255 28 0 R] endobj 28 0 obj <</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>
endstream endobj 21 0 obj <</Intent 29 0 R/Name(Logo)/Type/OCG/Usage 30 0 R>> endobj 29 0 obj [/View/Design] endobj 30 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 25 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 24 0 obj <</LastModified(D:20171230161716+02'00')/Private 31 0 R>> endobj 31 0 obj <</AIMetaData 32 0 R/AIPrivateData1 33 0 R/AIPrivateData2 34 0 R/ContainerVersion 11/CreatorVersion 16/NumBlock 2/RoundtripStreamType 1/RoundtripVersion 16>> endobj 32 0 obj <</Length 964>>stream
%!PS-Adobe-3.0
%%Creator: Adobe Illustrator(R) 16.0
%%AI8_CreatorVersion: 16.0.0
%%For: (PsychoMark) ()
%%Title: (logo.ai)
%%CreationDate: 12/30/2017 4:17 PM
%%Canvassize: 16383
%%BoundingBox: 113 218 501 623
%%HiResBoundingBox: 113.6367 218.375 500.3867 622.625
%%DocumentProcessColors:
%AI5_FileFormat 12.0
%AI12_BuildNumber: 682
%AI3_ColorUsage: Color
%AI7_ImageSettings: 0
%%RGBProcessColor: 0 0 0 ([Registration])
%AI3_Cropmarks: 41.5 164.5 553.5 676.5
%AI3_TemplateBox: 297.5 420.5 297.5 420.5
%AI3_TileBox: -8.5 24.5 603.5 816.5
%AI3_DocumentPreview: None
%AI5_ArtSize: 14400 14400
%AI5_RulerUnits: 2
%AI9_ColorModel: 1
%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0
%AI5_TargetResolution: 800
%AI5_NumLayers: 1
%AI9_OpenToView: -1232 1218 0.5 1789 914 26 0 0 82 117 0 0 0 1 1 1 1 1 0 1
%AI5_OpenViewLayers: 7
%%PageOrigin:0 0
%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9
%AI9_Flatten: 1
%AI12_CMSettings: 00.MS
%%EndComments
endstream endobj 33 0 obj <</Length 2175>>stream
%%BoundingBox: 113 218 501 623
%%HiResBoundingBox: 113.6367 218.375 500.3867 622.625
%AI7_Thumbnail: 124 128 8
%%BeginData: 2021 Hex Bytes
%0000330000660000990000CC0033000033330033660033990033CC0033FF
%0066000066330066660066990066CC0066FF009900009933009966009999
%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66
%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333
%3333663333993333CC3333FF3366003366333366663366993366CC3366FF
%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99
%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033
%6600666600996600CC6600FF6633006633336633666633996633CC6633FF
%6666006666336666666666996666CC6666FF669900669933669966669999
%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33
%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF
%9933009933339933669933999933CC9933FF996600996633996666996699
%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33
%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF
%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399
%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933
%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF
%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC
%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699
%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33
%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100
%000011111111220000002200000022222222440000004400000044444444
%550000005500000055555555770000007700000077777777880000008800
%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB
%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF
%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF
%524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
%FDFCFFFDFCFFFDFCFFFDF7FFFF
%%EndData
endstream endobj 34 0 obj <</Length 24380>>stream
%AI12_CompressedDataxœÜ½gwò:Ó0z>ïµò(Iè`z ½)Š)¡Æ†]žïo?ÜdãFÙïÙç¹÷ºsg¤Ñhšf¤;c£åÊL¶#Òåw†›?îîr9Üo©˜ýl¨¬VzOÁŸ¬MÁr°U¦°-;$E/¶›zÆ<-Â÷­ úŸñ|û4¤6ƒÕo/ö+<Ymg[÷paãñ<C3A3>÷óÃ=xäõyü„ÇGxÆ@ üi<¡6ÃÍŸCš^ülòGüðÇìö°™,6³ìöoð«×oðy#† á5„|èyyÑ$ii#wÈ
Ãn8ZnüòùÜ!_¾–ߎkr³oPÛ1IÓ¹íjKÑ1ð$S Š‹ ·îAOÑX3¯o<C2AF>=,V“çÃzDq‡">ô»€Þ}¥‡3ÐmôýTÖ৹߃ŽÑ1"Y³”Å1Ö<7F>&9[  4ú²q<C2B2>©ín  ÞxÝA@”ø úÁßP8ä²íÚäz·„EÃ÷EÃàqÀG€¿Øg®)jæŠÀç^ˆ€ð"^ž@òÏùWÌð¼Ý<C2BC>,m2Ô¾ÅÌP @Ì_öQó°"©×ÍbúËçi;!Wà Dq5D4Aÿy…¿lö<E280B9>š{0±ÛÕa<C395>¸.ÂcPþ¸Ôwä¦½í ®º¼>¿LàHo85D½ƒ/„°DÀ3Àpbî?‚ï!q8ÂpÚ`&ëÔb¶ØĸN†%j1¦7ì3D˜?h îöÿ(÷¶¿`ôû=¹áX+÷„1
á~jA¬…Í$·]É ÑJÜûTøž; ôÃÌ[ƒZl à›?ž™gAcuKÔö°«l¦Û?¬Œè<>c°ÐÁäN õÑø4bbCŽ ð<>oöΦŒ“" ÌSð.ú
þ<EFBFBD>Âõ¼Ÿ'§`
˜_ ?ÉÕv‡æn&†·!µÓ¼±n†”=àa×'C@2ºð›.°€kv€Hè%ÔFöHªá~nÈ®ÈÍ„æ¡3_%<25>g~Ô²õÏz´]-è5ÿ…ÿ¬³w{ÚÔ7L7©=7´·Û•@¦ûH˜djϼóŸAÂ7Cþw<C3BE>熫ÕbF wóÅX¾Ìs»º¸hŒ¨.‡QüˆGvüÆ ÇD…É?…e­Ú¦õ×p?žñ2¢†ÔÔXpz§Ít´uXìIa¾¶ë4u ­ùp†-XKnp®\.MÕežA¿ÿgE­ã©n¶mÐ7°Ž¬@$«ý—Íày®Iƒ´i-€ùAò<41>CþÁUlwi?îp<C3AE>ð é…£¡ˆ} |>ÔŽ°oØ׺ø‚—ûöüö>ý€ßþ2x Óáã0LnÀCᘀ®0¢;~ó‡Áz
? aR`ƒÒ¦Nc¸ê˜d†Ñéï·Ô<C2B7>Cèþ¤œÔÂkŒÁÿ³Boxœ§MR MÌñ<C38C>™&gò„—`‚ú¸ß0é¯JØNs†%ðGÜ <Ü<0F>×ÅgHýÃü@<Mr¸2X<32>#'5rºï WÀøNöi¼j…frø¤9Ù‡ž E ÿQ€ŽúƒÀ8dÿA8[ÐaøÌ`Ev,cîI0å40´ÿaœôÊãÑvHM ^°$€ñ;¶nkF?3Xá
aÛy¹42Mö'ÆŽglz¡ MrÕÞ6ìLw[z{<7B>ûØ—‘?€|ýïz…¾d<C2BE>äÆÍõžå¬Ãqî~„ˆ u»Oµg0Rú‚·þ^¯6 <36> ˆEj1:ìIZnbþ¯€¹¬Ýx<AŠäØÃDz÷þÙÿ³ãHi½ßЃ?‡,ÂñÞöOŒ©ÑZ¡áŸ®¥ó©6ÀÓÔC¥Õv¼$'ºÈÄ5½&ãž?ÀÑE*¼z xøtÌ¢Ô1P¼ù5™âr¢xÕ‰¢<E280B0>áhEêZzfúÿsF8](ÄþÔ/`ÛÿÃÃqŽô~»þˆ¿•EcôÂиëP?§þßX7 CÿµþüïZÊôô¯ÿÿÿ@Ó«Åø<C3B8>÷GBÀ5äŒ{ÅAÿµ˜ìçºf<C2BA>mùŸ<C3B9>Ý"àöinN.fs]â…oúŸ·?¤5¾t íÊ®Ñ٣ⷿ´†õ·>)ô_ç´*Žg´Ý# 8ß]ÇðŽ_úÏØHP¶¶jL¢ýÍÿ†AôÜ¢kr?œ
<EFBFBD>‰^Üó„<C3B3>céâ9¬µSv1ùCÜâÝ 'œçJp `=¤—ÒEAï¶{i»ájÁ±l˜[\“ÝÂÍ wö§ñvE }ËT ™Ã~khé= ÷ù¤P3¯×À À°Üçz{ØfL [­íÞÂMjÃîF¡ÝDië¨a7Ü<E28098>+(•° l2änc¸µ,°ÁžnèÝÌïøЯÅÄ@ ãð…|Þ€"4ƒôî »íŒ"ñ¥Õ˜âc^¿—+7õâ}Ðl÷A³1Ö˜_Á7å°LFK —W4• Š¤IêOÒÐ&ÿÞ£<C39E>Žáh±Zì9ÕñFaX2@ÑIiXÛÝ„[çƒ&4à.,oP£¦¤PAbê‚Ônôð' "8~oH¨P‡räjUø{/,Q.|„YW6òï9Þn&'¾T\P´¢âj»¥Pß: zÁP½µpÅ!É¿Æ8Õ5c<°öv'š­“æ<E2809C>‡r<íá°÷„igödfçZÂ0e²-€\Ùqü»ý“¤vp‡Öxc¼ZìÀê<C380>nýß`õÌ€Hâej<65>_>¢W($9]¢D ÃhF:æÅÇ9YÖ!µåëxÛ­5~geuŠ<|´÷|o!Èï“ÀUÿDÒs^~#)Š¡ãÜBôJý°ß!®ñ! ø¨µáfv€©"<22>íŽW<0F>h4 1[ü¦"[<5B>ÊqÊnÿîö¸w7jsh¹`rŽè&! kµÌTŠ‡ÕŠë!›¹žrš<72>7ùeIq8&3ÙJkiÁL'Mˆ<4D>ƒPn )œ_Ð{ŒÇT ÃΈ€Ÿ¶p¡ààöø<E28099>5UÂÔ“ß…Õg½§Ù¶É«² âxQÃún8T®¦åȃ÷7‰F¼*m±î†A¿JK=<3D>E>ˆ¨¯j4@ŒwVƒÓ)MòâQ[¡ÞË_cÏ µ˜<E28093>àSW¦m7eÜó÷)Œª-XÝŠÊÉŠ6<C5A0>ÂÄðp³_€ <¤±)
ª&IICwµØ<C2B5>zOm—¼?Hh´Þc‰“UA˜OJ<10>HD^ ¾aÑ®±¢ÌTyÐàÄœó%4Wûxˆ‰@W<>Ójv ­ö?IÄr²š9ðŸ`<60> ¢~ƒŒå<06>MbñˆÀCI^ö<>5N•3F<33>\ZPc<50>!Ô<ÐÉta="a¾çt±"«¤0<C2A4>2Mßæñ\®)Ã¥¢¶0¡Ø´ÈÕi×ÈaS0»"ƒß+˜¢æ­Ãˆ›âXM¨3„nÄaûñš<E28093>ç×àyÞîÅÏ9QøÑ€±Q$ã!²Úv,ç5ÖÀ+\C%¯nŠa6˜Ïœa5»K,z ç eNÊÁ½Åe ‚˜ƒ&eŽ5)"“ò¨m<C2A8>!-E<>#jÖ$ n<>¢6 Ý<Lþ®!+2K½¶u©y¬M,¯¡Ðh<C390>@-ØZ\ L<>ôbkLÜN<C39C>bL#<23>$c!ª¸QÃf+ø†Å¹05‡ÏVÒX­=B<Òó³¹wÀ覀ñ-íØQ;ˆz¸Zi4£—Ý t)FÒv †C“°”FÓñvµ°õØß‘¾À…-N÷¶aƆ, Å·#˜Zi€TÖIqQª£J‡áèHIœíuÔ[z¿rO<18>¨Ó<Ý4(ßc_Àˆz^ÚMÖàñj£¿_»‰~ðÌž¾ðŠÜôïvÛN¥°ÛÎTbˆU+Ò†øöX8ªØL´ÏD(µZÀâ÷
ÞúZî·;í2M) ¿J?™ÆÌ&GzÀw@4M £ y
X"”ú\@0˜=F5N¹•6å`[Ü£P'mw4ý¨ŠÙjÈ I/f\ÁûԄˆÝ3Q…‰Z"KIOÃ!=Zì×Ã<C397>~Q&ž˜ã±¯(7\£MÆÛ `ƒ= ò« 6åµ âcNˆ‡}²Í©‰øfÀ¦Êy¤-§@ Ï·Ôÿpî†B³pªÊñÌ­ÎŒl#.<2E> 35¥Íhè©ðÐ4þ©1Rz¼[<5B>¥öq£ñæ(h+m´¶2¾Ï¡0J0e«áN9؆jØÍÖK7¹<37>)6ª6£ar¸>^FíIŽ-=/<2F>U°‡õ \g°„£¶@ @«L"¨ä;?ΓV£1µÝiµ<69>ÔZí(,_/Üo )ZmJ…a©­…D­÷ø¸´ãº(¤ØšJz¢£5¦µã=[YÓÍÞ=YiHD¦ÑŽšn7ªâ¶£<C2B6>³äfÃý“T³ŠA“Ñš‰j“N»7älˆ(´ùÛŠ <0A>^Úh@[yÇÈ)ç£uòÌ@»éùØ餵`+r£WÐ?<3F>²ð$ÍÂrÚàï<C3A0>[¼ù<C2BC>º'׌¢¤; hGC®é쨩BCVeb±7¹¹2!=<3D>¦@ªc…AÇ¡Ø¡Uh¹Ý<C2B9>Õ$jA«M?j19¨;è*¼¯aœŒÖ¡JP³éa3Vã¦àùFC —† ŸÚ ï£fš^Æx<C386>[ZÖWwËmx#G†Üø¦çµõVo|Ú ú4ü½5°q<05> Ã&Ú”kÄmHŽ×ÿ¨9ÜXËí~®ép3FªÜJÑÒ"GD‡<µ—ž"ðšÌoÇ(ì)ï§g¸7qO<1D>Þ…}ÇÆâorÕ ©)9ÞãbƒÛÕdBY%j8<6A>&.* gvFU÷B™·j06oá[(Ùáè-1.&t22æ5ØNÞzå‰Öê” H¦fXša¶O•¤¤ˆØˆªxC†©;”ÃÓ˜Me±3‡S#È·ó5ƒ¼°òñž ZF¬C~áQƒ"Ç ¹ öѦÆæ¸çGmæۿʉܸQ.ŒóлáQ(<28>%ûÞ
„óE6*
mâínÏçÇíÈPgá±ÓpXÏÅa»pžìgeZ¹J%Ì“PŽ¡§<C2A1>TýþÃx{°Ä‡]ç£ÿ¾îʦ©Òz<6D>E£ÓjÉ-†nú6ôZ.„̱ôk)ùHÅjŸ§4u‡‹ßSäΘ ÎÿägNâ6ï»íé„sG§éªÏФã5#ŵzÜggå—Z: [¹ÅCrœw»-³#\µI çw±ð{iŸÿùÊÞ]ÎÌz[£3•Ö~îH†Ì‡b>pûýYYÞšü”xÉB» G§áÎËÇg¦<67>sw”±âíb_éIJø•ŽÑîµ#ï¼;­¥É Aô*~ê‡üôë-œ]¥WÝØ4;ßçæáw¯ˆ"ß÷ù±·öN¤,o Ði:ןõ·àÓýo¾2©³®ÈÏm¦å2o˜Nt‡“@ý±:Æ…qðÅšñDæÎïÈ>;¿éœåµ˜#ödçÑ<<3C><>ÇÃ%ü´p¦µ9ƒÚKx†ajqû'ÙÕ]Ê⢟‡L­uÿ `KÇçð°œP¼ó•ÎlƵãá)î ¯?á°‡žú3Ô¸âu,c^ä8ÿHwåÂ2üæ'&±EÎ3“ì}z°ºœdvn¬™1ôjwé\%a~+8£AX^<5E>¯|„ÌÉpnÛw$:“<>˜odþBp“;0¤dÈn†Óòz ½l ©’Ù¥-äb´Þ/óSÞ3LÜ<17>Žw
¢ Á}5hˆ©@_Ébý”x+T™ö9gá<C3A1>æëù*€ƒ»„#™,8}ùÔì<C394>ôö<C3B4>ˆO~žûh6ùxõl<C3B5>CZeù.| ]ðZš°@¿<05>Ùü;OÒ©@è=ô3δó?ŽüÔSý- ÛlhôúmÜu_3õ\¶‘Ÿ¶¿é߯<Â%èµ AßC“÷ÂÀëèdÝL½˜ÿyä?!O|º¾›sS»Ð0ù7'[a¤õ»®fê5{µ˜·Mª u8Z3K²À~ç~q¤:Ã_fHÉPd˜Ž·÷¦Lûq8œ„¸%¸ÉèRFT ¬ zî¥Þ'w3ßw"•'ŠŸi?âƒÄw¢˜<bw:²Ûh_:_bââ“ËMÃ>©9}@t£ÁIõX+e<06>^Ä7 Ç.þ]´N«î h¿ûl·ýÓ1EB‡f”,Zïw¶Ü<Ô\5wQàW°z[$lZ… dÔ4X]ë{08³-7èp|üÚÌ„ß}oÒyh”WpS©àrŽ¢rÓ]’Õ@“i?M@Ø$£ùl­·”ë/jŠµ+õÂS°x
>ÂW
<³Ï¾Q´5Vñb>øîs$Kß°_×xZ,äƒálÈUï Ùãö–;N„5ïùÞÙ³?ûÉ:»Út¶™ö¼{ `T<€]Á¹}öï]á<>Ls:·€×¾î³!GmΊN[~j)‡@·sF$:Ý2'цêWÛ_LϺPÞçG<C3A7>ù[æõnLÛÝgší<C5A1>UägåJ é&èˆFh°}$Ù¥u·(&J^+&êß›ö!N [0Ñí%F‡õá÷MÐ<§<E28099>¡­ûð t<>l5ˆ|;âz
ä÷ØÌz«<>Lëû1Ç><3E>f¾Ó‰rÎ š|w€<¨Ýg½ï‡A¦uh„§¨1”ià—ušÇî™)꧗HÕsp¸:4<13>û<EFBFBD>4Qµ® àÏ$KT½“ óé±÷ŸºIðÛ0<C39B>ÿæ<C3BF> ÞtȾYµÎrÜ?à“-Ú`^b_ç00€h»"h—jO?y¦ ÛxÇ¢á;[ယu^
ë>ÿÆãrg»Ãô öA<01>@h˜"<22>°[¶lù<E280B9>…†Æ…ÐÀ×¥Tâ;-ÅZK°Ôð˜Ñ|¤°×÷õhõš>285~k?Í<11>!é»å™ƒÒÏÄ…hij%?¿§N†d&4>c‰£è*Ûþ#ÉJD¦<>ð•aÄ>õq'”F£gZИOHö©è+ä 47
ì¡ÂïÆ>.<2E>_Žé… 4rôb†ˆÁQ5l,KWÄ Ø¨Y
D“¼Ä"äaˆ»ƒ­VfÀIV<08>ÁÚM2ëF˜2ñÔ2äƒ ™ö€rK†]™ð5¸pVE¸~ع<C398> N%·&Ó ªw™ÁaœÆϾð³g¹³˜M ;`†hhMCì¶P<C2B6>û„†ÂŒÕò)¶ í™v§º)¦-døS®?¢™ О³Zñû©+ín¨Örp€ëØ3ùeúÍü:Ë-úƒta¼ü½gtfc÷ ew·EoÈÝ<C388>ÞšØãA]ÍÏ\¶c6*¶OAé‰ü1ÂœîX¬ÑÜüÐ|ÏW«¿Y|HÙ™inòõt«O<C2AB> q»J¯½b4äZÄž‰Õ áú.n¥O=&ÛpT;»ÂØÙödCNŸ s-½ÙÑ,OÚ eÁäBÔã!*ІµÎ>#uÌ»Ã- à¿B8º*n§ŒÙv ¯¹¶ž§ægv ¾_â¼èð\<5C>u¡ó¢ÃsáÌAžQ]ppŒc-ò<>ûKÁƒ‰¬ÜT™<54>×»%k6u³ÈÂH%€ú_çx ó¸ÊŸùj6dl£ìKúÞ}¹ûÚ#S™x,yÃ2¤Â]ÄýÉPÕ<50>¯ü„‡å ã‰ÇNAfSwVµv¦þZl)ãBO”|†¤ÉPÈίƒRvš} ß ܃㮒õ|iyG€á<E282AC>1øäÜ—v¦Q4ꈞÅpk
>LÂÂ
R¦µJ;Àë³_︙ªûÒ¯Æ(ëζí$ ×2 ð½/͹ù§1z<p,ðåvC)<29>]>9€£Ò˜ø…ƒ~C?»ô=±ÉzEÀ©zyÒ¡l1QøtóPÂÅþ—Ý\,lpyúî¢ëÃ_Î[ÏG$<®=f_é†ÏÖ[?³]=ôî2/Ï­tɹo?~–ÌÛ{"¼<ŒDmç^•è:IIPsËSýÚ¨ž3iŠš¿bOo)„!N¤âßÐÌÓh®¯ï²ålà<6C>%¼ÎWÚ(š‡<C5A1>~&¯ºøíÀ¯{a¼µ3M™ËE»Í¢ë 8@Îɨ«f±8°çp¬þtbÔߤß^÷±¹£µÚ0úƒØ“ÕG¡Ž²+ÿHÙ¿YN;æc!É4åW²š¾eì JD1­•ìâ”êËë \ÆÀ[ÜNs z×0*
¿9 HÑ î‹(snû½¥\u…šÄ¼ã3”¶^cŸ©ö¼f.ªÏ“üdur,h5w>Eäse3£œ\[cÒÍ ˜hÛÛC0F~ß“,©Ê OvånzÐÖÙ" ƒóù5òUôï>@÷gÆôo¶oåUØœç> ƒC·w€Ñ
ÔA³ÂÈó¾[6H~ ŸUáµ4 ÂoO»XŸ3Mà <>,ô룰XâPöLm…±ƒø̬Ñ
ß"Œ}Àâ÷›Ó‰Ôë}¾²^|dƒ<64>®;óboÌ2Ͷ£×Í]é+œ]z'nÀ0
æÁ“¯|ÔìÐi¢&@V'ZrÝ<72>´ïo[Å<>ù¾—ŸeW[gþÑj³"“G<E2809C>ȼ˜Ý-gDMñémk.ƒ5Ôj“.8ì¡)®ïà|íÙ~ºs»ßó¨k`šgÆоV„Na6Øv»DÏ,F¢òQJ°0x•âºO?Óilayy¶ž3SÌ÷Êv¹Á‰ÚMükûñ©Öªc?<3F>ãuI“8Ù·-QÜ-ö</
Îí»ˆÉ 
¿Jë½ÝÛýðÂ戗Ì4Ð-OsƼI…º¥Üs®“0»÷A?€IýÛ3<>þÅÌFá~ƒgd¢ý™ypƒ…Z …Š¿åD~U
2;}³1?m}os Ómðw žÙ$+[9FBsy¯¾ï¢OS<4F>7S<37>ªéxv‡ålßÖ4加„NgÂ_“çü4úí)¼“û{ I£?”¥ l<>~/³<>×í<C397>hbá­(ôõSè>èVª±Jò!ä—ãè2ShgÂÑ&²'ùé •4#5ØþÍÅ\ækVÌ¥gÍò탷‰zù&ûOºÓ® ‹‰üë<0E>ËfS:öFÎÒ5@¡L4ŸÍŽæ ðRc®w¬Œý'†’(­žÖŽd¸T†úæ÷=Þãgˤf<C2A4>†!þÀ#?÷éδ}À€'C<>‡¼»9q¥cÏ?KÌrÚ!Sq“c·nøuûñÁ­ˆìèCÑXVž9ÙÿæÈMpŠ”ë‡|¹OÓyç¨XHØnï^Gö~³ëz2xÌ4/& Î–ïÈ€Š{­î€ ×öä§m
øƒÄt<EFBFBD>
ýõ]º+«iÊÜßç§[Ê-÷Q Gg6¸9Ô-æ¦)¿°Œ8ÿZ a¾eL¯âm÷gAøËy¾”¼#<23>Ý 1Ûqç<71>æáÆÖÊä : ŸPZtód¢‰ƒCðùm"¿Ýj©ø0J?™º7ëÞxj™N$wf|QrÖø4ñ`„$hç{(ù(d®ê ^êj¿èkË*)S±¶)Œƒ€Úå¶ÉÐË’ ·žŠ`z<>Ì63µ* Ô¯F”`X<>QEÌbO?Эí{£®%+â~vn”·'ö`9·7—*¾Öú&
ã̧˻_®±s ½ÃM¥^z…¶9“Ãñðøþˆ¨¡¯ì*œ¾Ež»!;ŠŽfÌ5MPüXñXÅSÙFdW«Ý·ÄÏÇ8 Så£ÂˆHXpûžbdVCîi˜áfinkû¼³þ;á ¨å<C2A8>ï¶Hß 4÷…±)ô<#U,Dše©ò[nÖ<6E>;Ÿ®ïï<C3AF>wÿL$«à Èï‚M8D£bhÄß
ŽºÅhØw©µK><3E>õX½¨n9Ô <0A>ý-<2D>Xm¸<6D>.…ÖR^€p-ÿæž Ño¤`Iú=*J(:ᨬ/¶ô`ž= s,ÁÚº\«â`å <01>Z¥ÃÝY!)Ñ{¸‘î*Z]<5D>œ÷uMÇÉØýŒºiÃQ'×ȼD:5&Å¢ó<C2A2>‰Œv3LC ñûþ2,#pKħ
â­=ïÁÞà÷˜çÀ(ǯ7ÚÆx«XLϳ·í‰6<>gŒ(½„'ÀCo>`¤$ž2-gÌÍ̾¡A<ZLƒLÄå6AS1$a2 Ÿ6d6°œLB<4C>ׯN$œÊ•só<73>‰ º`¦tâÅßÏW« ¿ï,} ÚiÅá}!ÿziøÅAøœ¿c ôß—@ Ow™æ*ø&ÉÃnš¶uMùê£p¿9»““®\@ã=Üà9Õ iî!? †L çásJþÚ ÀM²ÿÅ1Ë”¼¬âÅ'žX™F³>GãÞñ<C39E>›ò(ôä+nM¶ hªïnû.!"LÆí˜ohodW.o»Ô}ïnÀÜì³Bü<42>iòÜŠß_‡9Ìà° çɵq¶h2ð 'СæÌŒL=®70û¯ÖÌf4£y9'Ù÷­VÄò6Dp;À®í {w@Ľ„§,§½eÚ¯á¶@¾è2ýSƒ_¿‰Âœ<C382>Òßo@gí:C$žwX Ñ+kI´óö…gœpöªÙLÄY<C384>ðîp4hÕòvõ¹ bM¿°±²ãL½Z†û®³¤„OÔ§ÐäG|ø¶ý<C2B6>.®§ðsW,D·B¿;²ÇÕ“iÿz­ü°Â¦VüT^´íãÛÂ8d fŸl¶ExSyq ‡]Æ~¶ÀSѸúö½àêEfÙÀß…±À¢ïœeÚyÚú­SÀƒ¶ï+á#ä¡ØàºÅ–ù¯EÏŒ±¹ÿ@­•`ø_róôÄ•¯¬ro3€ð½|šÖj6ç¦ñîÜb$EÐC¼ŒX@5Xµ AALŠP¿Cc¢<An.˜òäIû‰‰8>+ ¿œ™MÊØ(~[¿|pQ|æ<1F>SBè <>Wêåf(Ö}<1D>Ñ<EFBFBD>EÖv ÇÊ<C387>Gˆ¡ýg>ñ8(fþÒ•µŒ…'G¬>‡¬¥6]Ôëýî6úZø¸<C3B8>ÎÞ ' úV†1}w?Óž<C393>÷°—ÿ')d¢Šsëòè€9<E282AC>õ¢Øj† jG}>¹lz˜øÙÈ™û´òÛ¿6ÌYÃèz¦Ìh«ZwÀ½[Òû7r<04><>QIÙ01¥
J­Ì‰kݦkx-Z‰׶IÎô6EÃÍŠ
iÛÂKº*¢Bžãôe®-Ÿ„îÆM­²HQë¶z}Ž¨mV+‰ZÜéÅf©Þ6ÛryÖ:Àò•ëêm}°mk?ÜL†”Z=×´M w;¾Ööœ¤I¼l?' l½¯<C2BD>Í”¥ ÍÉ<C38D><C389>þ ×ÈpƒßGh€¹ö†! 2i¹S݆W<1A>ÅÀþÙ »xi»1<C2BB>|P3àfÃÅâcˆœ€ŒuˆgØo!ˆ1iX ªý¡a5üžvF¶Z0gMèÃx»WÙäQ<C3A4>ª†Á¶“½ÛNô ÚpØ,áÕ:nu ÁS<53>Ìá²+<2B>-ÀW`(<28>î˜#û|1<>|Yêi»ÙŽçÔvM
Bç(;]¶þç„cÑÔ8Ž9š <f.k„äƒÂ²±ð<>$\IŒI<C592>-Qc[ÀN¨¡<>×»‡7Ü“íùa=Ú +Z—p‰ñê‚?4P¾ôIá½£™ø‚#=áµ—Ã#¥/¨‰^9)>RR™ÔðŸ3¨"~íˆ(êUüòBU|õtJÞ:…žðÕÈ)·x±NT‰
_V¡K@^yê¨jqæ¨ h àÅ'
eÃRóã<EFBFBD>Ôªuåµ:— : œ¿¶Ô²¦QöªøbV³hJñÕæÙ½ ¯ªüNbB1é±ÝÆNÑ=»ÈP†*`0sW¡hUÿ©”X!€ž“0Ö<>ÎC@©z<10>ŒŠÍé}Q£îUj(dÆÔv4Ü3wÞêPʬ"®lÆÀÀ@GBbÚXíEV™ÀÛ“Þö0_Øã'±w4*He^Ö}†Ž†r0ò ~<Æy/W& 'éBï BöÂÄ7D<37>'Ì¢ÌñÞèqáekø'ù öX™££Ž½aìâEÉ<45><EFBFBD>õ˜ËaY"÷ðæÄ“øOòUlŽdð;ìHuFÂãxr9Ró½/1?ÿà…ÿ„Äý©ö>ŸFK˲¹ù0„û`Iþ©ÏñÐ Í<>6ùÁèòXàF¸Ñ\&Œ¶ç÷¨Ñ9_€gßS·ÑqˆµŒÎ§nÞè"ž|„ç¡gEøƒÆœí%@ûè'лü2<C3BC>ª'ýÙˆ?z­ßQVŠ¡O‰ò€„•|eœ»çÇt5J'#åÄ›»¸}t
Ôç;/öÚŇÌÃØkÏ„7,ÿíiƒCÛ,h|0:;ýŠÑqEŒŽ±»Ç<15>¿ŒÎÁ$h´-+£mŸ]ÀÁÙðÁœMø) zò™AIFË·?Â<>àÞmü²ä}–¤)/iåöÐ/e.÷Á×ÒŠ˜Ü÷òÜ@j4EÅéõ¹ŠT O ÅÐU xó®ëO¿X­ÍäÞˆQ&<26>úÊÙÓn-rp$KÆ{a2ÖÀ¶ÙÚ(aíS_ƒyKM¤ôðüµïY¬ýÐ{C kÙ¼yÞå±&Œ´¹ÓCi˲Ã}y°$c¹<63>G9¬Žø8<C3B8>2;ïÏA V„!ôÞ‰b6T—Åj*þDn7þxC+QœŽËŠXï}<7D>^<5E>Yž2à ô&D©DõäÇZü}õåÚ#8¯<38>íѼZÖ1kÃbAX4ìÔú©ŽgŽ°ÎÄSûA}å; ˆÕvÌP<C38C>¯ÀÞýêǺ+?Âì1bk虈•°Ž©~ÄÛ•Çú\°C‡'+@# ¦Í»lQ k9åÛxßå±l=G|õú,ÕT b|j«/Y¬!ó]0L)`í ˆâ¶Ý°Þ :cqéöá¾FÎ_e±^"ű޻Œnv^ ŸË¢hñ˜à.(mI;iˆØ~4Üò`Í-ÙðNŠµVyþb±ö\VÉXÃA·û]À
9 î{¨­_ÂòX+¦C¤ÖGd±ÖWdY+@Suÿîœòà |8ˆVí÷ <20>µêï׊ŔQk»²¨Xá܈·žBío%¬y¢Cô£òXk.s{2°Çå°BaÓé?ЊÃíXÉÁN ëñæJe°•CXépß<70>í¾"ÖUÀú"¾†ß<39>ÓLϯeìîÙ)Kä~¿;Pĺ%SÖ™Ö'â»PË#¬ˆÓ¤«öÕkêî_*rX)êÙef±Žü6ÉâqDí?ƒuhÚ—¬ÈäHcÔÁŸ# bçÖúƒõ·_è¦ÖJªybÛž“źŒÚ%X簾)Â
Ðø²=oE,+šDáù£±ºŽåⳋÓ<¹½”Â…Â<E280A6>Áš²œV(¡=tpn™8X å¿<C3A5>åªb¹H:«çkèÎôÐ+—ÖG£«Ñ—­ÏV47±·d¸?Û‡ÂÁšz­ÕÄê<1D>ùg¾EúŽ(7røSß~môÅ6#ÉSAIû÷Fÿd½“=`'$•žR€#ž
O“£<E2809C>¨˜Gšúý<C3BA>¨¥ý>ôôXÞ¿§ˆZ3Pzš!j“j=hdäˆ'ã[DéõQWšJOD+·ÜKžb͇“huÌF…×?ÜD;ýdUz$^<5E>¿nù§ #×ÍÁfK­2Ñy5>0OÅ+>}$:3WJéi<C3A9><78>fx¢7x&ÞB…œÒë âÝþRzúC|ußí§Ñ>ÃÄ×ÏÔ©ðúg”è¿ÆýJOÓÄ 4ˆ*<ÀÍV¯Û^ *4Z½Ñoß“ÂÓٽ¶¼ÕÓ£2ÑÆ[ïóÒ·Px}bóö~ª÷òOƒýM;žØ¿+ÍG7ŒÛ#²µ¬ÀÓ±ÎÝåty*•‚¾ýʘ<þÈ? Ø>Q™oö¢Ôàˈ¯ØÓœËÞd<C39E>B Ý’;ë¤íÈnégF%vw˜óVø$³œè”øoH$RTÊ{—öì-¹b;î!4ÿ^H¸ÁoD1—u<E28094>s¹¬§ê¯µvìkßw+ØCmö[SýqÍøC¯»Õ‡ D=O<4F>ø™Ýò‡€¨<E282AC>&xÇÖìY<Œl`)š
ÀŠ5D¢2ù, ç ՟ĶDÌa Îíw ãVk ×UÆj*N<¬P­ñˆ‰b;û¢€ÍõÅÓP ë·
Ö’+*¶&÷÷f+EÇ4<>Õ/Â)ºóZœÃZZ‰(l²âX­[€F@L¾½nE¬ˆç°<02>øŸòX½Æ<>‹ˆ¼ö)bE®…"VèWL¬p4"Ĥ2ÖÈóKW+4R) Ð@;e 4Ü—£©5Çœ,~ô‰e÷˜z;$lئq] Ÿ5}íl ¦ŒGP ‰ãI¢E\<wÞòcWÁ°™E†!#g8â
k?íu¾z<C2BE>üŸnnXCƒ<43>'íð…õíØ@M,v—lÜoa¡¥ßJã2
â ÞÝ¡?pJß$Þ‹¡Î÷(½Ë"jÅ!|L±¡©Òk|½¿cÿ »yÁ<05>õ@ã<>¼·ðE—ؘ ;f¬ÓÉÂûÇù´eÄxœpÆø0'¢!Nú¬gNæï CƒˆŠz·ø&
}rœÌ–¤^,”ˆ¹¸ á:<08>þ°#D®»ìFa„Œö<$ÿ§‰ûH2sìï'­9<1C>ÅvŸq™$ñR†µø™>wQt<51>dÜq"½”9")jl/Ïó¥ÞN<C39E>¿æbZ™¿ˆ©×ÔÓA}uÒ#[P_[u¯ 8!Gznn´é%Bîíê9w" üøxˆæ„<>”0|§ERÈv<C388>xSqyöœ{ű=¢ýaɇBµ2ä+|v¤Ë—ãòË“ñŒd—òVk:ÇÌ >>Ñà\fõÁ1Ȇû>¹³%vòd.5ÖиUÐO¸î™qÉó|¿@<40>ôòM}Hh4ÇS&á ¤3øNøåÙ½T½—ò"N³•÷\ƒ6eÅ GCî_=,ñ Í8@²ÐF´"4EP¸/@ïîhŽ|¿:F-·úÄèQF¬**:8X€øääÅ“ìÞh<,ú¾Y´Mågƒ÷
³
ÿ°Ýg¢ßÇ F(–‡"Pάõ‰q<°¾9ûFLsî…aÖ_ä¬3a†Y¢‰§%ð{4-Ë¥®ôÔ¥<C394>H­<48>qui%M%kMŠMIa†KË,O±¦Ò=É“wxk)ë0ª0“Ã+·E é5jÑëadUïrØA·|Ù÷è£|·x3OÉÖ÷ɬ¦=…Ô¡LI—·ªÖ†YË#À§QÃÖ;aL<03> ÈŽ(fnN†&V0ÚÃEç´©å·{=¢i s³¾_<C2BE>hév2ÑØH³Ù'%Þ­/Ûí+Ê#©å,˜Í¬è÷wV+5[W^g—áîNY]¦áÖ·¬´4]kyáwÚ¦03LñßÆ«µ¤íê¸TF£(!N˜ª<CB9C>¬W#ô„s<Ô;£%4{‚¶ðºßÅdQ¨' CKüÇد¼ÎÚ'iõ'ç<¢­<51>BáqÄF|öì–=ú©y0,èÇ
ˆ-/zc<E(-”ŸŠÄ8…šÝõioÖ+
$é<Gk¯rQÀ(‚ŸŠ~Q >½Ã"7Ât´É‰„ײ¤œØ
Š@̼)k~ïµgŠW!=÷aV§¾©‚ë<¢Òç¯"G°AHýôR]ìrôBPPú˜^'.v½Ä+ÝÍ©5Ñb_?Š»‚§òßÆL&]ÁÕ ÃúQÅ<äâ™<C3A2>Çìæe"
Zí@.RÒ1¯åˆÊúÑŸê´Ÿ‡„<E280A1>f,Äý%. „°Rà él/TË⸞hªb¯;H$Ò7<C392>6ÁÓÂ%
±<EFBFBD>GIlG…¡Íò! ±™<C2B1>Š5ö3ÛŸz½3JèÏgBªZÚÇó°«žc<>˜µR¯^õ°¡ÔJVÒ9í©Õa%ïªb½xæºI½>Ø.aw†¡wU©BÔÆÆÙ=öb+BlHÂhô é.p¦(À9­Ï€0ÍûÄ%*+(?3H¬ù4ôBÃYº2ÊÏP-ئ.ø”¿Y×Ú£ÆVŸrø¡Û:swW©±Æw£ôh@•ð„ÆGiÕ×<C395>Ž(-€¦¾
õIh¸x¼—†ñáÌÙ¬(
;…Ú€ì'uG~‡r\e\¸es —Žî° 0êºAs_ Vy¢q±ÍvìvvÛoO`Â@“xfg«Ø1Ñ®Î<E28098>BEjNî}zv²¸(‡Ä<E280A1>—“nÀµ Ú$Ò üÓaÞ™ÑÆŠ†yÑ}½Xº¡¹çIö½št dqê€vtS0 `@Û±€ûúökH<6B>ã„
eNÓ¤Gœ¨Caò¡ãz$‰vw<Š¾?rØ·ŽŽ—Ž"a2“æPÛSbw á<1F>`¸ˆ£ŒÊã– tŠìÒœ1ðžÉЕѕÏ*ŠÙ:-¶nG<6E>¸¼ö<{O¸B¬SKèvô&TÈIA
”z;u§[‡™<E280A1>fNœ0¥,l4)þŠP$Ú“tiV…w»Õ7ò5éÍiâ3S×#v^<5E>[PŽx€ØtqÉ!Õ<>CSM‡Ï£á{3Na÷íÖÿ§r„`ªëÖ<C3AB>šªõ/§•"·Ú™Ö?>¯^Sð*jmhzºŽZ€.×FLñÅÓÅÉI¨;Ê‘=Q¶<51>6 ¯¢~TWŽrÂÆkr<6B>®U”cÌŠ²»¥ú1f=ÑÉPH4Ì<34>ž|ìù¸€Fj<6A>Ú¡(<28>bVe—Q-OéÊTÚ¾ęF°Ìvò:WìZäêá5É+&ZH}6Å»¸ª.˜ÐŽûSnw
»ª1oåŒ=¥>al!Žuj¯397Ηíö\5%IÆЇVtãzjj
O<EFBFBD>ƒ2M&;NJlw.<2E>´ÈÄ1­á<éÍÆ jssÒö„¦ÁË'S|Ùžéþ»Cšèˆ3tæôBSXö#Z.ÓCƒs†fþ%ê“r4YºÈ¸¹DŒðå1‡ÇÛ²\ÍΪÛKÖç¥Ug8È'‡B1zîÛÉFÕò4×)çs¨ÖòÝ`EK•óáZǵ|7ø1—”ó©×òÝ¥—•óaXejùðDåÊùÔkùnðÒÅKÊùÔkùÄÔå|êµ|7xéâ%å|êµ|7âÒÅóËùÔkùXµvy9Ÿz-bèk”ó©×ò±£9­œOœ­R€ÇÇø-<-ƒO¹ìWGŸôˆ´rÅŸ¶ê;<E280BA>—îœ<>ƾKÄ ËIùë*;…yq@ê RqõmGe>Ç©l"§L­P5åOv§PšV—Â<08>*VtñéáQ ëÂÔ W™>aùi*ÝÒ
t©ôi'±¡O­ß;AìôáÁfA÷ë{õüÖñÐbR¸dƒOd@¡ñ]Þƒû4K'ŸÎ£Yvwj~‰\\Ý<E28093>i>­Ó<C2AD>Ò*»ÓŸ_¢,:mdRLÎòRCë-Ó“à•ù¶³E˜o4
1õɯï LÑ]÷:4 LÚ“![ôz$¡‹ê•'Ú`ØÒ§ ETmâX#4<34>âˆJ ¦ I¹ FNYÕáåqºêÑ"{-㔚Âþᤂ•šBA&W3º°—r<E28094>©X„#5³µ2ïKj™÷õ&‘֘ö¦P+ó^M¡lRú ^BM¡$ê©ÅL…24<32>
½c<éŽòüÉÃÔ>ÆàhÊ{çM£þçD¢ù/<2F>3‡eŠ¨˜,<2C>ò]fnY*)Z–½¾Ò=¹¡Í<>?ˆÖ¹WSVÏÊrþ \έpŸÒ(>ìj¾'<27>`ÜŸC I¸H\\~º•È¢U²§0K¸q[>ÚXQqÔËþd×­D
hRDw B1ª®U°w¤ïì8¤€dHÇYªbL­„Àš§¤•º_ôl/Gõ¬ÒKla*04P¦'8l¸9¨Q«§!€”˲Ž’“ζÓ~*Šk_Xó¼Ð$•îu+—â„qÚOå´X<C2B4>JxðÁ‘ï©“´kôD}ºá9•íÖIÑ•>¡$ëp•Zôæ†?qL_·NÞHÝ(qÜøa/<2F>ÞÀ²¨K¢7§­/ŽÞøocÖ[9OO$ltz<15>§Go”ãëÇ£7`p«Jʈþz8<7A>ѵs P=Ü¥ÑX çÇ<C387>çæ%=êˆÞ°ëF³VP9z£«:ˆ·l <20>N*RM¼ðH é®ÒK£4V—!]U̹¸9¥B2ö¢1ŠžÃqF—?õÖQ̪ãسª<C2B3>¥«˜A¬kp6½\ŠâiòŒZÕ™ ¡UÆ“!ıÎ3Kü´%.ã{j”øé©hU]ÁL!¦JœNOÚ F ¥°©„¡•V²$LtCü¦Ì˜öÖÅÙ•yo<>+λvežzÚõÕ*ó49í:•yLtð¨8ït@ê•y'$Ã^R™‡ÛÐXqÞµ+óŽ<C3B3>B½‰'Uæ©¥ZqFè*ónð <0B>dÖã•*óØÌ{iqÞµ+óææÚ•yÞšÒ¾P©³½Fá?TyùëºS/(¯N«SGê%€æ»†4oéØô5 ð„Ë×ÊQò›Å<08>ØÅÖìŽl̺ø…]Œ¸öÄvyNJ±V<àX6ó^WŠ5°Ò“véz,|æÔiÈæêX<C3AA>½»åc<C3A5>SÖ/úS¡-¿Ò¤C¦)¦B[~u¸ª˜ê9¹l‰“Ù­s¥£Ž ­³pô¸¸ЉëQ^­u®²;ŠÊ<11>Ùè4ü´ÑIC:$1áQÂüíd·G#®ƒj*žÏ¬—†oW-}»jìÛ•Šd?¯P$ë5¹®S$ ]§Hº¼HB¹J,,£Ó>èZš;¨XFŠÊQ°ºò—Äé<PV¯ÇuqŒ6X]ÞŹBrEy"µ¦'WH<L½Þ=67ŠþŠò°åÉÖåý+Eyçûž'å)ï¯Z”Ç&Yh”k^\”wƒN†í«ë<16>܈V”QŒqÉ}ÕW✠íÓïoøÛãd&YzpòÙG±Dû•ÝB:9ð ;¶—µûαlzÒ#”µw&nKåa9<61>Ž= µ“‡¡`÷ x£T«]u-é“ä<s1[ài×êé®5ŸEg<45>È Ä/”·6oÃFçü§o“‡•Åðâõ<C3A2>Ñ^<5E>{<7B>Î|ó ^¼Þ‚¯·<C2AF>öv&?5`ÓœÑU Owf•ÓÃv‰wšO‰¯Ðc*ÂpßSTv×ð8¥Ep´åv_1+.»³ŽnKÅb¿€íS­ì®ïRÄŠn"WÀ2£Ú¬åb¿¾ZÙ<5A>1¨ŒÞDÎcõËÜS¨\—0~©\+÷nbX%WèÁÛ¹oýs{ú;S*Eë©•ÝÍ Öñ=…_eåb¿»¥§3RÂ:TÁZ"bb«SZÛ8{4+b5~šC¯Jû™Š•{ÉÔÂuëBøÑ'®(ð0ÑÕ®n&%ÄJMMõ£<0E>Ôa°ÄO‡£LT!žÆ-bðºÓ*ѱj1gíüÞcã¶q¿æçKã°gÝ0wzíãTòå;½Ò²gQ+gt)i^Qs¼&¼ìz=qŸÒÿk]¯'7}zÃv éâL,@ü×¾mE”;¨r·ôZ=nÖSá<>ö]xZ­èá<>ÜipgWÅêºcE/á5®Ÿ8aÝÓZàS©ð8©ò­|SxµÂ>9ïãÔ˜<C394>ŽÂ>9/A>lwQaŸ\UŸ¢ }~aŸ\ _³°O®ª­›ëöɱ¿·v½Â>åp÷U ûäÒS0 }­Â>ÍLÈëöÉíó(ìâ^RØ'žW¦ªOecåÜÂ>…]Ükö©T¬\³°Oï]öaùþ|UŸüöêE…}rʉ‰@]µ°O®OøÖ÷•
ûäªú$]×(ì“C~Ý\¯°O·Y|ÅÂ>¹ª>¹Š• ûÎ&Úi…}ZD»RaŸ\Uß©DÓQØ'WÕw£PéuAaŸœMz#­ú¾¼°ONö`JúZ…}r-ŒïyÕÂ>1€{M÷ÌÂ>¹¹VÞX9»°Ÿ%ngFMßœYاà{*RäÌÂ>Œ¼<>y£\PvnaŸÜ<C5B8>n°““”ìUØ­ }D&_ FYóšv‡Z¡׉Ÿ
òq7êüê+M¹!19®qŸÉq¥[ü2WøÉšúH¥y0ƪLRù²<ÍR}}|Y€Ôº³×®oúæÊêW>Á_íÊ=­»zeûtœ2»¥gaëêç…ê6*¤
<EFBFBD> l]&ÿmté»L<C2BB>R—é8±I3Sð=%÷ÿ<C3B7>Y<'„™óltÚë:/ÿã8M}
.¾ü<C2BE>‰rhÝÿ§³¦ïG„_tùf§©Üÿ§¿TJáò¿Sƒ<53>g^þ'„”Þÿwb½Ôñå7GžËÝÿwF PØ5ö\<5C>‡bR®JñÜõj<vÕëœIŽæ&örq5QU=¿CH¸Ô¬é“Ëp<5»NüÅ·U3<><33>`4¯íSÎ Ñ]‡nìÓH Ó—¤©ÖÇЊ÷<C5A0>‰öOlÖcwŠ4ŸÈ[;iÃFõu×—©¥Äƒ®Ôc駤Z!<21>à:©VèlË9 Ð\O•žBÌ+ì¤ ("SVŽt:E*'ŽA@g-Å#(Àϯ›“+íqhʇ$ê¹¼^ZíûCZ<43>ª}HíÝ(ýh?¤®ûeì>™$rÍ®K°aÊLš­ ¢¦Ž¹Á<C2B9>MµÍ)`ŧlw˜ã|Õ÷=u sGù(gƼ^õrÇ×ë]îø*)¡8W
t¶'÷
nº‹îC€¢ž>z
 +:ï†o±©d#<23> ŠL Å%›ÅÀ&;^<5E>à7™Šs÷gÜû'_ýwæzÄ@]ñ®o­{ÿtšê—ÞûÇ™êŠWÿ<57>Xú£pïß©.î™÷þɨ5ñÕ—Œë(fsÚe}RhÚ÷þIĪվgÝû§ûøöÒçïÅõe<C3B5>€Õ§qò†þj_¯IÖµäú´j_¯é´ûååƒ)<29>椎ºÍBL®ô^ðΤ+ø¥‘Ñ…]Ví 0Úóòjß7Õ³íÒH{žR}”µ£ëAe#­¥:ÎÚ<C38E>ed¯êM6 &—gF¯²O,¤ê¢½*eµ&_K¥V-7RŽö±œ¦ÛÁÐæ:r¥Þ½ÂòЖ:§ŽBª.rñ¯ä{(u?ÿÈ÷TPR1«[%cRÓb”†@·Tk©NµGÌÆ­ øùÇÏÁB¹ v¼x÷ŒºÛœ[9•O
73ïU*Ó.9Uë˜hW» sD [¹Š»Qz-›œ;¬C<C2AC>Þè¼@°;ÐQªânº§ïj—a>©ž2¢»îVXÆÉàÓF!; 5š¢|{XÅ >F{°Ô° ÿ¤<C3BF>Ž±ûæP<C3A6>¡Û_ÞòÓw/!ûIT#GÑÞ;JÀŠZ|5<>ÉÊWæ%L÷Š•yÔáÛ­\Ñ$|3éM|áj:™[ùjµwµ*įĿ‘"NŸ[ŠXï½<C3AF>ƒ±Ö‰b<E280B0>@CGž³-l¸â9Ú<'•*ó"åäïíš«¤2φÕÞð·ÇaD~ð)b%ŠQâYkÈ|Û\ûúrX8\•òGS(c-9¿;ŠX-¤5<Ç]Ò’@·ÖšE+E¿&<26>rX¦1ýåj¦ŒrøÑ'v2l¹÷ÉZO»þa½ …¦!óo¿Ð­k ÎYîc',ÑùÌHÌQ,ɺ>ŠÀ”²Îâ5ŸŽìLÖa—ÙQúÈ_åÚ…<tÆŠM/­l$•[ùDæ°ìµnz»¥7áóx¯L¤ÀäÕÏÒkç%AàitÇ<74>>òš7À` —ê¤:%qK«<ήè€<C3A8>V§” z#9ƒXW<>˜¦œ5G¨™¯·ØäêëF k§éëò=§®¸r<>ã<\±.s¸'sÚ5<<3C>ú9»z#·=çþX˜˜h…ÏŽzŠ<7A>ÞMðÂu¶‰z.óâi…kB ë¹e|£t°™¾D½AP6¤ªX¨q©¾zDýukZ^MA5L_<MœŠâ=Þù~ÕG­ Wô¤G~“žÉÐQ¥?4=arë8<C3AB>çăº½Tþç97L῾Ì2²“Þ«#<23>I*)7̱9šuvÀ¤Sк
Ú° ÉIIݤ;¡ -r<>¨“K*½FG1á5Ft*×Ù)Å ÃTPGQÒSë±9”ìJÊž/ »¶TóÖŸ£9TÌZF(ÍR!ÝAÙAS,¡½áï[;ÚÉŒ¯F4Íj¢“ˆv­óQгˆ¦RwTÅ,Þ,>³$Q¯Ùˆ×ßœQ(^žÊõˆ72ÇœP(î„r=â<>ä>éKõÖ#rŠ@ÑGRqÚEƒr{k'”$*ˆ½£zD9‡ý„DmU£”ýpRI¢I<>ê%Ô©%‰ºÜCéöªxH'U.iÔ#*{ÒõWùq<C3B9>uY!.þÅË
q7ꨶñz—j…®tY¡ ´åÇJeÚ¿tY!R=÷b@½—òa»÷²BÄi°[ÿîe…xæý¿xY¡|øv”½vÙÕLw´NµÂo;äÓà.½ð<C2BD>cUùÛOͶS¼ððœS­Î¸ðPqp×8ÕJ¸ðð¢ªÞ\áT+tááNµÒs᡾zÏ/<$ô<>cè³.<LªÞvˆ9—]xxbAÙ¹JÙB|ÛáQ̹ªîFõ~Ï.<T¿íP%ÖyÚ…‡êCbLõ+\x¨™ {<7B> Õ/ceÚåª/cÞT—@<40>z᡺æ“Úig_x(J:ºíPÖ¿9çÂCõ¼,,íú² u”\ãÂCõÛy}sé…‡'ÞSxî…‡b(ÒÛ<0E>Äg^x¨œ®Æ¢¹Î…‡êû1¬L»üÂCÕê&WýZÕjÊ·âÁEªïó [ધx+FnO½ðP© ߊ¸°ä#") QrAª]xx¸äÂCžÝdo;<ŠÙœ{á¡:”Å{
//¹Àn;¼¬”äUÑC—ì6ëKíÕqá¡zí ¾¿Ï»ðPýäÁñ¸ðÂC¾ðK¶bû/ZÒ_u|á¡™v<E284A2> Õo;¼ÜTg/<¼B9¶ž õ¸¸W¸ð<C2B8>ƒ"ïq©µS/<Ô¼¢PEØœqá¡Z¡Çç/ë{^~á¡,“ñ·^&ÓÞô?ø¾çEª?XöÃe
—+ >5:¨xáá鵸g]x( Åê+'\xx~F—Ì…‡çêß°_x(Z<>2h®pá!WU'Û!+Ó.¿ðP=‰Š1n¯p᡺wÏíj…Wò·žëMzááù¾çI*ÉCæ¶Ãk¥(æÔo;¼‘­ö…‡ê·²&ÇåªéÊ+é3.<T¿íPËNÓ_¤«zÛ!„¼èÂÃs,3.<TœM´$ÞúVƒ¦qá¡®¼ÎË/<T×(¤*UäþØv¿)ë
VM¥‘ðá`β!¦¯1<C2AF>4" ~S÷êùþâ"J¦”ãª<C3A3>&¨‘€hŸÖ±Á‰€êø:¬¡i“cI
@IdŽ¢ÍEÚ³O<f¼·Ï4åQXÕUv´CÊx÷é¸7¨ÑÒ/Ï<>Œ#žü<C5BE>:ñfÏÑ^,·D¡ðã!
Q¬¾d "(n5¢ôuµÊ󀨭§3¢¾"çDëÉ%Ú•E‡x¥çS¢CìWD§ÿp Þ\+ñî|µ_#S<>è÷»SbÐôï‰o×B|?Y_(Š*x(ús§ÞM ¡ƒˆ•¶„ï¡<C3AF>ÐÜÃjSk1)×ËÏÑiºóõ>3Úïïº<C3AF>ÛH|•½k´J<C2B4>÷óå<C3B3>Éõ<[Í«ñ]%½¯<C2BD>~ºù„<C3B9>+J4œ»Àó7šTÐ3ÅvûŽ¸%'àçÆVVœ°sƒJ^i¸ÖŒ®l/€]<5D>ÉÞ°ËJè…ˆ‰Vz‰E¿Äw¢o£¨g—CîÑX¶®#á·¤‰b¶š%ŠÓñ#Qª?¯is?4Å´Faò·àxˆ<žâÀxÃTH¾…Nx€î?$<uÒ)1ÂÄËHt•á·u-Di±Á ÚH°˜úß{£-ñ0º<,Î<11>ÑiK§áo<C3A1>éÖ)£+ãŸ<18>OݲÑþkcþFXÖfîõ9 ½õÚsÞ8@“[ =^8´A:^3RhŠßS|jí¼ÎÙ, >u~ûOx&7zÝ]ï Âêö ¯PBZÙO?¤¼Q¶1§_³nÊö—˜Õ¿ºØ¯µ ȃ}a¼ü<C2BC>ž`…Ȭ·5:S}{ûò`eû™ Û„h ܃ˆ{6¼Í=pÏr.á<>/ûþšâT<Â`“Í2܃º—Гv·"<¥;ú ¢<>?ãØK9§ÐG]ª¸Í<>v Û><00>Ùæû¢àAÓ¾úS¯Fðµ¶óÈvD,Ð(:a+;0ÁÉ,,P.F€l­E€pªƒùmÔ=0"íDº|}EpíÌy~ÏSkéï¶ýÍ 3|êÜkÂÓ«¹p¢}sh¾Áì‡Þ]yÏ0qm,¯ÅD!ðƒÉOFºº/¸w˹¸œ6®E9ùùA,p <0A>œˆE]´=F^¢R1m!ÛùÊäÁÈùž`h]/ÇÆmŸ#ï¼;­åJÅg[ Ì,“õ†~èCœÉFu¤’Ð5¼__=,÷<>º„wT«ØÐÜŒ>¼ŒEìõ}ÉhÅ·Ÿ†~îÓ$€`°ó»l"<22>.¤ÑÁ×®‡}wùApŸúÏ<>€F­%…幜ø±g}£PØ>ª¾ï§ß;v4Ëu<36>Äɾmš‡Šõì*bŽ`a<>dñ°BŠ˜{d+ó…‰r>³ïºy¬ceö}Â[ò¦­àÓÐË}šø„v@g7Á÷?IwàhæÁ}§h·%ãáŽËôTü~º‹"Eë¿Ðaâ±ä‚ùú
9
<EFBFBD>n9Síf <0A>ε˜$?MÊB÷4Û¿Š¨VºðBæ<02><>o]£íùÝÊ
ÑC ÝÊ\5Õ6Ú«¤Ñµyù„5*w´¿ãáyè1,žŒ­=Öyò“m2ü…¯G2 ½¬nðu°ç´l<C2B4>鶿Pt:XÑ ïr‹ÎÞÖ <0A>[|–´ñ Í>4)<29>èÀ!à™&*žEwïf_ <67> i Ó
<EFBFBD>raªó\=føì  SG¢- e¹NW<4E>H~C Ž¦êq$Ã<>rî{™™ˆDl<44> ‚£* bT½p4üRô²¿!0A³:xölçGhcªß‚•ù ÞüƈS$D<>÷“]™6EoÙUôB^24Ë©&z/vIàñ/m0̤)ƒïÈÚKͱ¯ÆS4S…`®:ø7Í~?›ŸÑ/±ûm>7“ÎJá-K6ÓÓ¶÷<õµŠQs0YŒÞ6'¹¯Gs9~˜ƒß :`<60>ÛKœiµL >ðÜÂÉu3ÁûûµHòÝÞ¦c…ßϘ?—dÚ¹þg¡ÜXxÓ¿O&_Y/èb~åͲ&D ¿àÌ;ú™=d3HX¬7 Ì,âc¬fºàX¼Ï3íÎ'£Ô2Ó:çáßr³V-îÂûÄ4GË  ‰˜…w·ýÊAÃ#:Œ^}ÌǨß|y·;ñV쿼éø㲩>`&-Œ9jr$÷F‰£ˆ óÁe÷¸fÏ£(
ò+dŽÕš€àä"»´Z_Ô<00>êT<y&êxõ6sÕó¥ÒÃ2ÓÎûO&¼Ï—íy+:¨~MNÛ[Ü<>rÖ"ö[ÑI6Pt²<Wø,þòÆpÜŸjïÓ¹EñžJw,Ýßô¶LõŠgÙœ©Ï5@„Àm~úB7Ñ¢¤<C2A2>_<1¹ÛäÁòŒ½s}8‰æz Ð`4·Ïè;äûøòãzJnôg
½£¿€Ýš“F/7t†2æù@Y;Þ[S«™šH¸ö‰üaXª™Úªg;UÍ”ƒF
HÒ|+[ð•ÓÑBdì,PýX?þ^Û$K«N÷š´‡ÞÍÑ E¶ÃeË^ÂøŒSx¼ì/8»\.»´l>óî°…F“Y@粿DÎA¢i<C2A2>ùb9ÇX6ZcV0`·Ý-ZP(Ô’|Ø r¨™àýµfš‰<C5A1>l\•dÍ!µv¡”×±æ šK¥¼µ~§ šýtÔŒSx}SF<53>Z»È”¥5»õ­MîS|ÌnŒ¾Ñ5ðKF Ãv2KìBN;²âš³E
´ Ýj¡Ä}:yQ8àÉ¡3ó²F§¯øÌ|µÙ³>£ë³Ð‚^` :€UðÀEÁZ‰±<E280B0>&N£+âê<C3AA>B6N1ž!ïM NcÃlæ„2ö4²§ Ò¸˜¾¶ÛAÐùM¶ÞHóÁàw¦ÿ±æ+¡G0#VS:*ºù@ò¯0 žùÝcÃ|¨tàúQwÈt§úPóÐ6¾Cõ¹œy…“$6Æûù\¬¾ñÀžŽÎywóÊM6#½– Ä*±,N6ªP0å“R§tGR@Ÿ>×mTÉœÙú>æzG}¡Z;É€RЬ—áQ·W1*ÔQÃ<1A>“݈Ӆíuv£½¿ÚñÎU ýùnÔI<<3C>ô<EFBFBD>´ gj9•X<E280A2>œÃîÛßã+횈cF=üè2™ð¢3ßôA%Ë»5<C2BB>ôÍ*P4:“Gø atþîÞ˜mÇ‹)5JÝhûžFØpä`âgÎwý·ô͹¢È^ÆT¿¾O«Sß\Šº0ü.,Ó_Ï7Àß„Gè<47> m·Îÿ»úæTUÇØZcV06<>Û¼zà†Ë~¸Šø†DÕqœv<C593>¢ÉOïwfh\<5C>ƹ¡sùrÆÕE•xA8e<38><65>Éél&äùa3}¨esÂ:;s±ip×,j2í“RÇ€qNÓ³ÎÎ5@sÒ:;sè8§éYg:ÜÛëü
A!:Èe¿¢7sY7á+¼e{ÏçŽHgÆ/ÏÅ|Ê|Ì8·1Kþ½¸ÿÊ”CßÏéi{/P_£z<åíDòæÉ¡<C389> þb;î ÁBhŠã…— ­=€æÚ<C3A6>z9CzÒWŽh覜¸9#Z™µœÄý÷=ida³ÞÚ5#rCÇÓyþ'‡s²š3×FnÏÞ28¶µÏˆ§<CB86>ÊãQÄËwöqWÃÓøW#·Š.ž8žæ½ žf½ýpÃØY~mœäËÈ-wNIKW¼×Bîsóð©s±ÿ:ØtÄàܱ¼˜”&1ÏRÕ»âRMûg¦ýúÓ×%çÐ'>w0V`[¤ò˜¤Õ¦8X®ìÅÌjø£Ï<C2A3> G6¦ÈZÁENOå95·0~Ø4ƒ)§3œ?¹ì÷•8Ê´ðe»Ã½ Iíý7gŸÛ<C5B8>ü—gM=¼ÿ×fM=@ó/Ïþ ÛD—Ì>šz>£ë_ýSv
/˜}4õŒ°ù7gM8
ÿ«³¯Ï¸U<C2B8>}ÆðÚŽ“³p ͤŽ³D³ŠÆàÞâ …ê¸ùE5GõuØ<75>ëU˜”ô4¦¸ïƒÛ"† ýfÊeLü^UGtKÀ&€ÚóÞ¹(H`8r·©` ú¬Ñž_úÍdJ¦Jœ»µãã‡o*ï(ÏÆôH`t»<74> caÅŠ* ‚¥`e2û
Ÿq—ÿ>þážYÞé-õÝL%#ú ÌaÇ<61>Ô=€ÙvŸ4—8ØK=(4Bxñ¿Ñ—ÀŽø¸þ3éM<E28099>„ÜàtOpnO¿Ù‡ØHüê¶YS_ «<C2A0>ó·cÃÍÍÁ(äöôÇ=·<m]øÀÌí°;â«×gœ¡zÎ K´¬­êànî)¹M?¯h}1×^Áüy¾;+<2B>ôÌE­ òt ¦0tøÄépø¨ótèŠéàà§vnÿ ü#Ž1/F„Üû¤ÏÁífÛ…)M:Øo˜î¤r¿øªbÎ<…D`±²×´hÓÁ]z¬þp}ÉÁwðê`64äX¼kÜz
¨lïC ƒutÛüT`#ä]Âø-á&ŽÓTaØÔah°s!Õ ¡´,µ•as^Ú —xyžíc h7¨zU†çÒ<C3A7>"ÑykyOâMèÁpÚN_çbv Ɔ> Æ<>Ó©CïŒ8]r¢‰8[ÇŒøÓ/V+ `˜ªKƒ<4B>ÎKYËI(à\\m^ÔT\éŒeãôq0Bfa<66>ѦR5'Âå± ín7þxƒ»†oí·“r‰§©<C2A7>Ës†ršGQN`w<>,— ‡]÷Ú÷œË%§yˆK¢,€tsšÇwI'Nóøµ—]9ðð”s00¨dÐ/ê„OCqúF<C3BA>>ç¥<C3A7>p‰•ô93âsë` €FmF|zL9!Æ .WÒ>¯ø«Xøü‚Ç$'¥iÂ|pJŠ¥íTì½@õÝï™r蹜ΠKŠ†˜Òkþ
L..ófe|Q™O¡K°•FurÃÂu—.ß <q¢Â+T”9*Às#×ÆŸz51ÕT\<5C><04>ÿ=ØÐW`ʦ·àkÌÁ…†Ø¶`ÚÅ|ý¢ITdñß&ßlEV?=ãêh«XW½NbóÍ?°ãrw#ô€á´ªöê<C3B6>ð/¹ñ³‡)ÿ€À¸n+sîÁ3S<33>ë-ÕLCþ7¼ÇJ°úî1ÿÌ…?ØÅ Ë<{¸Z¶gE¼åP òË3³ñŽúw<ðÓd´ó²ëæÅÅ;/·Œ~cÂ
Þq(½È«ðŽËuô•…;~ÿð²E—½¢ƒ/aejÎ|¶Pl­íÆ·àW­»3jë§ãDçVðíù(G“9HrD€âQ„Â…t"ðp•ÇL'¯q*”| <gÂ_+±½·Œ\!ꇯ,þÊg;L}ß0ÞðåËP°¼1 íË¿W¼ §çÇõ ûiõêc?>úL-FÁ6Ü°Ðú
¾¬·| 20ïiòÝ ï Ûú«Á¼>84Yà߶.Ï_ïxYíw|òÃ? úMv4#l4ßoÆÊjfWî™=ÓOkùjÅØb1°bÚŠŽáÏòºÇá¶'²þ»C…„å
,â/³ºï}¯¦Jý>þd?å‡ ¾<>Ÿm×Yg¤Ý©çÚ_ÅüÊ4Î4ÛŸÂÈ•~ƒâ)ÁD9æ\Ùî~bBL<­8Š™ž{6ŽÂ,ž§ ûZ<C3BB>´3„´<´ì¨>ä"ñc<>·ïéO½†ŒL!‡8-e+SJÒK¨ÖÊv¶|Þkòøò®¶|E© Î~˹ái ]žUmèhäIùÊ‚«Ä†çŒq‡<71>ždÀ
+/ÝÄÄj<C384>qž14+Å“Ôc¯³æ€YÕÅ<C395>
,Oþ1±%@û¢¯¹<C2AF>.WL§DtÁÄ( ¿ÜìKi\OpF¬„.]ÌÜŒVB—j®äJ-ˆH-¸ º\,/eþ0[ y}Oó°"©:µ˜-6çÍñ›?<™Š×ûº™lI¶É¿÷ùíø°&7{CÌàÉ´r•J$˜'ÇÛ _€sþæeŸå6c?BE”Jˆø0ŸFK˲¹ù0ÌO‰^RšhhÙµas™Ýƒ»ƒ¹ƒp®e´i'üÚcb;LøTr ³ÈP4×nΓTöPp<ÕÞ$KÑïvéæ bV=K *­ü{>5<>§¼wÖ¶¾oå¾*«|áãÛ1DEÂÇÇÀÔ¢JÆJ³áh$ÕÙV×Ðw
áŸ8<Ø¢atyîû2ÕÙw`!AîÓŸŽe@Ò
7¼]2BÉòÐcf¶;@ÝÅ®–à' ¿ò:Öi³Ÿ¬L!=XŒvñbDkÓɧ/Lsn´xÝü¸ýííÓŸêì²Ü2
/Äë +ÃÆì<C386>d¢Á¶€GpÏðEæû:ôÓB96¶ú0ü¥²{l8j°ÜÄ'^`ØÁ²Hn“d#çJuŠ3{
EéÕ‡
ãñCÀê†çV°•å<E280A2>ŠKðƒàAJÌiÔÜÌé–‡.°'M®t/ø3<C3B8> \°n6̹$>Û­ÛÆ4ü Ž^ÝÍ¡9í i ½pJB¯éƒ“1ÎùJ`;N¯±\æõ>þ<>‡«»L;³ycŽÂÈ~Øû(ó Y
ã.¯àÚ~žÉ¾ñI՜؉Ì<>£¦9ì¢ð™·1Ÿ†¦s ¦PÄ»¿ŒR¡Ñqè;¿£Y­Ö4Z¾ºa¸Û f.bAø³\øá(Ë¡Úÿ7‰³§ÌÞƒühF\<5C>þI'”ðJŒSqXN{-<2D>3åþüÐóŒ<C3B3>ùTø|t0Ÿ°žïg~ô›/Ûs$Ý ½¯Ë«üôŽ†~P:‘ꘓ,€Ý ­Ò•5Hw÷Èþ Ì~J &~X”Ïi‡%x!šb»pþîêò‡ñÇÉØ1\ü@¯)s¦Ø&úM™3íÄÐ'˜2gÚ1ÜÞµ^SæL;† ˆ©A…˜£óJ}øÄ ,ˆüöÏ?(Ëm+Þžó/ܶ"å<>lMRT"ÕDåÓ阳%/<2F>æžÉ•¢_evQÍø6ì»ïQ²…Jõ¿ ûr à`ïËø ´,Èl@º0Þ³/Y°ì€ŸÜüoþ707Î<òÆJ1au¿§ÎŸyAÒÌe_ØÉd‰øºÉï^ö˜ÔnãNº{ WÜ%»—èŒuŽh'oÜA:H7%ÔãhL<68>_J üòtèãt@›Ê,Þq"€îàD€g숉À14N‡aâY ƒÿcå<63>`‰`yºOßÊæ3XôìG¨1Cú ¸…Ëf³b»ÙòÌPj õ©ÄPʘD™ÖæèŒXuLºœ:ŒÞNÇÊPÀ<>X~É@êËžæyÙ@ÐÙ<C390>¬è<w seÖÒ%QZõÂPT<1D>¯ú,ÑN]ç<>Þö$AGsãsw™°i ¤ÒŠ'šîiŒ(ùNàÞ%‡AÒå|$ó½ÃÑèÈòpæ"»áîbI6¶Fmb¨­ÅehzkQ~ê<>%Dë}òÔÃúK¿Ê¢#s{\Ò•pš4±hô{™êR.8M/·öæÚ\rÔ )ѲŒrÂ@69j"NÓ=ê\$pZï`ºlí¿Í:”´<E2809D>þ`-<2D>yK”À8ºH!%="µˆ¡Ñ‰¹‚â:Áê5bŒôel1Úì%}¦ýê@òJzÇz­Ð|œÆ¬Q,riý°`Àµ ª|àò»ËÂvZ:y!!8ÁyŠQÊë„(µ(åuB”hnÔ¢”× Q"4jQÊë„(Ñn¯Z”ò:!ÊîÌU¥(åuB”\\@1Jy<4A>%@£¥¼Nˆmø«E)¯¢D9†jQÊë„(9) ¥¼NˆºÔ¢”:C”Yá j6#ƒ‘<16>@ GmÌQ¸CÓ#š%תó 7uÝPjY1©ÅË679èµ¢ëÁŸ þa;“Œ14µ˜]ˆÈà_îœð´ Õ,ÀSÄßIg‡âδ '˜hêô5ö!{?Ë´ŸþÄ6ð¹]üœ×i™{Ød žsÝÔ¤ªƒï4L´«ìÐñâ(l—ý’ :ûaKÐàOƕ츰[L(Âl³{K¯Ö2.{ÎniõÏn6xæ"@!¡ˆ`.ì¸|;6|¸{ ÷9á©ïp7sPØLð<4C>Lðóø©Eî;Ô$8ȳŦ6ü‡¤nþð˜ÿðüŽ¼¾ˆÁ /Aøkmt󇵶<C2B5>mm†Ä9ðd¨}~1Þ/¶›!õ<>!†~ë>Õ^+yCÌÀ6<C380>¬ ´¿ÛÐöéöqpóaÈÀ?Ý¿àß&üC°øá]ôÐËþÖýöñ|ú1n_Ðð—ÁKž _„arÞ(áŽúÂaƒ?t ë›?a¿Ûòr¿Ônþh)u<>í#ðÿÎÝ ˆ)f˜ÁÌ06Õ34´4„Šc†‰<E280A0>ž9ÈVSK¨ƦÆz&0"Ì011Ó3‡‡!Ô D’ê#˜;,-Eˆ0ÃÇ šâ€ œÞtA¥°j@bzjHQbf(¦'–¥*$æåå—$–¤¥ÒRRŠ3òËA" Mp ÀäìïÆËM˜Ù
endstream endobj 5 0 obj <</Intent 14 0 R/Name(Logo)/Type/OCG/Usage 15 0 R>> endobj 14 0 obj [/View/Design] endobj 15 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 22 0 obj [21 0 R] endobj 35 0 obj <</CreationDate(D:20171230161300+01'00')/Creator(Adobe Illustrator CS6 \(Windows\))/ModDate(D:20171230161716+01'00')>> endobj xref
0 36
0000000004 65535 f
0000000016 00000 n
0000000159 00000 n
0000009448 00000 n
0000000000 00000 f
0000039045 00000 n
0000000000 00000 f
0000009499 00000 n
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000039112 00000 n
0000039143 00000 n
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000010825 00000 n
0000039228 00000 n
0000009835 00000 n
0000011122 00000 n
0000011009 00000 n
0000010082 00000 n
0000010263 00000 n
0000010311 00000 n
0000010893 00000 n
0000010924 00000 n
0000011196 00000 n
0000011370 00000 n
0000012385 00000 n
0000014612 00000 n
0000039253 00000 n
trailer
<</Size 36/Root 1 0 R/Info 35 0 R/ID[<95FCB4CF9C1B59448ABEC1DF1DD64C33><716E2DB4294F6749B3E5ADF7E13AF65C>]>>
startxref
39388
%%EOF

BIN
web/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

View File

@ -1,31 +0,0 @@
{
"name": "stairs",
"version": "1.0.0",
"description": "Stairs lighting project",
"main": "app.js",
"author": "Mark van Renswoude",
"license": "ISC",
"dependencies": {
"buffer-reader": "^0.1.0",
"express": "^4.15.2",
"md5-file": "^3.1.1",
"semver-utils": "^1.1.1"
},
"devDependencies": {
"@types/crossroads": "0.0.29",
"@types/hasher": "0.0.29",
"@types/jquery": "^2.0.41",
"@types/knockout": "^3.4.40",
"@types/nprogress": "0.0.29",
"@types/requirejs": "^2.1.29",
"gulp": "^3.9.1",
"gulp-clean-css": "^3.0.4",
"gulp-concat": "^2.6.1",
"gulp-debounced-watch": "^1.0.4",
"gulp-plumber": "^1.1.0",
"gulp-sass": "^3.1.0",
"gulp-typescript": "^3.1.6",
"gulp-uglify": "^2.1.2",
"typescript": "^2.2.2"
}
}

View File

@ -1,24 +0,0 @@
module.exports =
{
Command:
{
Error: 0x00,
Ping: 0x01,
Reply: 0x02,
GetMode: 0x03,
SetMode: 0x04,
GetRange: 0x05,
SetRange: 0x06,
UpdateFirmware: 0xFF
},
Mode:
{
Static: 0x01,
Custom: 0x02,
Alternate: 0x03,
Slide: 0x04
//ADC: 0x05
}
};

222
web/site.scss Normal file
View File

@ -0,0 +1,222 @@
$color-primary: #0066ff;
$color-quaternary: #404040;
@import "milligram";
$bodyBackgroundColor: black;
$textColor: white;
$containerBackgroundColor: #202020;
$containerShadow: 0 0 50px #fcf6cf;
$buttonBorderColor: #404040;
$sliderBarColor: #404040;
$sliderBarSize: .5rem;
$sliderThumbColor: #fcf6cf;
$sliderThumbSize: 2rem;
$smallScreen: "screen and (min-width: 768px)";
[v-cloak]
{
display: none;
}
body
{
background-color: $bodyBackgroundColor;
color: $textColor;
font-family: 'Verdana', 'Arial', sans-serif;
font-size: 10pt;
padding-bottom: 3rem;
@media #{$smallScreen}
{
padding-top: 3rem;
}
}
input, textarea
{
color: $textColor;
}
#container
{
background-color: $containerBackgroundColor;
margin-top: 2rem;
padding: 1rem;
box-shadow: $containerShadow;
border: solid 1px black;
@media #{$smallScreen}
{
width: 768px;
margin-left: auto;
margin-right: auto;
}
}
.header
{
position: relative;
img
{
float: left;
margin-right: 1rem;
}
.wifistatus
{
position: absolute;
right: 0;
top: 0;
.indicator
{
display: inline-block;
width: 1rem;
height: 1rem;
border-radius: 50%;
margin-right: 0.5rem;
&[data-status=connected] { background-color: #339966; }
&[data-status=disconnected] { border: solid 1px #808080; }
&[data-status=connecting] { background-color: #ff9933; }
&[data-status=error] { background-color: #cc0000; }
}
}
}
h1
{
font-size: 16pt;
margin: 0;
}
h2
{
color: #c0c0c0;
font-size: 10pt;
margin: 0;
}
h3
{
color: #808080;
background-color: #282828;
font-size: 14pt;
border-bottom: solid 1px #808080;
}
.version
{
color: #808080;
font-size: 8pt;
text-align: center;
margin-top: 2rem;
}
.tabs
{
clear: both;
margin-top: 3rem;
.button
{
background-color: $buttonBorderColor;
color: $textColor !important;
border-color: #808080;
&.button-outline
{
background-color: transparent;
}
}
}
input[disabled]
{
cursor: not-allowed;
color: #808080;
background-color: #262626;
}
.label-inline
{
margin-right: 2rem;
}
.hint
{
display: block;
font-size: 8pt;
color: #808080;
margin-bottom: 1.5rem;
}
.loading
{
margin-top: 3rem;
text-align: center;
}
.suboptions
{
margin-left: 5rem;
}
.buttons
{
text-align: center;
}
.slider
{
-webkit-appearance: none;
width: 100%;
height: $sliderBarSize;
border-radius: $sliderBarSize / 2;
background: $sliderBarColor;
outline: none;
&::-webkit-slider-thumb
{
-webkit-appearance: none;
appearance: none;
width: $sliderThumbSize;
height: $sliderThumbSize;
border-radius: 50%;
background: $sliderThumbColor;
cursor: pointer;
}
&::-moz-range-thumb
{
width: $sliderThumbSize;
height: $sliderThumbSize;
border-radius: 50%;
background: $sliderThumbColor;
cursor: pointer;
}
}

View File

@ -1 +0,0 @@
var bowerBase="../../bower_components/",config={baseUrl:"assets/dist/",shim:{bootstrap:{deps:["jquery","tether"],exports:"Bootstrap"}},paths:{crossroads:bowerBase+"crossroads/dist/crossroads.min",hasher:bowerBase+"hasher/dist/js/hasher.min",jquery:bowerBase+"jquery/dist/jquery.min",knockout:bowerBase+"knockout/dist/knockout",signals:bowerBase+"js-signals/dist/signals.min",text:bowerBase+"text/text",bootstrap:bowerBase+"bootstrap/dist/js/bootstrap.min",tether:bowerBase+"tether/dist/js/tether.min",nprogress:bowerBase+"nprogress/nprogress"}};config.wrapShim=!0,requirejs.config(config),window.Tether=require(["tether"],function(){require(["bootstrap","index"])});

View File

@ -1 +0,0 @@
body{background-color:#fff}#page{margin-top:16px}.row .header{font-weight:700;padding-bottom:8px}

View File

@ -1,26 +0,0 @@
<form>
<div class="form-group row">
<label for="host" class="col-sm-2 col-form-label">Host</label>
<div class="col-sm-10">
<input type="text" class="form-control" data-bind="value: Host" id="host" />
</div>
</div>
<div class="form-group row">
<label for="port" class="col-sm-2 col-form-label">Port</label>
<div class="col-sm-10">
<input type="number" class="form-control" data-bind="value: Port" min="1" max="65536" id="port" />
</div>
</div>
<div class="form-group row">
<label for="path" class="col-sm-2 col-form-label">Path</label>
<div class="col-sm-10">
<input type="text" class="form-control" data-bind="value: Path" id="path" />
</div>
</div>
<div class="form-group row">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-primary" data-bind="click: updateFirmware">Check for update</button>
</div>
</div>
</form>

View File

@ -1 +0,0 @@
define(["require","exports","text!./page-firmware.html","knockout"],function(t,e,o,r){"use strict";return{viewModel:function(){function t(){this.Host=r.observable(location.hostname),this.Port=r.observable(location.port),this.Path=r.observable("/updateFirmware"),this.updateFirmware=function(){}}return t}(),template:o}});

View File

@ -1 +0,0 @@
Hello world!

View File

@ -1 +0,0 @@
define(["require","exports","text!./page-home.html"],function(e,t,n){"use strict";return{viewModel:function(){function e(){}return e.prototype.dispose=function(){},e}(),template:n}});

View File

@ -1,71 +0,0 @@
<form>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="mode" data-bind="checkedValue: StairsMode.Static, checked: Stairs.Mode.Current">
Static
</label>
</div>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="mode" data-bind="checkedValue: StairsMode.Custom, checked: Stairs.Mode.Current">
Custom
</label>
</div>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="mode" data-bind="checkedValue: StairsMode.Alternate, checked: Stairs.Mode.Current">
Alternating
</label>
</div>
</div>
</form>
<div data-bind="visible: Stairs.Mode.Current() == StairsMode.Static" style="display: none">
<div class="form-group row">
<div class="col-sm-2">Brightness</div>
<div class="col-sm-5"><input type="number" class="form-control" min="0" max="4095" data-bind="value: Stairs.Mode.Static.Brightness" /></div>
<div class="col-sm-5"><input type="range" class="form-control" min="0" max="4095" data-bind="value: Stairs.Mode.Static.Brightness, valueUpdate: 'input'" /></div>
</div>
</div>
<div data-bind="visible: Stairs.Mode.Current() == StairsMode.Custom" style="display: none">
<form>
<div class="row">
<div class="col-sm-2 header">Step</div>
<div class="col-sm-10 header">Value</div>
</div>
<div data-bind="foreach: Stairs.Mode.Custom.Brightness">
<div class="form-group row">
<div class="col-sm-2" data-bind="text: $parent.Stairs.Mode.Custom.Brightness().length - $index()"></div>
<div class="col-sm-5"><input type="number" class="form-control" min="0" max="4095" data-bind="value: $data.value" /></div>
<div class="col-sm-5"><input type="range" class="form-control" min="0" max="4095" data-bind="value: $data.value, valueUpdate: 'input'" /></div>
</div>
</div>
</form>
</div>
<div data-bind="visible: Stairs.Mode.Current() == StairsMode.Alternate" style="display: none">
<div class="form-group row">
<div class="col-sm-2">Interval</div>
<div class="col-sm-5"><input type="number" class="form-control" data-bind="value: Stairs.Mode.Alternate.Interval" /></div>
<div class="col-sm-5"></div>
</div>
<div class="form-group row">
<div class="col-sm-2">Brightness</div>
<div class="col-sm-5"><input type="number" class="form-control" min="0" max="4095" data-bind="value: Stairs.Mode.Alternate.Brightness" /></div>
<div class="col-sm-5"><input type="range" class="form-control" min="0" max="4095" data-bind="value: Stairs.Mode.Alternate.Brightness, valueUpdate: 'input'" /></div>
</div>
</div>
<!--
<div data-bind="visible: Stairs.Mode.Current() == StairsMode.Slide" style="display: none">
<div class="parameter">
Brightness: <input type="range" min="0" max="4095" data-bind="value: slide.brightness, valueUpdate: 'input'" /> <input type="number" min="0" max="4095" data-bind="value: slide.brightness" />
</div>
</div>
-->

View File

@ -1 +0,0 @@
define(["require","exports","text!./page-mode.html","stairs"],function(t,e,i,r){"use strict";return{viewModel:function(){function t(){this.StairsMode=r.StairsMode,this.Stairs=r.Stairs.instance()}return t}(),template:i}});

View File

@ -1,23 +0,0 @@
<form>
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" class="form-check-input" data-bind="checked: Stairs.Range.UseScaling"> Use scaling
</label>
</div>
<div class="row">
<div class="col-sm-2 header">Step</div>
<div class="col-sm-5 header">Start (min. 0)</div>
<div class="col-sm-5 header">End (max. 4095)</div>
</div>
<div data-bind="foreach: Stairs.Range.Values">
<div class="form-group row">
<div class="col-sm-2" data-bind="text: $parent.Stairs.Range.Values().length - $index()"></div>
<div class="col-sm-5"><input type="number" class="form-control" data-bind="value: Start"></div>
<div class="col-sm-5"><input type="number" class="form-control" data-bind="value: End"></div>
</div>
</div>
<button class="btn btn-warning" data-bind="click: resetRanges">Reset</button>
</form>

View File

@ -1 +0,0 @@
define(["require","exports","text!./page-settings.html","stairs"],function(t,e,n,r){"use strict";return{viewModel:function(){function t(){var t=this;this.Stairs=r.Stairs.instance(),this.resetRanges=function(){return t.Stairs.Range.Values(t.Stairs.Range.Values().map(function(t){var e=new r.StairsRangeValue;return e.Start(0),e.End(4095),e})),!1}}return t}(),template:n}});

View File

@ -1 +0,0 @@
define(["require","exports"],function(e,n){"use strict";n.__esModule=!0;var u=function(){function e(){}return e}();n.Debug=u});

View File

@ -1,7 +0,0 @@
I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project,
Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome,
comprehensive icon sets or copy and paste your own.
Please. Check it out.
-Dave Gandy

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 434 KiB

View File

@ -1,34 +0,0 @@
// Animated Icons
// --------------------------
.@{fa-css-prefix}-spin {
-webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear;
}
.@{fa-css-prefix}-pulse {
-webkit-animation: fa-spin 1s infinite steps(8);
animation: fa-spin 1s infinite steps(8);
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}

View File

@ -1,25 +0,0 @@
// Bordered & Pulled
// -------------------------
.@{fa-css-prefix}-border {
padding: .2em .25em .15em;
border: solid .08em @fa-border-color;
border-radius: .1em;
}
.@{fa-css-prefix}-pull-left { float: left; }
.@{fa-css-prefix}-pull-right { float: right; }
.@{fa-css-prefix} {
&.@{fa-css-prefix}-pull-left { margin-right: .3em; }
&.@{fa-css-prefix}-pull-right { margin-left: .3em; }
}
/* Deprecated as of 4.4.0 */
.pull-right { float: right; }
.pull-left { float: left; }
.@{fa-css-prefix} {
&.pull-left { margin-right: .3em; }
&.pull-right { margin-left: .3em; }
}

View File

@ -1,12 +0,0 @@
// Base Class Definition
// -------------------------
.@{fa-css-prefix} {
display: inline-block;
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
font-size: inherit; // can't have font-size inherit on line above, so need to override
text-rendering: auto; // optimizelegibility throws things off #1094
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@ -1,6 +0,0 @@
// Fixed Width Icons
// -------------------------
.@{fa-css-prefix}-fw {
width: (18em / 14);
text-align: center;
}

View File

@ -1,18 +0,0 @@
/*!
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/
@import "variables.less";
@import "mixins.less";
@import "path.less";
@import "core.less";
@import "larger.less";
@import "fixed-width.less";
@import "list.less";
@import "bordered-pulled.less";
@import "animated.less";
@import "rotated-flipped.less";
@import "stacked.less";
@import "icons.less";
@import "screen-reader.less";

View File

@ -1,789 +0,0 @@
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
readers do not read off random characters that represent icons */
.@{fa-css-prefix}-glass:before { content: @fa-var-glass; }
.@{fa-css-prefix}-music:before { content: @fa-var-music; }
.@{fa-css-prefix}-search:before { content: @fa-var-search; }
.@{fa-css-prefix}-envelope-o:before { content: @fa-var-envelope-o; }
.@{fa-css-prefix}-heart:before { content: @fa-var-heart; }
.@{fa-css-prefix}-star:before { content: @fa-var-star; }
.@{fa-css-prefix}-star-o:before { content: @fa-var-star-o; }
.@{fa-css-prefix}-user:before { content: @fa-var-user; }
.@{fa-css-prefix}-film:before { content: @fa-var-film; }
.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; }
.@{fa-css-prefix}-th:before { content: @fa-var-th; }
.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; }
.@{fa-css-prefix}-check:before { content: @fa-var-check; }
.@{fa-css-prefix}-remove:before,
.@{fa-css-prefix}-close:before,
.@{fa-css-prefix}-times:before { content: @fa-var-times; }
.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; }
.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; }
.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; }
.@{fa-css-prefix}-signal:before { content: @fa-var-signal; }
.@{fa-css-prefix}-gear:before,
.@{fa-css-prefix}-cog:before { content: @fa-var-cog; }
.@{fa-css-prefix}-trash-o:before { content: @fa-var-trash-o; }
.@{fa-css-prefix}-home:before { content: @fa-var-home; }
.@{fa-css-prefix}-file-o:before { content: @fa-var-file-o; }
.@{fa-css-prefix}-clock-o:before { content: @fa-var-clock-o; }
.@{fa-css-prefix}-road:before { content: @fa-var-road; }
.@{fa-css-prefix}-download:before { content: @fa-var-download; }
.@{fa-css-prefix}-arrow-circle-o-down:before { content: @fa-var-arrow-circle-o-down; }
.@{fa-css-prefix}-arrow-circle-o-up:before { content: @fa-var-arrow-circle-o-up; }
.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; }
.@{fa-css-prefix}-play-circle-o:before { content: @fa-var-play-circle-o; }
.@{fa-css-prefix}-rotate-right:before,
.@{fa-css-prefix}-repeat:before { content: @fa-var-repeat; }
.@{fa-css-prefix}-refresh:before { content: @fa-var-refresh; }
.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; }
.@{fa-css-prefix}-lock:before { content: @fa-var-lock; }
.@{fa-css-prefix}-flag:before { content: @fa-var-flag; }
.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; }
.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; }
.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; }
.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; }
.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; }
.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; }
.@{fa-css-prefix}-tag:before { content: @fa-var-tag; }
.@{fa-css-prefix}-tags:before { content: @fa-var-tags; }
.@{fa-css-prefix}-book:before { content: @fa-var-book; }
.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; }
.@{fa-css-prefix}-print:before { content: @fa-var-print; }
.@{fa-css-prefix}-camera:before { content: @fa-var-camera; }
.@{fa-css-prefix}-font:before { content: @fa-var-font; }
.@{fa-css-prefix}-bold:before { content: @fa-var-bold; }
.@{fa-css-prefix}-italic:before { content: @fa-var-italic; }
.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; }
.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; }
.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; }
.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; }
.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; }
.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; }
.@{fa-css-prefix}-list:before { content: @fa-var-list; }
.@{fa-css-prefix}-dedent:before,
.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; }
.@{fa-css-prefix}-indent:before { content: @fa-var-indent; }
.@{fa-css-prefix}-video-camera:before { content: @fa-var-video-camera; }
.@{fa-css-prefix}-photo:before,
.@{fa-css-prefix}-image:before,
.@{fa-css-prefix}-picture-o:before { content: @fa-var-picture-o; }
.@{fa-css-prefix}-pencil:before { content: @fa-var-pencil; }
.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; }
.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; }
.@{fa-css-prefix}-tint:before { content: @fa-var-tint; }
.@{fa-css-prefix}-edit:before,
.@{fa-css-prefix}-pencil-square-o:before { content: @fa-var-pencil-square-o; }
.@{fa-css-prefix}-share-square-o:before { content: @fa-var-share-square-o; }
.@{fa-css-prefix}-check-square-o:before { content: @fa-var-check-square-o; }
.@{fa-css-prefix}-arrows:before { content: @fa-var-arrows; }
.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; }
.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; }
.@{fa-css-prefix}-backward:before { content: @fa-var-backward; }
.@{fa-css-prefix}-play:before { content: @fa-var-play; }
.@{fa-css-prefix}-pause:before { content: @fa-var-pause; }
.@{fa-css-prefix}-stop:before { content: @fa-var-stop; }
.@{fa-css-prefix}-forward:before { content: @fa-var-forward; }
.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; }
.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; }
.@{fa-css-prefix}-eject:before { content: @fa-var-eject; }
.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; }
.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; }
.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; }
.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; }
.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; }
.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; }
.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; }
.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; }
.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; }
.@{fa-css-prefix}-times-circle-o:before { content: @fa-var-times-circle-o; }
.@{fa-css-prefix}-check-circle-o:before { content: @fa-var-check-circle-o; }
.@{fa-css-prefix}-ban:before { content: @fa-var-ban; }
.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; }
.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; }
.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; }
.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; }
.@{fa-css-prefix}-mail-forward:before,
.@{fa-css-prefix}-share:before { content: @fa-var-share; }
.@{fa-css-prefix}-expand:before { content: @fa-var-expand; }
.@{fa-css-prefix}-compress:before { content: @fa-var-compress; }
.@{fa-css-prefix}-plus:before { content: @fa-var-plus; }
.@{fa-css-prefix}-minus:before { content: @fa-var-minus; }
.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; }
.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; }
.@{fa-css-prefix}-gift:before { content: @fa-var-gift; }
.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; }
.@{fa-css-prefix}-fire:before { content: @fa-var-fire; }
.@{fa-css-prefix}-eye:before { content: @fa-var-eye; }
.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; }
.@{fa-css-prefix}-warning:before,
.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; }
.@{fa-css-prefix}-plane:before { content: @fa-var-plane; }
.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; }
.@{fa-css-prefix}-random:before { content: @fa-var-random; }
.@{fa-css-prefix}-comment:before { content: @fa-var-comment; }
.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; }
.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; }
.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; }
.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; }
.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; }
.@{fa-css-prefix}-folder:before { content: @fa-var-folder; }
.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; }
.@{fa-css-prefix}-arrows-v:before { content: @fa-var-arrows-v; }
.@{fa-css-prefix}-arrows-h:before { content: @fa-var-arrows-h; }
.@{fa-css-prefix}-bar-chart-o:before,
.@{fa-css-prefix}-bar-chart:before { content: @fa-var-bar-chart; }
.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; }
.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; }
.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; }
.@{fa-css-prefix}-key:before { content: @fa-var-key; }
.@{fa-css-prefix}-gears:before,
.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; }
.@{fa-css-prefix}-comments:before { content: @fa-var-comments; }
.@{fa-css-prefix}-thumbs-o-up:before { content: @fa-var-thumbs-o-up; }
.@{fa-css-prefix}-thumbs-o-down:before { content: @fa-var-thumbs-o-down; }
.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; }
.@{fa-css-prefix}-heart-o:before { content: @fa-var-heart-o; }
.@{fa-css-prefix}-sign-out:before { content: @fa-var-sign-out; }
.@{fa-css-prefix}-linkedin-square:before { content: @fa-var-linkedin-square; }
.@{fa-css-prefix}-thumb-tack:before { content: @fa-var-thumb-tack; }
.@{fa-css-prefix}-external-link:before { content: @fa-var-external-link; }
.@{fa-css-prefix}-sign-in:before { content: @fa-var-sign-in; }
.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; }
.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; }
.@{fa-css-prefix}-upload:before { content: @fa-var-upload; }
.@{fa-css-prefix}-lemon-o:before { content: @fa-var-lemon-o; }
.@{fa-css-prefix}-phone:before { content: @fa-var-phone; }
.@{fa-css-prefix}-square-o:before { content: @fa-var-square-o; }
.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; }
.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; }
.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; }
.@{fa-css-prefix}-facebook-f:before,
.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; }
.@{fa-css-prefix}-github:before { content: @fa-var-github; }
.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; }
.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; }
.@{fa-css-prefix}-feed:before,
.@{fa-css-prefix}-rss:before { content: @fa-var-rss; }
.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; }
.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; }
.@{fa-css-prefix}-bell:before { content: @fa-var-bell; }
.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; }
.@{fa-css-prefix}-hand-o-right:before { content: @fa-var-hand-o-right; }
.@{fa-css-prefix}-hand-o-left:before { content: @fa-var-hand-o-left; }
.@{fa-css-prefix}-hand-o-up:before { content: @fa-var-hand-o-up; }
.@{fa-css-prefix}-hand-o-down:before { content: @fa-var-hand-o-down; }
.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; }
.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; }
.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; }
.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; }
.@{fa-css-prefix}-globe:before { content: @fa-var-globe; }
.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; }
.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; }
.@{fa-css-prefix}-filter:before { content: @fa-var-filter; }
.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; }
.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; }
.@{fa-css-prefix}-group:before,
.@{fa-css-prefix}-users:before { content: @fa-var-users; }
.@{fa-css-prefix}-chain:before,
.@{fa-css-prefix}-link:before { content: @fa-var-link; }
.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; }
.@{fa-css-prefix}-flask:before { content: @fa-var-flask; }
.@{fa-css-prefix}-cut:before,
.@{fa-css-prefix}-scissors:before { content: @fa-var-scissors; }
.@{fa-css-prefix}-copy:before,
.@{fa-css-prefix}-files-o:before { content: @fa-var-files-o; }
.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; }
.@{fa-css-prefix}-save:before,
.@{fa-css-prefix}-floppy-o:before { content: @fa-var-floppy-o; }
.@{fa-css-prefix}-square:before { content: @fa-var-square; }
.@{fa-css-prefix}-navicon:before,
.@{fa-css-prefix}-reorder:before,
.@{fa-css-prefix}-bars:before { content: @fa-var-bars; }
.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; }
.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; }
.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; }
.@{fa-css-prefix}-underline:before { content: @fa-var-underline; }
.@{fa-css-prefix}-table:before { content: @fa-var-table; }
.@{fa-css-prefix}-magic:before { content: @fa-var-magic; }
.@{fa-css-prefix}-truck:before { content: @fa-var-truck; }
.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; }
.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; }
.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; }
.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; }
.@{fa-css-prefix}-money:before { content: @fa-var-money; }
.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; }
.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; }
.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; }
.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; }
.@{fa-css-prefix}-columns:before { content: @fa-var-columns; }
.@{fa-css-prefix}-unsorted:before,
.@{fa-css-prefix}-sort:before { content: @fa-var-sort; }
.@{fa-css-prefix}-sort-down:before,
.@{fa-css-prefix}-sort-desc:before { content: @fa-var-sort-desc; }
.@{fa-css-prefix}-sort-up:before,
.@{fa-css-prefix}-sort-asc:before { content: @fa-var-sort-asc; }
.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; }
.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; }
.@{fa-css-prefix}-rotate-left:before,
.@{fa-css-prefix}-undo:before { content: @fa-var-undo; }
.@{fa-css-prefix}-legal:before,
.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; }
.@{fa-css-prefix}-dashboard:before,
.@{fa-css-prefix}-tachometer:before { content: @fa-var-tachometer; }
.@{fa-css-prefix}-comment-o:before { content: @fa-var-comment-o; }
.@{fa-css-prefix}-comments-o:before { content: @fa-var-comments-o; }
.@{fa-css-prefix}-flash:before,
.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; }
.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; }
.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; }
.@{fa-css-prefix}-paste:before,
.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; }
.@{fa-css-prefix}-lightbulb-o:before { content: @fa-var-lightbulb-o; }
.@{fa-css-prefix}-exchange:before { content: @fa-var-exchange; }
.@{fa-css-prefix}-cloud-download:before { content: @fa-var-cloud-download; }
.@{fa-css-prefix}-cloud-upload:before { content: @fa-var-cloud-upload; }
.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; }
.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; }
.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; }
.@{fa-css-prefix}-bell-o:before { content: @fa-var-bell-o; }
.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; }
.@{fa-css-prefix}-cutlery:before { content: @fa-var-cutlery; }
.@{fa-css-prefix}-file-text-o:before { content: @fa-var-file-text-o; }
.@{fa-css-prefix}-building-o:before { content: @fa-var-building-o; }
.@{fa-css-prefix}-hospital-o:before { content: @fa-var-hospital-o; }
.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; }
.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; }
.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; }
.@{fa-css-prefix}-beer:before { content: @fa-var-beer; }
.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; }
.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; }
.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; }
.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; }
.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; }
.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; }
.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; }
.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; }
.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; }
.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; }
.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; }
.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; }
.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; }
.@{fa-css-prefix}-mobile-phone:before,
.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; }
.@{fa-css-prefix}-circle-o:before { content: @fa-var-circle-o; }
.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; }
.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; }
.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; }
.@{fa-css-prefix}-circle:before { content: @fa-var-circle; }
.@{fa-css-prefix}-mail-reply:before,
.@{fa-css-prefix}-reply:before { content: @fa-var-reply; }
.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; }
.@{fa-css-prefix}-folder-o:before { content: @fa-var-folder-o; }
.@{fa-css-prefix}-folder-open-o:before { content: @fa-var-folder-open-o; }
.@{fa-css-prefix}-smile-o:before { content: @fa-var-smile-o; }
.@{fa-css-prefix}-frown-o:before { content: @fa-var-frown-o; }
.@{fa-css-prefix}-meh-o:before { content: @fa-var-meh-o; }
.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; }
.@{fa-css-prefix}-keyboard-o:before { content: @fa-var-keyboard-o; }
.@{fa-css-prefix}-flag-o:before { content: @fa-var-flag-o; }
.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; }
.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; }
.@{fa-css-prefix}-code:before { content: @fa-var-code; }
.@{fa-css-prefix}-mail-reply-all:before,
.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; }
.@{fa-css-prefix}-star-half-empty:before,
.@{fa-css-prefix}-star-half-full:before,
.@{fa-css-prefix}-star-half-o:before { content: @fa-var-star-half-o; }
.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; }
.@{fa-css-prefix}-crop:before { content: @fa-var-crop; }
.@{fa-css-prefix}-code-fork:before { content: @fa-var-code-fork; }
.@{fa-css-prefix}-unlink:before,
.@{fa-css-prefix}-chain-broken:before { content: @fa-var-chain-broken; }
.@{fa-css-prefix}-question:before { content: @fa-var-question; }
.@{fa-css-prefix}-info:before { content: @fa-var-info; }
.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; }
.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; }
.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; }
.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; }
.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; }
.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; }
.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; }
.@{fa-css-prefix}-shield:before { content: @fa-var-shield; }
.@{fa-css-prefix}-calendar-o:before { content: @fa-var-calendar-o; }
.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; }
.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; }
.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; }
.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; }
.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; }
.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; }
.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; }
.@{fa-css-prefix}-html5:before { content: @fa-var-html5; }
.@{fa-css-prefix}-css3:before { content: @fa-var-css3; }
.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; }
.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; }
.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; }
.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; }
.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; }
.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; }
.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; }
.@{fa-css-prefix}-ticket:before { content: @fa-var-ticket; }
.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; }
.@{fa-css-prefix}-minus-square-o:before { content: @fa-var-minus-square-o; }
.@{fa-css-prefix}-level-up:before { content: @fa-var-level-up; }
.@{fa-css-prefix}-level-down:before { content: @fa-var-level-down; }
.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; }
.@{fa-css-prefix}-pencil-square:before { content: @fa-var-pencil-square; }
.@{fa-css-prefix}-external-link-square:before { content: @fa-var-external-link-square; }
.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; }
.@{fa-css-prefix}-compass:before { content: @fa-var-compass; }
.@{fa-css-prefix}-toggle-down:before,
.@{fa-css-prefix}-caret-square-o-down:before { content: @fa-var-caret-square-o-down; }
.@{fa-css-prefix}-toggle-up:before,
.@{fa-css-prefix}-caret-square-o-up:before { content: @fa-var-caret-square-o-up; }
.@{fa-css-prefix}-toggle-right:before,
.@{fa-css-prefix}-caret-square-o-right:before { content: @fa-var-caret-square-o-right; }
.@{fa-css-prefix}-euro:before,
.@{fa-css-prefix}-eur:before { content: @fa-var-eur; }
.@{fa-css-prefix}-gbp:before { content: @fa-var-gbp; }
.@{fa-css-prefix}-dollar:before,
.@{fa-css-prefix}-usd:before { content: @fa-var-usd; }
.@{fa-css-prefix}-rupee:before,
.@{fa-css-prefix}-inr:before { content: @fa-var-inr; }
.@{fa-css-prefix}-cny:before,
.@{fa-css-prefix}-rmb:before,
.@{fa-css-prefix}-yen:before,
.@{fa-css-prefix}-jpy:before { content: @fa-var-jpy; }
.@{fa-css-prefix}-ruble:before,
.@{fa-css-prefix}-rouble:before,
.@{fa-css-prefix}-rub:before { content: @fa-var-rub; }
.@{fa-css-prefix}-won:before,
.@{fa-css-prefix}-krw:before { content: @fa-var-krw; }
.@{fa-css-prefix}-bitcoin:before,
.@{fa-css-prefix}-btc:before { content: @fa-var-btc; }
.@{fa-css-prefix}-file:before { content: @fa-var-file; }
.@{fa-css-prefix}-file-text:before { content: @fa-var-file-text; }
.@{fa-css-prefix}-sort-alpha-asc:before { content: @fa-var-sort-alpha-asc; }
.@{fa-css-prefix}-sort-alpha-desc:before { content: @fa-var-sort-alpha-desc; }
.@{fa-css-prefix}-sort-amount-asc:before { content: @fa-var-sort-amount-asc; }
.@{fa-css-prefix}-sort-amount-desc:before { content: @fa-var-sort-amount-desc; }
.@{fa-css-prefix}-sort-numeric-asc:before { content: @fa-var-sort-numeric-asc; }
.@{fa-css-prefix}-sort-numeric-desc:before { content: @fa-var-sort-numeric-desc; }
.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; }
.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; }
.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; }
.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; }
.@{fa-css-prefix}-xing:before { content: @fa-var-xing; }
.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; }
.@{fa-css-prefix}-youtube-play:before { content: @fa-var-youtube-play; }
.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; }
.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; }
.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; }
.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; }
.@{fa-css-prefix}-adn:before { content: @fa-var-adn; }
.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; }
.@{fa-css-prefix}-bitbucket-square:before { content: @fa-var-bitbucket-square; }
.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; }
.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; }
.@{fa-css-prefix}-long-arrow-down:before { content: @fa-var-long-arrow-down; }
.@{fa-css-prefix}-long-arrow-up:before { content: @fa-var-long-arrow-up; }
.@{fa-css-prefix}-long-arrow-left:before { content: @fa-var-long-arrow-left; }
.@{fa-css-prefix}-long-arrow-right:before { content: @fa-var-long-arrow-right; }
.@{fa-css-prefix}-apple:before { content: @fa-var-apple; }
.@{fa-css-prefix}-windows:before { content: @fa-var-windows; }
.@{fa-css-prefix}-android:before { content: @fa-var-android; }
.@{fa-css-prefix}-linux:before { content: @fa-var-linux; }
.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; }
.@{fa-css-prefix}-skype:before { content: @fa-var-skype; }
.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; }
.@{fa-css-prefix}-trello:before { content: @fa-var-trello; }
.@{fa-css-prefix}-female:before { content: @fa-var-female; }
.@{fa-css-prefix}-male:before { content: @fa-var-male; }
.@{fa-css-prefix}-gittip:before,
.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; }
.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; }
.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; }
.@{fa-css-prefix}-archive:before { content: @fa-var-archive; }
.@{fa-css-prefix}-bug:before { content: @fa-var-bug; }
.@{fa-css-prefix}-vk:before { content: @fa-var-vk; }
.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; }
.@{fa-css-prefix}-renren:before { content: @fa-var-renren; }
.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; }
.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; }
.@{fa-css-prefix}-arrow-circle-o-right:before { content: @fa-var-arrow-circle-o-right; }
.@{fa-css-prefix}-arrow-circle-o-left:before { content: @fa-var-arrow-circle-o-left; }
.@{fa-css-prefix}-toggle-left:before,
.@{fa-css-prefix}-caret-square-o-left:before { content: @fa-var-caret-square-o-left; }
.@{fa-css-prefix}-dot-circle-o:before { content: @fa-var-dot-circle-o; }
.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; }
.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; }
.@{fa-css-prefix}-turkish-lira:before,
.@{fa-css-prefix}-try:before { content: @fa-var-try; }
.@{fa-css-prefix}-plus-square-o:before { content: @fa-var-plus-square-o; }
.@{fa-css-prefix}-space-shuttle:before { content: @fa-var-space-shuttle; }
.@{fa-css-prefix}-slack:before { content: @fa-var-slack; }
.@{fa-css-prefix}-envelope-square:before { content: @fa-var-envelope-square; }
.@{fa-css-prefix}-wordpress:before { content: @fa-var-wordpress; }
.@{fa-css-prefix}-openid:before { content: @fa-var-openid; }
.@{fa-css-prefix}-institution:before,
.@{fa-css-prefix}-bank:before,
.@{fa-css-prefix}-university:before { content: @fa-var-university; }
.@{fa-css-prefix}-mortar-board:before,
.@{fa-css-prefix}-graduation-cap:before { content: @fa-var-graduation-cap; }
.@{fa-css-prefix}-yahoo:before { content: @fa-var-yahoo; }
.@{fa-css-prefix}-google:before { content: @fa-var-google; }
.@{fa-css-prefix}-reddit:before { content: @fa-var-reddit; }
.@{fa-css-prefix}-reddit-square:before { content: @fa-var-reddit-square; }
.@{fa-css-prefix}-stumbleupon-circle:before { content: @fa-var-stumbleupon-circle; }
.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; }
.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; }
.@{fa-css-prefix}-digg:before { content: @fa-var-digg; }
.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; }
.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; }
.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; }
.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; }
.@{fa-css-prefix}-language:before { content: @fa-var-language; }
.@{fa-css-prefix}-fax:before { content: @fa-var-fax; }
.@{fa-css-prefix}-building:before { content: @fa-var-building; }
.@{fa-css-prefix}-child:before { content: @fa-var-child; }
.@{fa-css-prefix}-paw:before { content: @fa-var-paw; }
.@{fa-css-prefix}-spoon:before { content: @fa-var-spoon; }
.@{fa-css-prefix}-cube:before { content: @fa-var-cube; }
.@{fa-css-prefix}-cubes:before { content: @fa-var-cubes; }
.@{fa-css-prefix}-behance:before { content: @fa-var-behance; }
.@{fa-css-prefix}-behance-square:before { content: @fa-var-behance-square; }
.@{fa-css-prefix}-steam:before { content: @fa-var-steam; }
.@{fa-css-prefix}-steam-square:before { content: @fa-var-steam-square; }
.@{fa-css-prefix}-recycle:before { content: @fa-var-recycle; }
.@{fa-css-prefix}-automobile:before,
.@{fa-css-prefix}-car:before { content: @fa-var-car; }
.@{fa-css-prefix}-cab:before,
.@{fa-css-prefix}-taxi:before { content: @fa-var-taxi; }
.@{fa-css-prefix}-tree:before { content: @fa-var-tree; }
.@{fa-css-prefix}-spotify:before { content: @fa-var-spotify; }
.@{fa-css-prefix}-deviantart:before { content: @fa-var-deviantart; }
.@{fa-css-prefix}-soundcloud:before { content: @fa-var-soundcloud; }
.@{fa-css-prefix}-database:before { content: @fa-var-database; }
.@{fa-css-prefix}-file-pdf-o:before { content: @fa-var-file-pdf-o; }
.@{fa-css-prefix}-file-word-o:before { content: @fa-var-file-word-o; }
.@{fa-css-prefix}-file-excel-o:before { content: @fa-var-file-excel-o; }
.@{fa-css-prefix}-file-powerpoint-o:before { content: @fa-var-file-powerpoint-o; }
.@{fa-css-prefix}-file-photo-o:before,
.@{fa-css-prefix}-file-picture-o:before,
.@{fa-css-prefix}-file-image-o:before { content: @fa-var-file-image-o; }
.@{fa-css-prefix}-file-zip-o:before,
.@{fa-css-prefix}-file-archive-o:before { content: @fa-var-file-archive-o; }
.@{fa-css-prefix}-file-sound-o:before,
.@{fa-css-prefix}-file-audio-o:before { content: @fa-var-file-audio-o; }
.@{fa-css-prefix}-file-movie-o:before,
.@{fa-css-prefix}-file-video-o:before { content: @fa-var-file-video-o; }
.@{fa-css-prefix}-file-code-o:before { content: @fa-var-file-code-o; }
.@{fa-css-prefix}-vine:before { content: @fa-var-vine; }
.@{fa-css-prefix}-codepen:before { content: @fa-var-codepen; }
.@{fa-css-prefix}-jsfiddle:before { content: @fa-var-jsfiddle; }
.@{fa-css-prefix}-life-bouy:before,
.@{fa-css-prefix}-life-buoy:before,
.@{fa-css-prefix}-life-saver:before,
.@{fa-css-prefix}-support:before,
.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; }
.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; }
.@{fa-css-prefix}-ra:before,
.@{fa-css-prefix}-resistance:before,
.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; }
.@{fa-css-prefix}-ge:before,
.@{fa-css-prefix}-empire:before { content: @fa-var-empire; }
.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; }
.@{fa-css-prefix}-git:before { content: @fa-var-git; }
.@{fa-css-prefix}-y-combinator-square:before,
.@{fa-css-prefix}-yc-square:before,
.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; }
.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; }
.@{fa-css-prefix}-qq:before { content: @fa-var-qq; }
.@{fa-css-prefix}-wechat:before,
.@{fa-css-prefix}-weixin:before { content: @fa-var-weixin; }
.@{fa-css-prefix}-send:before,
.@{fa-css-prefix}-paper-plane:before { content: @fa-var-paper-plane; }
.@{fa-css-prefix}-send-o:before,
.@{fa-css-prefix}-paper-plane-o:before { content: @fa-var-paper-plane-o; }
.@{fa-css-prefix}-history:before { content: @fa-var-history; }
.@{fa-css-prefix}-circle-thin:before { content: @fa-var-circle-thin; }
.@{fa-css-prefix}-header:before { content: @fa-var-header; }
.@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; }
.@{fa-css-prefix}-sliders:before { content: @fa-var-sliders; }
.@{fa-css-prefix}-share-alt:before { content: @fa-var-share-alt; }
.@{fa-css-prefix}-share-alt-square:before { content: @fa-var-share-alt-square; }
.@{fa-css-prefix}-bomb:before { content: @fa-var-bomb; }
.@{fa-css-prefix}-soccer-ball-o:before,
.@{fa-css-prefix}-futbol-o:before { content: @fa-var-futbol-o; }
.@{fa-css-prefix}-tty:before { content: @fa-var-tty; }
.@{fa-css-prefix}-binoculars:before { content: @fa-var-binoculars; }
.@{fa-css-prefix}-plug:before { content: @fa-var-plug; }
.@{fa-css-prefix}-slideshare:before { content: @fa-var-slideshare; }
.@{fa-css-prefix}-twitch:before { content: @fa-var-twitch; }
.@{fa-css-prefix}-yelp:before { content: @fa-var-yelp; }
.@{fa-css-prefix}-newspaper-o:before { content: @fa-var-newspaper-o; }
.@{fa-css-prefix}-wifi:before { content: @fa-var-wifi; }
.@{fa-css-prefix}-calculator:before { content: @fa-var-calculator; }
.@{fa-css-prefix}-paypal:before { content: @fa-var-paypal; }
.@{fa-css-prefix}-google-wallet:before { content: @fa-var-google-wallet; }
.@{fa-css-prefix}-cc-visa:before { content: @fa-var-cc-visa; }
.@{fa-css-prefix}-cc-mastercard:before { content: @fa-var-cc-mastercard; }
.@{fa-css-prefix}-cc-discover:before { content: @fa-var-cc-discover; }
.@{fa-css-prefix}-cc-amex:before { content: @fa-var-cc-amex; }
.@{fa-css-prefix}-cc-paypal:before { content: @fa-var-cc-paypal; }
.@{fa-css-prefix}-cc-stripe:before { content: @fa-var-cc-stripe; }
.@{fa-css-prefix}-bell-slash:before { content: @fa-var-bell-slash; }
.@{fa-css-prefix}-bell-slash-o:before { content: @fa-var-bell-slash-o; }
.@{fa-css-prefix}-trash:before { content: @fa-var-trash; }
.@{fa-css-prefix}-copyright:before { content: @fa-var-copyright; }
.@{fa-css-prefix}-at:before { content: @fa-var-at; }
.@{fa-css-prefix}-eyedropper:before { content: @fa-var-eyedropper; }
.@{fa-css-prefix}-paint-brush:before { content: @fa-var-paint-brush; }
.@{fa-css-prefix}-birthday-cake:before { content: @fa-var-birthday-cake; }
.@{fa-css-prefix}-area-chart:before { content: @fa-var-area-chart; }
.@{fa-css-prefix}-pie-chart:before { content: @fa-var-pie-chart; }
.@{fa-css-prefix}-line-chart:before { content: @fa-var-line-chart; }
.@{fa-css-prefix}-lastfm:before { content: @fa-var-lastfm; }
.@{fa-css-prefix}-lastfm-square:before { content: @fa-var-lastfm-square; }
.@{fa-css-prefix}-toggle-off:before { content: @fa-var-toggle-off; }
.@{fa-css-prefix}-toggle-on:before { content: @fa-var-toggle-on; }
.@{fa-css-prefix}-bicycle:before { content: @fa-var-bicycle; }
.@{fa-css-prefix}-bus:before { content: @fa-var-bus; }
.@{fa-css-prefix}-ioxhost:before { content: @fa-var-ioxhost; }
.@{fa-css-prefix}-angellist:before { content: @fa-var-angellist; }
.@{fa-css-prefix}-cc:before { content: @fa-var-cc; }
.@{fa-css-prefix}-shekel:before,
.@{fa-css-prefix}-sheqel:before,
.@{fa-css-prefix}-ils:before { content: @fa-var-ils; }
.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; }
.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; }
.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; }
.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; }
.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; }
.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; }
.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; }
.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; }
.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; }
.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; }
.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; }
.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; }
.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; }
.@{fa-css-prefix}-ship:before { content: @fa-var-ship; }
.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; }
.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; }
.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; }
.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; }
.@{fa-css-prefix}-venus:before { content: @fa-var-venus; }
.@{fa-css-prefix}-mars:before { content: @fa-var-mars; }
.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; }
.@{fa-css-prefix}-intersex:before,
.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; }
.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; }
.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; }
.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; }
.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; }
.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; }
.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; }
.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; }
.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; }
.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; }
.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; }
.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; }
.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; }
.@{fa-css-prefix}-server:before { content: @fa-var-server; }
.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; }
.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; }
.@{fa-css-prefix}-hotel:before,
.@{fa-css-prefix}-bed:before { content: @fa-var-bed; }
.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; }
.@{fa-css-prefix}-train:before { content: @fa-var-train; }
.@{fa-css-prefix}-subway:before { content: @fa-var-subway; }
.@{fa-css-prefix}-medium:before { content: @fa-var-medium; }
.@{fa-css-prefix}-yc:before,
.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; }
.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; }
.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; }
.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; }
.@{fa-css-prefix}-battery-4:before,
.@{fa-css-prefix}-battery:before,
.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; }
.@{fa-css-prefix}-battery-3:before,
.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; }
.@{fa-css-prefix}-battery-2:before,
.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; }
.@{fa-css-prefix}-battery-1:before,
.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; }
.@{fa-css-prefix}-battery-0:before,
.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; }
.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; }
.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; }
.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; }
.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; }
.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; }
.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; }
.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; }
.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; }
.@{fa-css-prefix}-clone:before { content: @fa-var-clone; }
.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; }
.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; }
.@{fa-css-prefix}-hourglass-1:before,
.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; }
.@{fa-css-prefix}-hourglass-2:before,
.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; }
.@{fa-css-prefix}-hourglass-3:before,
.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; }
.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; }
.@{fa-css-prefix}-hand-grab-o:before,
.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; }
.@{fa-css-prefix}-hand-stop-o:before,
.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; }
.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; }
.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; }
.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; }
.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; }
.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; }
.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; }
.@{fa-css-prefix}-registered:before { content: @fa-var-registered; }
.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; }
.@{fa-css-prefix}-gg:before { content: @fa-var-gg; }
.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; }
.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; }
.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; }
.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; }
.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; }
.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; }
.@{fa-css-prefix}-safari:before { content: @fa-var-safari; }
.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; }
.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; }
.@{fa-css-prefix}-opera:before { content: @fa-var-opera; }
.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; }
.@{fa-css-prefix}-tv:before,
.@{fa-css-prefix}-television:before { content: @fa-var-television; }
.@{fa-css-prefix}-contao:before { content: @fa-var-contao; }
.@{fa-css-prefix}-500px:before { content: @fa-var-500px; }
.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; }
.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; }
.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; }
.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; }
.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; }
.@{fa-css-prefix}-industry:before { content: @fa-var-industry; }
.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; }
.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; }
.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; }
.@{fa-css-prefix}-map:before { content: @fa-var-map; }
.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; }
.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; }
.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; }
.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; }
.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; }
.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; }
.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; }
.@{fa-css-prefix}-edge:before { content: @fa-var-edge; }
.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; }
.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; }
.@{fa-css-prefix}-modx:before { content: @fa-var-modx; }
.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; }
.@{fa-css-prefix}-usb:before { content: @fa-var-usb; }
.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; }
.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; }
.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; }
.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; }
.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; }
.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; }
.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; }
.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; }
.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; }
.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; }
.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; }
.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; }
.@{fa-css-prefix}-percent:before { content: @fa-var-percent; }
.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; }
.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; }
.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; }
.@{fa-css-prefix}-envira:before { content: @fa-var-envira; }
.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; }
.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; }
.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; }
.@{fa-css-prefix}-blind:before { content: @fa-var-blind; }
.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; }
.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; }
.@{fa-css-prefix}-braille:before { content: @fa-var-braille; }
.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; }
.@{fa-css-prefix}-asl-interpreting:before,
.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; }
.@{fa-css-prefix}-deafness:before,
.@{fa-css-prefix}-hard-of-hearing:before,
.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; }
.@{fa-css-prefix}-glide:before { content: @fa-var-glide; }
.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; }
.@{fa-css-prefix}-signing:before,
.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; }
.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; }
.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; }
.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; }
.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; }
.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; }
.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; }
.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; }
.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; }
.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; }
.@{fa-css-prefix}-google-plus-circle:before,
.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; }
.@{fa-css-prefix}-fa:before,
.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; }
.@{fa-css-prefix}-handshake-o:before { content: @fa-var-handshake-o; }
.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; }
.@{fa-css-prefix}-envelope-open-o:before { content: @fa-var-envelope-open-o; }
.@{fa-css-prefix}-linode:before { content: @fa-var-linode; }
.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; }
.@{fa-css-prefix}-address-book-o:before { content: @fa-var-address-book-o; }
.@{fa-css-prefix}-vcard:before,
.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; }
.@{fa-css-prefix}-vcard-o:before,
.@{fa-css-prefix}-address-card-o:before { content: @fa-var-address-card-o; }
.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; }
.@{fa-css-prefix}-user-circle-o:before { content: @fa-var-user-circle-o; }
.@{fa-css-prefix}-user-o:before { content: @fa-var-user-o; }
.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; }
.@{fa-css-prefix}-drivers-license:before,
.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; }
.@{fa-css-prefix}-drivers-license-o:before,
.@{fa-css-prefix}-id-card-o:before { content: @fa-var-id-card-o; }
.@{fa-css-prefix}-quora:before { content: @fa-var-quora; }
.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; }
.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; }
.@{fa-css-prefix}-thermometer-4:before,
.@{fa-css-prefix}-thermometer:before,
.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; }
.@{fa-css-prefix}-thermometer-3:before,
.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; }
.@{fa-css-prefix}-thermometer-2:before,
.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; }
.@{fa-css-prefix}-thermometer-1:before,
.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; }
.@{fa-css-prefix}-thermometer-0:before,
.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; }
.@{fa-css-prefix}-shower:before { content: @fa-var-shower; }
.@{fa-css-prefix}-bathtub:before,
.@{fa-css-prefix}-s15:before,
.@{fa-css-prefix}-bath:before { content: @fa-var-bath; }
.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; }
.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; }
.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; }
.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; }
.@{fa-css-prefix}-times-rectangle:before,
.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; }
.@{fa-css-prefix}-times-rectangle-o:before,
.@{fa-css-prefix}-window-close-o:before { content: @fa-var-window-close-o; }
.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; }
.@{fa-css-prefix}-grav:before { content: @fa-var-grav; }
.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; }
.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; }
.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; }
.@{fa-css-prefix}-eercast:before { content: @fa-var-eercast; }
.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; }
.@{fa-css-prefix}-snowflake-o:before { content: @fa-var-snowflake-o; }
.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; }
.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; }
.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; }

View File

@ -1,13 +0,0 @@
// Icon Sizes
// -------------------------
/* makes the font 33% larger relative to the icon container */
.@{fa-css-prefix}-lg {
font-size: (4em / 3);
line-height: (3em / 4);
vertical-align: -15%;
}
.@{fa-css-prefix}-2x { font-size: 2em; }
.@{fa-css-prefix}-3x { font-size: 3em; }
.@{fa-css-prefix}-4x { font-size: 4em; }
.@{fa-css-prefix}-5x { font-size: 5em; }

View File

@ -1,19 +0,0 @@
// List Icons
// -------------------------
.@{fa-css-prefix}-ul {
padding-left: 0;
margin-left: @fa-li-width;
list-style-type: none;
> li { position: relative; }
}
.@{fa-css-prefix}-li {
position: absolute;
left: -@fa-li-width;
width: @fa-li-width;
top: (2em / 14);
text-align: center;
&.@{fa-css-prefix}-lg {
left: (-@fa-li-width + (4em / 14));
}
}

View File

@ -1,60 +0,0 @@
// Mixins
// --------------------------
.fa-icon() {
display: inline-block;
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
font-size: inherit; // can't have font-size inherit on line above, so need to override
text-rendering: auto; // optimizelegibility throws things off #1094
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.fa-icon-rotate(@degrees, @rotation) {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
-webkit-transform: rotate(@degrees);
-ms-transform: rotate(@degrees);
transform: rotate(@degrees);
}
.fa-icon-flip(@horiz, @vert, @rotation) {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
-webkit-transform: scale(@horiz, @vert);
-ms-transform: scale(@horiz, @vert);
transform: scale(@horiz, @vert);
}
// Only display content to screen readers. A la Bootstrap 4.
//
// See: http://a11yproject.com/posts/how-to-hide-content/
.sr-only() {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
border: 0;
}
// Use in conjunction with .sr-only to only display content when it's focused.
//
// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
//
// Credit: HTML5 Boilerplate
.sr-only-focusable() {
&:active,
&:focus {
position: static;
width: auto;
height: auto;
margin: 0;
overflow: visible;
clip: auto;
}
}

View File

@ -1,15 +0,0 @@
/* FONT PATH
* -------------------------- */
@font-face {
font-family: 'FontAwesome';
src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
font-weight: normal;
font-style: normal;
}

View File

@ -1,20 +0,0 @@
// Rotated & Flipped Icons
// -------------------------
.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
// Hook for IE8-9
// -------------------------
:root .@{fa-css-prefix}-rotate-90,
:root .@{fa-css-prefix}-rotate-180,
:root .@{fa-css-prefix}-rotate-270,
:root .@{fa-css-prefix}-flip-horizontal,
:root .@{fa-css-prefix}-flip-vertical {
filter: none;
}

View File

@ -1,5 +0,0 @@
// Screen Readers
// -------------------------
.sr-only { .sr-only(); }
.sr-only-focusable { .sr-only-focusable(); }

View File

@ -1,20 +0,0 @@
// Stacked Icons
// -------------------------
.@{fa-css-prefix}-stack {
position: relative;
display: inline-block;
width: 2em;
height: 2em;
line-height: 2em;
vertical-align: middle;
}
.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
position: absolute;
left: 0;
width: 100%;
text-align: center;
}
.@{fa-css-prefix}-stack-1x { line-height: inherit; }
.@{fa-css-prefix}-stack-2x { font-size: 2em; }
.@{fa-css-prefix}-inverse { color: @fa-inverse; }

View File

@ -1,800 +0,0 @@
// Variables
// --------------------------
@fa-font-path: "../fonts";
@fa-font-size-base: 14px;
@fa-line-height-base: 1;
//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly
@fa-css-prefix: fa;
@fa-version: "4.7.0";
@fa-border-color: #eee;
@fa-inverse: #fff;
@fa-li-width: (30em / 14);
@fa-var-500px: "\f26e";
@fa-var-address-book: "\f2b9";
@fa-var-address-book-o: "\f2ba";
@fa-var-address-card: "\f2bb";
@fa-var-address-card-o: "\f2bc";
@fa-var-adjust: "\f042";
@fa-var-adn: "\f170";
@fa-var-align-center: "\f037";
@fa-var-align-justify: "\f039";
@fa-var-align-left: "\f036";
@fa-var-align-right: "\f038";
@fa-var-amazon: "\f270";
@fa-var-ambulance: "\f0f9";
@fa-var-american-sign-language-interpreting: "\f2a3";
@fa-var-anchor: "\f13d";
@fa-var-android: "\f17b";
@fa-var-angellist: "\f209";
@fa-var-angle-double-down: "\f103";
@fa-var-angle-double-left: "\f100";
@fa-var-angle-double-right: "\f101";
@fa-var-angle-double-up: "\f102";
@fa-var-angle-down: "\f107";
@fa-var-angle-left: "\f104";
@fa-var-angle-right: "\f105";
@fa-var-angle-up: "\f106";
@fa-var-apple: "\f179";
@fa-var-archive: "\f187";
@fa-var-area-chart: "\f1fe";
@fa-var-arrow-circle-down: "\f0ab";
@fa-var-arrow-circle-left: "\f0a8";
@fa-var-arrow-circle-o-down: "\f01a";
@fa-var-arrow-circle-o-left: "\f190";
@fa-var-arrow-circle-o-right: "\f18e";
@fa-var-arrow-circle-o-up: "\f01b";
@fa-var-arrow-circle-right: "\f0a9";
@fa-var-arrow-circle-up: "\f0aa";
@fa-var-arrow-down: "\f063";
@fa-var-arrow-left: "\f060";
@fa-var-arrow-right: "\f061";
@fa-var-arrow-up: "\f062";
@fa-var-arrows: "\f047";
@fa-var-arrows-alt: "\f0b2";
@fa-var-arrows-h: "\f07e";
@fa-var-arrows-v: "\f07d";
@fa-var-asl-interpreting: "\f2a3";
@fa-var-assistive-listening-systems: "\f2a2";
@fa-var-asterisk: "\f069";
@fa-var-at: "\f1fa";
@fa-var-audio-description: "\f29e";
@fa-var-automobile: "\f1b9";
@fa-var-backward: "\f04a";
@fa-var-balance-scale: "\f24e";
@fa-var-ban: "\f05e";
@fa-var-bandcamp: "\f2d5";
@fa-var-bank: "\f19c";
@fa-var-bar-chart: "\f080";
@fa-var-bar-chart-o: "\f080";
@fa-var-barcode: "\f02a";
@fa-var-bars: "\f0c9";
@fa-var-bath: "\f2cd";
@fa-var-bathtub: "\f2cd";
@fa-var-battery: "\f240";
@fa-var-battery-0: "\f244";
@fa-var-battery-1: "\f243";
@fa-var-battery-2: "\f242";
@fa-var-battery-3: "\f241";
@fa-var-battery-4: "\f240";
@fa-var-battery-empty: "\f244";
@fa-var-battery-full: "\f240";
@fa-var-battery-half: "\f242";
@fa-var-battery-quarter: "\f243";
@fa-var-battery-three-quarters: "\f241";
@fa-var-bed: "\f236";
@fa-var-beer: "\f0fc";
@fa-var-behance: "\f1b4";
@fa-var-behance-square: "\f1b5";
@fa-var-bell: "\f0f3";
@fa-var-bell-o: "\f0a2";
@fa-var-bell-slash: "\f1f6";
@fa-var-bell-slash-o: "\f1f7";
@fa-var-bicycle: "\f206";
@fa-var-binoculars: "\f1e5";
@fa-var-birthday-cake: "\f1fd";
@fa-var-bitbucket: "\f171";
@fa-var-bitbucket-square: "\f172";
@fa-var-bitcoin: "\f15a";
@fa-var-black-tie: "\f27e";
@fa-var-blind: "\f29d";
@fa-var-bluetooth: "\f293";
@fa-var-bluetooth-b: "\f294";
@fa-var-bold: "\f032";
@fa-var-bolt: "\f0e7";
@fa-var-bomb: "\f1e2";
@fa-var-book: "\f02d";
@fa-var-bookmark: "\f02e";
@fa-var-bookmark-o: "\f097";
@fa-var-braille: "\f2a1";
@fa-var-briefcase: "\f0b1";
@fa-var-btc: "\f15a";
@fa-var-bug: "\f188";
@fa-var-building: "\f1ad";
@fa-var-building-o: "\f0f7";
@fa-var-bullhorn: "\f0a1";
@fa-var-bullseye: "\f140";
@fa-var-bus: "\f207";
@fa-var-buysellads: "\f20d";
@fa-var-cab: "\f1ba";
@fa-var-calculator: "\f1ec";
@fa-var-calendar: "\f073";
@fa-var-calendar-check-o: "\f274";
@fa-var-calendar-minus-o: "\f272";
@fa-var-calendar-o: "\f133";
@fa-var-calendar-plus-o: "\f271";
@fa-var-calendar-times-o: "\f273";
@fa-var-camera: "\f030";
@fa-var-camera-retro: "\f083";
@fa-var-car: "\f1b9";
@fa-var-caret-down: "\f0d7";
@fa-var-caret-left: "\f0d9";
@fa-var-caret-right: "\f0da";
@fa-var-caret-square-o-down: "\f150";
@fa-var-caret-square-o-left: "\f191";
@fa-var-caret-square-o-right: "\f152";
@fa-var-caret-square-o-up: "\f151";
@fa-var-caret-up: "\f0d8";
@fa-var-cart-arrow-down: "\f218";
@fa-var-cart-plus: "\f217";
@fa-var-cc: "\f20a";
@fa-var-cc-amex: "\f1f3";
@fa-var-cc-diners-club: "\f24c";
@fa-var-cc-discover: "\f1f2";
@fa-var-cc-jcb: "\f24b";
@fa-var-cc-mastercard: "\f1f1";
@fa-var-cc-paypal: "\f1f4";
@fa-var-cc-stripe: "\f1f5";
@fa-var-cc-visa: "\f1f0";
@fa-var-certificate: "\f0a3";
@fa-var-chain: "\f0c1";
@fa-var-chain-broken: "\f127";
@fa-var-check: "\f00c";
@fa-var-check-circle: "\f058";
@fa-var-check-circle-o: "\f05d";
@fa-var-check-square: "\f14a";
@fa-var-check-square-o: "\f046";
@fa-var-chevron-circle-down: "\f13a";
@fa-var-chevron-circle-left: "\f137";
@fa-var-chevron-circle-right: "\f138";
@fa-var-chevron-circle-up: "\f139";
@fa-var-chevron-down: "\f078";
@fa-var-chevron-left: "\f053";
@fa-var-chevron-right: "\f054";
@fa-var-chevron-up: "\f077";
@fa-var-child: "\f1ae";
@fa-var-chrome: "\f268";
@fa-var-circle: "\f111";
@fa-var-circle-o: "\f10c";
@fa-var-circle-o-notch: "\f1ce";
@fa-var-circle-thin: "\f1db";
@fa-var-clipboard: "\f0ea";
@fa-var-clock-o: "\f017";
@fa-var-clone: "\f24d";
@fa-var-close: "\f00d";
@fa-var-cloud: "\f0c2";
@fa-var-cloud-download: "\f0ed";
@fa-var-cloud-upload: "\f0ee";
@fa-var-cny: "\f157";
@fa-var-code: "\f121";
@fa-var-code-fork: "\f126";
@fa-var-codepen: "\f1cb";
@fa-var-codiepie: "\f284";
@fa-var-coffee: "\f0f4";
@fa-var-cog: "\f013";
@fa-var-cogs: "\f085";
@fa-var-columns: "\f0db";
@fa-var-comment: "\f075";
@fa-var-comment-o: "\f0e5";
@fa-var-commenting: "\f27a";
@fa-var-commenting-o: "\f27b";
@fa-var-comments: "\f086";
@fa-var-comments-o: "\f0e6";
@fa-var-compass: "\f14e";
@fa-var-compress: "\f066";
@fa-var-connectdevelop: "\f20e";
@fa-var-contao: "\f26d";
@fa-var-copy: "\f0c5";
@fa-var-copyright: "\f1f9";
@fa-var-creative-commons: "\f25e";
@fa-var-credit-card: "\f09d";
@fa-var-credit-card-alt: "\f283";
@fa-var-crop: "\f125";
@fa-var-crosshairs: "\f05b";
@fa-var-css3: "\f13c";
@fa-var-cube: "\f1b2";
@fa-var-cubes: "\f1b3";
@fa-var-cut: "\f0c4";
@fa-var-cutlery: "\f0f5";
@fa-var-dashboard: "\f0e4";
@fa-var-dashcube: "\f210";
@fa-var-database: "\f1c0";
@fa-var-deaf: "\f2a4";
@fa-var-deafness: "\f2a4";
@fa-var-dedent: "\f03b";
@fa-var-delicious: "\f1a5";
@fa-var-desktop: "\f108";
@fa-var-deviantart: "\f1bd";
@fa-var-diamond: "\f219";
@fa-var-digg: "\f1a6";
@fa-var-dollar: "\f155";
@fa-var-dot-circle-o: "\f192";
@fa-var-download: "\f019";
@fa-var-dribbble: "\f17d";
@fa-var-drivers-license: "\f2c2";
@fa-var-drivers-license-o: "\f2c3";
@fa-var-dropbox: "\f16b";
@fa-var-drupal: "\f1a9";
@fa-var-edge: "\f282";
@fa-var-edit: "\f044";
@fa-var-eercast: "\f2da";
@fa-var-eject: "\f052";
@fa-var-ellipsis-h: "\f141";
@fa-var-ellipsis-v: "\f142";
@fa-var-empire: "\f1d1";
@fa-var-envelope: "\f0e0";
@fa-var-envelope-o: "\f003";
@fa-var-envelope-open: "\f2b6";
@fa-var-envelope-open-o: "\f2b7";
@fa-var-envelope-square: "\f199";
@fa-var-envira: "\f299";
@fa-var-eraser: "\f12d";
@fa-var-etsy: "\f2d7";
@fa-var-eur: "\f153";
@fa-var-euro: "\f153";
@fa-var-exchange: "\f0ec";
@fa-var-exclamation: "\f12a";
@fa-var-exclamation-circle: "\f06a";
@fa-var-exclamation-triangle: "\f071";
@fa-var-expand: "\f065";
@fa-var-expeditedssl: "\f23e";
@fa-var-external-link: "\f08e";
@fa-var-external-link-square: "\f14c";
@fa-var-eye: "\f06e";
@fa-var-eye-slash: "\f070";
@fa-var-eyedropper: "\f1fb";
@fa-var-fa: "\f2b4";
@fa-var-facebook: "\f09a";
@fa-var-facebook-f: "\f09a";
@fa-var-facebook-official: "\f230";
@fa-var-facebook-square: "\f082";
@fa-var-fast-backward: "\f049";
@fa-var-fast-forward: "\f050";
@fa-var-fax: "\f1ac";
@fa-var-feed: "\f09e";
@fa-var-female: "\f182";
@fa-var-fighter-jet: "\f0fb";
@fa-var-file: "\f15b";
@fa-var-file-archive-o: "\f1c6";
@fa-var-file-audio-o: "\f1c7";
@fa-var-file-code-o: "\f1c9";
@fa-var-file-excel-o: "\f1c3";
@fa-var-file-image-o: "\f1c5";
@fa-var-file-movie-o: "\f1c8";
@fa-var-file-o: "\f016";
@fa-var-file-pdf-o: "\f1c1";
@fa-var-file-photo-o: "\f1c5";
@fa-var-file-picture-o: "\f1c5";
@fa-var-file-powerpoint-o: "\f1c4";
@fa-var-file-sound-o: "\f1c7";
@fa-var-file-text: "\f15c";
@fa-var-file-text-o: "\f0f6";
@fa-var-file-video-o: "\f1c8";
@fa-var-file-word-o: "\f1c2";
@fa-var-file-zip-o: "\f1c6";
@fa-var-files-o: "\f0c5";
@fa-var-film: "\f008";
@fa-var-filter: "\f0b0";
@fa-var-fire: "\f06d";
@fa-var-fire-extinguisher: "\f134";
@fa-var-firefox: "\f269";
@fa-var-first-order: "\f2b0";
@fa-var-flag: "\f024";
@fa-var-flag-checkered: "\f11e";
@fa-var-flag-o: "\f11d";
@fa-var-flash: "\f0e7";
@fa-var-flask: "\f0c3";
@fa-var-flickr: "\f16e";
@fa-var-floppy-o: "\f0c7";
@fa-var-folder: "\f07b";
@fa-var-folder-o: "\f114";
@fa-var-folder-open: "\f07c";
@fa-var-folder-open-o: "\f115";
@fa-var-font: "\f031";
@fa-var-font-awesome: "\f2b4";
@fa-var-fonticons: "\f280";
@fa-var-fort-awesome: "\f286";
@fa-var-forumbee: "\f211";
@fa-var-forward: "\f04e";
@fa-var-foursquare: "\f180";
@fa-var-free-code-camp: "\f2c5";
@fa-var-frown-o: "\f119";
@fa-var-futbol-o: "\f1e3";
@fa-var-gamepad: "\f11b";
@fa-var-gavel: "\f0e3";
@fa-var-gbp: "\f154";
@fa-var-ge: "\f1d1";
@fa-var-gear: "\f013";
@fa-var-gears: "\f085";
@fa-var-genderless: "\f22d";
@fa-var-get-pocket: "\f265";
@fa-var-gg: "\f260";
@fa-var-gg-circle: "\f261";
@fa-var-gift: "\f06b";
@fa-var-git: "\f1d3";
@fa-var-git-square: "\f1d2";
@fa-var-github: "\f09b";
@fa-var-github-alt: "\f113";
@fa-var-github-square: "\f092";
@fa-var-gitlab: "\f296";
@fa-var-gittip: "\f184";
@fa-var-glass: "\f000";
@fa-var-glide: "\f2a5";
@fa-var-glide-g: "\f2a6";
@fa-var-globe: "\f0ac";
@fa-var-google: "\f1a0";
@fa-var-google-plus: "\f0d5";
@fa-var-google-plus-circle: "\f2b3";
@fa-var-google-plus-official: "\f2b3";
@fa-var-google-plus-square: "\f0d4";
@fa-var-google-wallet: "\f1ee";
@fa-var-graduation-cap: "\f19d";
@fa-var-gratipay: "\f184";
@fa-var-grav: "\f2d6";
@fa-var-group: "\f0c0";
@fa-var-h-square: "\f0fd";
@fa-var-hacker-news: "\f1d4";
@fa-var-hand-grab-o: "\f255";
@fa-var-hand-lizard-o: "\f258";
@fa-var-hand-o-down: "\f0a7";
@fa-var-hand-o-left: "\f0a5";
@fa-var-hand-o-right: "\f0a4";
@fa-var-hand-o-up: "\f0a6";
@fa-var-hand-paper-o: "\f256";
@fa-var-hand-peace-o: "\f25b";
@fa-var-hand-pointer-o: "\f25a";
@fa-var-hand-rock-o: "\f255";
@fa-var-hand-scissors-o: "\f257";
@fa-var-hand-spock-o: "\f259";
@fa-var-hand-stop-o: "\f256";
@fa-var-handshake-o: "\f2b5";
@fa-var-hard-of-hearing: "\f2a4";
@fa-var-hashtag: "\f292";
@fa-var-hdd-o: "\f0a0";
@fa-var-header: "\f1dc";
@fa-var-headphones: "\f025";
@fa-var-heart: "\f004";
@fa-var-heart-o: "\f08a";
@fa-var-heartbeat: "\f21e";
@fa-var-history: "\f1da";
@fa-var-home: "\f015";
@fa-var-hospital-o: "\f0f8";
@fa-var-hotel: "\f236";
@fa-var-hourglass: "\f254";
@fa-var-hourglass-1: "\f251";
@fa-var-hourglass-2: "\f252";
@fa-var-hourglass-3: "\f253";
@fa-var-hourglass-end: "\f253";
@fa-var-hourglass-half: "\f252";
@fa-var-hourglass-o: "\f250";
@fa-var-hourglass-start: "\f251";
@fa-var-houzz: "\f27c";
@fa-var-html5: "\f13b";
@fa-var-i-cursor: "\f246";
@fa-var-id-badge: "\f2c1";
@fa-var-id-card: "\f2c2";
@fa-var-id-card-o: "\f2c3";
@fa-var-ils: "\f20b";
@fa-var-image: "\f03e";
@fa-var-imdb: "\f2d8";
@fa-var-inbox: "\f01c";
@fa-var-indent: "\f03c";
@fa-var-industry: "\f275";
@fa-var-info: "\f129";
@fa-var-info-circle: "\f05a";
@fa-var-inr: "\f156";
@fa-var-instagram: "\f16d";
@fa-var-institution: "\f19c";
@fa-var-internet-explorer: "\f26b";
@fa-var-intersex: "\f224";
@fa-var-ioxhost: "\f208";
@fa-var-italic: "\f033";
@fa-var-joomla: "\f1aa";
@fa-var-jpy: "\f157";
@fa-var-jsfiddle: "\f1cc";
@fa-var-key: "\f084";
@fa-var-keyboard-o: "\f11c";
@fa-var-krw: "\f159";
@fa-var-language: "\f1ab";
@fa-var-laptop: "\f109";
@fa-var-lastfm: "\f202";
@fa-var-lastfm-square: "\f203";
@fa-var-leaf: "\f06c";
@fa-var-leanpub: "\f212";
@fa-var-legal: "\f0e3";
@fa-var-lemon-o: "\f094";
@fa-var-level-down: "\f149";
@fa-var-level-up: "\f148";
@fa-var-life-bouy: "\f1cd";
@fa-var-life-buoy: "\f1cd";
@fa-var-life-ring: "\f1cd";
@fa-var-life-saver: "\f1cd";
@fa-var-lightbulb-o: "\f0eb";
@fa-var-line-chart: "\f201";
@fa-var-link: "\f0c1";
@fa-var-linkedin: "\f0e1";
@fa-var-linkedin-square: "\f08c";
@fa-var-linode: "\f2b8";
@fa-var-linux: "\f17c";
@fa-var-list: "\f03a";
@fa-var-list-alt: "\f022";
@fa-var-list-ol: "\f0cb";
@fa-var-list-ul: "\f0ca";
@fa-var-location-arrow: "\f124";
@fa-var-lock: "\f023";
@fa-var-long-arrow-down: "\f175";
@fa-var-long-arrow-left: "\f177";
@fa-var-long-arrow-right: "\f178";
@fa-var-long-arrow-up: "\f176";
@fa-var-low-vision: "\f2a8";
@fa-var-magic: "\f0d0";
@fa-var-magnet: "\f076";
@fa-var-mail-forward: "\f064";
@fa-var-mail-reply: "\f112";
@fa-var-mail-reply-all: "\f122";
@fa-var-male: "\f183";
@fa-var-map: "\f279";
@fa-var-map-marker: "\f041";
@fa-var-map-o: "\f278";
@fa-var-map-pin: "\f276";
@fa-var-map-signs: "\f277";
@fa-var-mars: "\f222";
@fa-var-mars-double: "\f227";
@fa-var-mars-stroke: "\f229";
@fa-var-mars-stroke-h: "\f22b";
@fa-var-mars-stroke-v: "\f22a";
@fa-var-maxcdn: "\f136";
@fa-var-meanpath: "\f20c";
@fa-var-medium: "\f23a";
@fa-var-medkit: "\f0fa";
@fa-var-meetup: "\f2e0";
@fa-var-meh-o: "\f11a";
@fa-var-mercury: "\f223";
@fa-var-microchip: "\f2db";
@fa-var-microphone: "\f130";
@fa-var-microphone-slash: "\f131";
@fa-var-minus: "\f068";
@fa-var-minus-circle: "\f056";
@fa-var-minus-square: "\f146";
@fa-var-minus-square-o: "\f147";
@fa-var-mixcloud: "\f289";
@fa-var-mobile: "\f10b";
@fa-var-mobile-phone: "\f10b";
@fa-var-modx: "\f285";
@fa-var-money: "\f0d6";
@fa-var-moon-o: "\f186";
@fa-var-mortar-board: "\f19d";
@fa-var-motorcycle: "\f21c";
@fa-var-mouse-pointer: "\f245";
@fa-var-music: "\f001";
@fa-var-navicon: "\f0c9";
@fa-var-neuter: "\f22c";
@fa-var-newspaper-o: "\f1ea";
@fa-var-object-group: "\f247";
@fa-var-object-ungroup: "\f248";
@fa-var-odnoklassniki: "\f263";
@fa-var-odnoklassniki-square: "\f264";
@fa-var-opencart: "\f23d";
@fa-var-openid: "\f19b";
@fa-var-opera: "\f26a";
@fa-var-optin-monster: "\f23c";
@fa-var-outdent: "\f03b";
@fa-var-pagelines: "\f18c";
@fa-var-paint-brush: "\f1fc";
@fa-var-paper-plane: "\f1d8";
@fa-var-paper-plane-o: "\f1d9";
@fa-var-paperclip: "\f0c6";
@fa-var-paragraph: "\f1dd";
@fa-var-paste: "\f0ea";
@fa-var-pause: "\f04c";
@fa-var-pause-circle: "\f28b";
@fa-var-pause-circle-o: "\f28c";
@fa-var-paw: "\f1b0";
@fa-var-paypal: "\f1ed";
@fa-var-pencil: "\f040";
@fa-var-pencil-square: "\f14b";
@fa-var-pencil-square-o: "\f044";
@fa-var-percent: "\f295";
@fa-var-phone: "\f095";
@fa-var-phone-square: "\f098";
@fa-var-photo: "\f03e";
@fa-var-picture-o: "\f03e";
@fa-var-pie-chart: "\f200";
@fa-var-pied-piper: "\f2ae";
@fa-var-pied-piper-alt: "\f1a8";
@fa-var-pied-piper-pp: "\f1a7";
@fa-var-pinterest: "\f0d2";
@fa-var-pinterest-p: "\f231";
@fa-var-pinterest-square: "\f0d3";
@fa-var-plane: "\f072";
@fa-var-play: "\f04b";
@fa-var-play-circle: "\f144";
@fa-var-play-circle-o: "\f01d";
@fa-var-plug: "\f1e6";
@fa-var-plus: "\f067";
@fa-var-plus-circle: "\f055";
@fa-var-plus-square: "\f0fe";
@fa-var-plus-square-o: "\f196";
@fa-var-podcast: "\f2ce";
@fa-var-power-off: "\f011";
@fa-var-print: "\f02f";
@fa-var-product-hunt: "\f288";
@fa-var-puzzle-piece: "\f12e";
@fa-var-qq: "\f1d6";
@fa-var-qrcode: "\f029";
@fa-var-question: "\f128";
@fa-var-question-circle: "\f059";
@fa-var-question-circle-o: "\f29c";
@fa-var-quora: "\f2c4";
@fa-var-quote-left: "\f10d";
@fa-var-quote-right: "\f10e";
@fa-var-ra: "\f1d0";
@fa-var-random: "\f074";
@fa-var-ravelry: "\f2d9";
@fa-var-rebel: "\f1d0";
@fa-var-recycle: "\f1b8";
@fa-var-reddit: "\f1a1";
@fa-var-reddit-alien: "\f281";
@fa-var-reddit-square: "\f1a2";
@fa-var-refresh: "\f021";
@fa-var-registered: "\f25d";
@fa-var-remove: "\f00d";
@fa-var-renren: "\f18b";
@fa-var-reorder: "\f0c9";
@fa-var-repeat: "\f01e";
@fa-var-reply: "\f112";
@fa-var-reply-all: "\f122";
@fa-var-resistance: "\f1d0";
@fa-var-retweet: "\f079";
@fa-var-rmb: "\f157";
@fa-var-road: "\f018";
@fa-var-rocket: "\f135";
@fa-var-rotate-left: "\f0e2";
@fa-var-rotate-right: "\f01e";
@fa-var-rouble: "\f158";
@fa-var-rss: "\f09e";
@fa-var-rss-square: "\f143";
@fa-var-rub: "\f158";
@fa-var-ruble: "\f158";
@fa-var-rupee: "\f156";
@fa-var-s15: "\f2cd";
@fa-var-safari: "\f267";
@fa-var-save: "\f0c7";
@fa-var-scissors: "\f0c4";
@fa-var-scribd: "\f28a";
@fa-var-search: "\f002";
@fa-var-search-minus: "\f010";
@fa-var-search-plus: "\f00e";
@fa-var-sellsy: "\f213";
@fa-var-send: "\f1d8";
@fa-var-send-o: "\f1d9";
@fa-var-server: "\f233";
@fa-var-share: "\f064";
@fa-var-share-alt: "\f1e0";
@fa-var-share-alt-square: "\f1e1";
@fa-var-share-square: "\f14d";
@fa-var-share-square-o: "\f045";
@fa-var-shekel: "\f20b";
@fa-var-sheqel: "\f20b";
@fa-var-shield: "\f132";
@fa-var-ship: "\f21a";
@fa-var-shirtsinbulk: "\f214";
@fa-var-shopping-bag: "\f290";
@fa-var-shopping-basket: "\f291";
@fa-var-shopping-cart: "\f07a";
@fa-var-shower: "\f2cc";
@fa-var-sign-in: "\f090";
@fa-var-sign-language: "\f2a7";
@fa-var-sign-out: "\f08b";
@fa-var-signal: "\f012";
@fa-var-signing: "\f2a7";
@fa-var-simplybuilt: "\f215";
@fa-var-sitemap: "\f0e8";
@fa-var-skyatlas: "\f216";
@fa-var-skype: "\f17e";
@fa-var-slack: "\f198";
@fa-var-sliders: "\f1de";
@fa-var-slideshare: "\f1e7";
@fa-var-smile-o: "\f118";
@fa-var-snapchat: "\f2ab";
@fa-var-snapchat-ghost: "\f2ac";
@fa-var-snapchat-square: "\f2ad";
@fa-var-snowflake-o: "\f2dc";
@fa-var-soccer-ball-o: "\f1e3";
@fa-var-sort: "\f0dc";
@fa-var-sort-alpha-asc: "\f15d";
@fa-var-sort-alpha-desc: "\f15e";
@fa-var-sort-amount-asc: "\f160";
@fa-var-sort-amount-desc: "\f161";
@fa-var-sort-asc: "\f0de";
@fa-var-sort-desc: "\f0dd";
@fa-var-sort-down: "\f0dd";
@fa-var-sort-numeric-asc: "\f162";
@fa-var-sort-numeric-desc: "\f163";
@fa-var-sort-up: "\f0de";
@fa-var-soundcloud: "\f1be";
@fa-var-space-shuttle: "\f197";
@fa-var-spinner: "\f110";
@fa-var-spoon: "\f1b1";
@fa-var-spotify: "\f1bc";
@fa-var-square: "\f0c8";
@fa-var-square-o: "\f096";
@fa-var-stack-exchange: "\f18d";
@fa-var-stack-overflow: "\f16c";
@fa-var-star: "\f005";
@fa-var-star-half: "\f089";
@fa-var-star-half-empty: "\f123";
@fa-var-star-half-full: "\f123";
@fa-var-star-half-o: "\f123";
@fa-var-star-o: "\f006";
@fa-var-steam: "\f1b6";
@fa-var-steam-square: "\f1b7";
@fa-var-step-backward: "\f048";
@fa-var-step-forward: "\f051";
@fa-var-stethoscope: "\f0f1";
@fa-var-sticky-note: "\f249";
@fa-var-sticky-note-o: "\f24a";
@fa-var-stop: "\f04d";
@fa-var-stop-circle: "\f28d";
@fa-var-stop-circle-o: "\f28e";
@fa-var-street-view: "\f21d";
@fa-var-strikethrough: "\f0cc";
@fa-var-stumbleupon: "\f1a4";
@fa-var-stumbleupon-circle: "\f1a3";
@fa-var-subscript: "\f12c";
@fa-var-subway: "\f239";
@fa-var-suitcase: "\f0f2";
@fa-var-sun-o: "\f185";
@fa-var-superpowers: "\f2dd";
@fa-var-superscript: "\f12b";
@fa-var-support: "\f1cd";
@fa-var-table: "\f0ce";
@fa-var-tablet: "\f10a";
@fa-var-tachometer: "\f0e4";
@fa-var-tag: "\f02b";
@fa-var-tags: "\f02c";
@fa-var-tasks: "\f0ae";
@fa-var-taxi: "\f1ba";
@fa-var-telegram: "\f2c6";
@fa-var-television: "\f26c";
@fa-var-tencent-weibo: "\f1d5";
@fa-var-terminal: "\f120";
@fa-var-text-height: "\f034";
@fa-var-text-width: "\f035";
@fa-var-th: "\f00a";
@fa-var-th-large: "\f009";
@fa-var-th-list: "\f00b";
@fa-var-themeisle: "\f2b2";
@fa-var-thermometer: "\f2c7";
@fa-var-thermometer-0: "\f2cb";
@fa-var-thermometer-1: "\f2ca";
@fa-var-thermometer-2: "\f2c9";
@fa-var-thermometer-3: "\f2c8";
@fa-var-thermometer-4: "\f2c7";
@fa-var-thermometer-empty: "\f2cb";
@fa-var-thermometer-full: "\f2c7";
@fa-var-thermometer-half: "\f2c9";
@fa-var-thermometer-quarter: "\f2ca";
@fa-var-thermometer-three-quarters: "\f2c8";
@fa-var-thumb-tack: "\f08d";
@fa-var-thumbs-down: "\f165";
@fa-var-thumbs-o-down: "\f088";
@fa-var-thumbs-o-up: "\f087";
@fa-var-thumbs-up: "\f164";
@fa-var-ticket: "\f145";
@fa-var-times: "\f00d";
@fa-var-times-circle: "\f057";
@fa-var-times-circle-o: "\f05c";
@fa-var-times-rectangle: "\f2d3";
@fa-var-times-rectangle-o: "\f2d4";
@fa-var-tint: "\f043";
@fa-var-toggle-down: "\f150";
@fa-var-toggle-left: "\f191";
@fa-var-toggle-off: "\f204";
@fa-var-toggle-on: "\f205";
@fa-var-toggle-right: "\f152";
@fa-var-toggle-up: "\f151";
@fa-var-trademark: "\f25c";
@fa-var-train: "\f238";
@fa-var-transgender: "\f224";
@fa-var-transgender-alt: "\f225";
@fa-var-trash: "\f1f8";
@fa-var-trash-o: "\f014";
@fa-var-tree: "\f1bb";
@fa-var-trello: "\f181";
@fa-var-tripadvisor: "\f262";
@fa-var-trophy: "\f091";
@fa-var-truck: "\f0d1";
@fa-var-try: "\f195";
@fa-var-tty: "\f1e4";
@fa-var-tumblr: "\f173";
@fa-var-tumblr-square: "\f174";
@fa-var-turkish-lira: "\f195";
@fa-var-tv: "\f26c";
@fa-var-twitch: "\f1e8";
@fa-var-twitter: "\f099";
@fa-var-twitter-square: "\f081";
@fa-var-umbrella: "\f0e9";
@fa-var-underline: "\f0cd";
@fa-var-undo: "\f0e2";
@fa-var-universal-access: "\f29a";
@fa-var-university: "\f19c";
@fa-var-unlink: "\f127";
@fa-var-unlock: "\f09c";
@fa-var-unlock-alt: "\f13e";
@fa-var-unsorted: "\f0dc";
@fa-var-upload: "\f093";
@fa-var-usb: "\f287";
@fa-var-usd: "\f155";
@fa-var-user: "\f007";
@fa-var-user-circle: "\f2bd";
@fa-var-user-circle-o: "\f2be";
@fa-var-user-md: "\f0f0";
@fa-var-user-o: "\f2c0";
@fa-var-user-plus: "\f234";
@fa-var-user-secret: "\f21b";
@fa-var-user-times: "\f235";
@fa-var-users: "\f0c0";
@fa-var-vcard: "\f2bb";
@fa-var-vcard-o: "\f2bc";
@fa-var-venus: "\f221";
@fa-var-venus-double: "\f226";
@fa-var-venus-mars: "\f228";
@fa-var-viacoin: "\f237";
@fa-var-viadeo: "\f2a9";
@fa-var-viadeo-square: "\f2aa";
@fa-var-video-camera: "\f03d";
@fa-var-vimeo: "\f27d";
@fa-var-vimeo-square: "\f194";
@fa-var-vine: "\f1ca";
@fa-var-vk: "\f189";
@fa-var-volume-control-phone: "\f2a0";
@fa-var-volume-down: "\f027";
@fa-var-volume-off: "\f026";
@fa-var-volume-up: "\f028";
@fa-var-warning: "\f071";
@fa-var-wechat: "\f1d7";
@fa-var-weibo: "\f18a";
@fa-var-weixin: "\f1d7";
@fa-var-whatsapp: "\f232";
@fa-var-wheelchair: "\f193";
@fa-var-wheelchair-alt: "\f29b";
@fa-var-wifi: "\f1eb";
@fa-var-wikipedia-w: "\f266";
@fa-var-window-close: "\f2d3";
@fa-var-window-close-o: "\f2d4";
@fa-var-window-maximize: "\f2d0";
@fa-var-window-minimize: "\f2d1";
@fa-var-window-restore: "\f2d2";
@fa-var-windows: "\f17a";
@fa-var-won: "\f159";
@fa-var-wordpress: "\f19a";
@fa-var-wpbeginner: "\f297";
@fa-var-wpexplorer: "\f2de";
@fa-var-wpforms: "\f298";
@fa-var-wrench: "\f0ad";
@fa-var-xing: "\f168";
@fa-var-xing-square: "\f169";
@fa-var-y-combinator: "\f23b";
@fa-var-y-combinator-square: "\f1d4";
@fa-var-yahoo: "\f19e";
@fa-var-yc: "\f23b";
@fa-var-yc-square: "\f1d4";
@fa-var-yelp: "\f1e9";
@fa-var-yen: "\f157";
@fa-var-yoast: "\f2b1";
@fa-var-youtube: "\f167";
@fa-var-youtube-play: "\f16a";
@fa-var-youtube-square: "\f166";

View File

@ -1,34 +0,0 @@
// Spinning Icons
// --------------------------
.#{$fa-css-prefix}-spin {
-webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear;
}
.#{$fa-css-prefix}-pulse {
-webkit-animation: fa-spin 1s infinite steps(8);
animation: fa-spin 1s infinite steps(8);
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}

View File

@ -1,25 +0,0 @@
// Bordered & Pulled
// -------------------------
.#{$fa-css-prefix}-border {
padding: .2em .25em .15em;
border: solid .08em $fa-border-color;
border-radius: .1em;
}
.#{$fa-css-prefix}-pull-left { float: left; }
.#{$fa-css-prefix}-pull-right { float: right; }
.#{$fa-css-prefix} {
&.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
&.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
}
/* Deprecated as of 4.4.0 */
.pull-right { float: right; }
.pull-left { float: left; }
.#{$fa-css-prefix} {
&.pull-left { margin-right: .3em; }
&.pull-right { margin-left: .3em; }
}

View File

@ -1,12 +0,0 @@
// Base Class Definition
// -------------------------
.#{$fa-css-prefix} {
display: inline-block;
font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
font-size: inherit; // can't have font-size inherit on line above, so need to override
text-rendering: auto; // optimizelegibility throws things off #1094
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@ -1,6 +0,0 @@
// Fixed Width Icons
// -------------------------
.#{$fa-css-prefix}-fw {
width: (18em / 14);
text-align: center;
}

View File

@ -1,789 +0,0 @@
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
readers do not read off random characters that represent icons */
.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; }
.#{$fa-css-prefix}-music:before { content: $fa-var-music; }
.#{$fa-css-prefix}-search:before { content: $fa-var-search; }
.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; }
.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; }
.#{$fa-css-prefix}-star:before { content: $fa-var-star; }
.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; }
.#{$fa-css-prefix}-user:before { content: $fa-var-user; }
.#{$fa-css-prefix}-film:before { content: $fa-var-film; }
.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; }
.#{$fa-css-prefix}-th:before { content: $fa-var-th; }
.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; }
.#{$fa-css-prefix}-check:before { content: $fa-var-check; }
.#{$fa-css-prefix}-remove:before,
.#{$fa-css-prefix}-close:before,
.#{$fa-css-prefix}-times:before { content: $fa-var-times; }
.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; }
.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; }
.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; }
.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; }
.#{$fa-css-prefix}-gear:before,
.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; }
.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; }
.#{$fa-css-prefix}-home:before { content: $fa-var-home; }
.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; }
.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; }
.#{$fa-css-prefix}-road:before { content: $fa-var-road; }
.#{$fa-css-prefix}-download:before { content: $fa-var-download; }
.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; }
.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; }
.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; }
.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; }
.#{$fa-css-prefix}-rotate-right:before,
.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; }
.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; }
.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; }
.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; }
.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; }
.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; }
.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; }
.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; }
.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; }
.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; }
.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; }
.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; }
.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; }
.#{$fa-css-prefix}-book:before { content: $fa-var-book; }
.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; }
.#{$fa-css-prefix}-print:before { content: $fa-var-print; }
.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; }
.#{$fa-css-prefix}-font:before { content: $fa-var-font; }
.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; }
.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; }
.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; }
.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; }
.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; }
.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; }
.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; }
.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; }
.#{$fa-css-prefix}-list:before { content: $fa-var-list; }
.#{$fa-css-prefix}-dedent:before,
.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; }
.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; }
.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; }
.#{$fa-css-prefix}-photo:before,
.#{$fa-css-prefix}-image:before,
.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; }
.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; }
.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; }
.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; }
.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; }
.#{$fa-css-prefix}-edit:before,
.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; }
.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; }
.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; }
.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; }
.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; }
.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; }
.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; }
.#{$fa-css-prefix}-play:before { content: $fa-var-play; }
.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; }
.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; }
.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; }
.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; }
.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; }
.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; }
.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; }
.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; }
.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; }
.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; }
.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; }
.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; }
.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; }
.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; }
.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; }
.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; }
.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; }
.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; }
.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; }
.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; }
.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; }
.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; }
.#{$fa-css-prefix}-mail-forward:before,
.#{$fa-css-prefix}-share:before { content: $fa-var-share; }
.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; }
.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; }
.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; }
.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; }
.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; }
.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; }
.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; }
.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; }
.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; }
.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; }
.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; }
.#{$fa-css-prefix}-warning:before,
.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; }
.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; }
.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; }
.#{$fa-css-prefix}-random:before { content: $fa-var-random; }
.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; }
.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; }
.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; }
.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; }
.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; }
.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; }
.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; }
.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; }
.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; }
.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; }
.#{$fa-css-prefix}-bar-chart-o:before,
.#{$fa-css-prefix}-bar-chart:before { content: $fa-var-bar-chart; }
.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; }
.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; }
.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; }
.#{$fa-css-prefix}-key:before { content: $fa-var-key; }
.#{$fa-css-prefix}-gears:before,
.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; }
.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; }
.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; }
.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; }
.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; }
.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; }
.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; }
.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; }
.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; }
.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; }
.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; }
.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; }
.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; }
.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; }
.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; }
.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; }
.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; }
.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; }
.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; }
.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; }
.#{$fa-css-prefix}-facebook-f:before,
.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; }
.#{$fa-css-prefix}-github:before { content: $fa-var-github; }
.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; }
.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; }
.#{$fa-css-prefix}-feed:before,
.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; }
.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; }
.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; }
.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; }
.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; }
.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; }
.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; }
.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; }
.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; }
.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; }
.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; }
.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; }
.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; }
.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; }
.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; }
.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; }
.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; }
.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; }
.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; }
.#{$fa-css-prefix}-group:before,
.#{$fa-css-prefix}-users:before { content: $fa-var-users; }
.#{$fa-css-prefix}-chain:before,
.#{$fa-css-prefix}-link:before { content: $fa-var-link; }
.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; }
.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; }
.#{$fa-css-prefix}-cut:before,
.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; }
.#{$fa-css-prefix}-copy:before,
.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; }
.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; }
.#{$fa-css-prefix}-save:before,
.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; }
.#{$fa-css-prefix}-square:before { content: $fa-var-square; }
.#{$fa-css-prefix}-navicon:before,
.#{$fa-css-prefix}-reorder:before,
.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; }
.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; }
.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; }
.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; }
.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; }
.#{$fa-css-prefix}-table:before { content: $fa-var-table; }
.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; }
.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; }
.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; }
.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; }
.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; }
.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; }
.#{$fa-css-prefix}-money:before { content: $fa-var-money; }
.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; }
.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; }
.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; }
.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; }
.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; }
.#{$fa-css-prefix}-unsorted:before,
.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; }
.#{$fa-css-prefix}-sort-down:before,
.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; }
.#{$fa-css-prefix}-sort-up:before,
.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; }
.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; }
.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; }
.#{$fa-css-prefix}-rotate-left:before,
.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; }
.#{$fa-css-prefix}-legal:before,
.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; }
.#{$fa-css-prefix}-dashboard:before,
.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; }
.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; }
.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; }
.#{$fa-css-prefix}-flash:before,
.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; }
.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; }
.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; }
.#{$fa-css-prefix}-paste:before,
.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; }
.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; }
.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; }
.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; }
.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; }
.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; }
.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; }
.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; }
.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; }
.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; }
.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; }
.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; }
.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; }
.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; }
.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; }
.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; }
.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; }
.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; }
.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; }
.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; }
.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; }
.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; }
.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; }
.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; }
.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; }
.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; }
.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; }
.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; }
.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; }
.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; }
.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; }
.#{$fa-css-prefix}-mobile-phone:before,
.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; }
.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; }
.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; }
.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; }
.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; }
.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; }
.#{$fa-css-prefix}-mail-reply:before,
.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; }
.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; }
.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; }
.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; }
.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; }
.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; }
.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; }
.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; }
.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; }
.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; }
.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; }
.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; }
.#{$fa-css-prefix}-code:before { content: $fa-var-code; }
.#{$fa-css-prefix}-mail-reply-all:before,
.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; }
.#{$fa-css-prefix}-star-half-empty:before,
.#{$fa-css-prefix}-star-half-full:before,
.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; }
.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; }
.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; }
.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; }
.#{$fa-css-prefix}-unlink:before,
.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; }
.#{$fa-css-prefix}-question:before { content: $fa-var-question; }
.#{$fa-css-prefix}-info:before { content: $fa-var-info; }
.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; }
.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; }
.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; }
.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; }
.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; }
.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; }
.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; }
.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; }
.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; }
.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; }
.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; }
.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; }
.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; }
.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; }
.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; }
.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; }
.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; }
.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; }
.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; }
.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; }
.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; }
.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; }
.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; }
.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; }
.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; }
.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; }
.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; }
.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; }
.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; }
.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; }
.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; }
.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; }
.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; }
.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; }
.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; }
.#{$fa-css-prefix}-toggle-down:before,
.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; }
.#{$fa-css-prefix}-toggle-up:before,
.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; }
.#{$fa-css-prefix}-toggle-right:before,
.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; }
.#{$fa-css-prefix}-euro:before,
.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; }
.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; }
.#{$fa-css-prefix}-dollar:before,
.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; }
.#{$fa-css-prefix}-rupee:before,
.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; }
.#{$fa-css-prefix}-cny:before,
.#{$fa-css-prefix}-rmb:before,
.#{$fa-css-prefix}-yen:before,
.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; }
.#{$fa-css-prefix}-ruble:before,
.#{$fa-css-prefix}-rouble:before,
.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; }
.#{$fa-css-prefix}-won:before,
.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; }
.#{$fa-css-prefix}-bitcoin:before,
.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; }
.#{$fa-css-prefix}-file:before { content: $fa-var-file; }
.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; }
.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; }
.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; }
.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; }
.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; }
.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; }
.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; }
.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; }
.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; }
.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; }
.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; }
.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; }
.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; }
.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; }
.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; }
.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; }
.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; }
.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; }
.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; }
.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; }
.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; }
.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; }
.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; }
.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; }
.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; }
.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; }
.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; }
.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; }
.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; }
.#{$fa-css-prefix}-android:before { content: $fa-var-android; }
.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; }
.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; }
.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; }
.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; }
.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; }
.#{$fa-css-prefix}-female:before { content: $fa-var-female; }
.#{$fa-css-prefix}-male:before { content: $fa-var-male; }
.#{$fa-css-prefix}-gittip:before,
.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; }
.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; }
.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; }
.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; }
.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; }
.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; }
.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; }
.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; }
.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; }
.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; }
.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; }
.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; }
.#{$fa-css-prefix}-toggle-left:before,
.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; }
.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; }
.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; }
.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; }
.#{$fa-css-prefix}-turkish-lira:before,
.#{$fa-css-prefix}-try:before { content: $fa-var-try; }
.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; }
.#{$fa-css-prefix}-space-shuttle:before { content: $fa-var-space-shuttle; }
.#{$fa-css-prefix}-slack:before { content: $fa-var-slack; }
.#{$fa-css-prefix}-envelope-square:before { content: $fa-var-envelope-square; }
.#{$fa-css-prefix}-wordpress:before { content: $fa-var-wordpress; }
.#{$fa-css-prefix}-openid:before { content: $fa-var-openid; }
.#{$fa-css-prefix}-institution:before,
.#{$fa-css-prefix}-bank:before,
.#{$fa-css-prefix}-university:before { content: $fa-var-university; }
.#{$fa-css-prefix}-mortar-board:before,
.#{$fa-css-prefix}-graduation-cap:before { content: $fa-var-graduation-cap; }
.#{$fa-css-prefix}-yahoo:before { content: $fa-var-yahoo; }
.#{$fa-css-prefix}-google:before { content: $fa-var-google; }
.#{$fa-css-prefix}-reddit:before { content: $fa-var-reddit; }
.#{$fa-css-prefix}-reddit-square:before { content: $fa-var-reddit-square; }
.#{$fa-css-prefix}-stumbleupon-circle:before { content: $fa-var-stumbleupon-circle; }
.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; }
.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; }
.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; }
.#{$fa-css-prefix}-pied-piper-pp:before { content: $fa-var-pied-piper-pp; }
.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; }
.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; }
.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; }
.#{$fa-css-prefix}-language:before { content: $fa-var-language; }
.#{$fa-css-prefix}-fax:before { content: $fa-var-fax; }
.#{$fa-css-prefix}-building:before { content: $fa-var-building; }
.#{$fa-css-prefix}-child:before { content: $fa-var-child; }
.#{$fa-css-prefix}-paw:before { content: $fa-var-paw; }
.#{$fa-css-prefix}-spoon:before { content: $fa-var-spoon; }
.#{$fa-css-prefix}-cube:before { content: $fa-var-cube; }
.#{$fa-css-prefix}-cubes:before { content: $fa-var-cubes; }
.#{$fa-css-prefix}-behance:before { content: $fa-var-behance; }
.#{$fa-css-prefix}-behance-square:before { content: $fa-var-behance-square; }
.#{$fa-css-prefix}-steam:before { content: $fa-var-steam; }
.#{$fa-css-prefix}-steam-square:before { content: $fa-var-steam-square; }
.#{$fa-css-prefix}-recycle:before { content: $fa-var-recycle; }
.#{$fa-css-prefix}-automobile:before,
.#{$fa-css-prefix}-car:before { content: $fa-var-car; }
.#{$fa-css-prefix}-cab:before,
.#{$fa-css-prefix}-taxi:before { content: $fa-var-taxi; }
.#{$fa-css-prefix}-tree:before { content: $fa-var-tree; }
.#{$fa-css-prefix}-spotify:before { content: $fa-var-spotify; }
.#{$fa-css-prefix}-deviantart:before { content: $fa-var-deviantart; }
.#{$fa-css-prefix}-soundcloud:before { content: $fa-var-soundcloud; }
.#{$fa-css-prefix}-database:before { content: $fa-var-database; }
.#{$fa-css-prefix}-file-pdf-o:before { content: $fa-var-file-pdf-o; }
.#{$fa-css-prefix}-file-word-o:before { content: $fa-var-file-word-o; }
.#{$fa-css-prefix}-file-excel-o:before { content: $fa-var-file-excel-o; }
.#{$fa-css-prefix}-file-powerpoint-o:before { content: $fa-var-file-powerpoint-o; }
.#{$fa-css-prefix}-file-photo-o:before,
.#{$fa-css-prefix}-file-picture-o:before,
.#{$fa-css-prefix}-file-image-o:before { content: $fa-var-file-image-o; }
.#{$fa-css-prefix}-file-zip-o:before,
.#{$fa-css-prefix}-file-archive-o:before { content: $fa-var-file-archive-o; }
.#{$fa-css-prefix}-file-sound-o:before,
.#{$fa-css-prefix}-file-audio-o:before { content: $fa-var-file-audio-o; }
.#{$fa-css-prefix}-file-movie-o:before,
.#{$fa-css-prefix}-file-video-o:before { content: $fa-var-file-video-o; }
.#{$fa-css-prefix}-file-code-o:before { content: $fa-var-file-code-o; }
.#{$fa-css-prefix}-vine:before { content: $fa-var-vine; }
.#{$fa-css-prefix}-codepen:before { content: $fa-var-codepen; }
.#{$fa-css-prefix}-jsfiddle:before { content: $fa-var-jsfiddle; }
.#{$fa-css-prefix}-life-bouy:before,
.#{$fa-css-prefix}-life-buoy:before,
.#{$fa-css-prefix}-life-saver:before,
.#{$fa-css-prefix}-support:before,
.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; }
.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; }
.#{$fa-css-prefix}-ra:before,
.#{$fa-css-prefix}-resistance:before,
.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; }
.#{$fa-css-prefix}-ge:before,
.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; }
.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; }
.#{$fa-css-prefix}-git:before { content: $fa-var-git; }
.#{$fa-css-prefix}-y-combinator-square:before,
.#{$fa-css-prefix}-yc-square:before,
.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; }
.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; }
.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; }
.#{$fa-css-prefix}-wechat:before,
.#{$fa-css-prefix}-weixin:before { content: $fa-var-weixin; }
.#{$fa-css-prefix}-send:before,
.#{$fa-css-prefix}-paper-plane:before { content: $fa-var-paper-plane; }
.#{$fa-css-prefix}-send-o:before,
.#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; }
.#{$fa-css-prefix}-history:before { content: $fa-var-history; }
.#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; }
.#{$fa-css-prefix}-header:before { content: $fa-var-header; }
.#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; }
.#{$fa-css-prefix}-sliders:before { content: $fa-var-sliders; }
.#{$fa-css-prefix}-share-alt:before { content: $fa-var-share-alt; }
.#{$fa-css-prefix}-share-alt-square:before { content: $fa-var-share-alt-square; }
.#{$fa-css-prefix}-bomb:before { content: $fa-var-bomb; }
.#{$fa-css-prefix}-soccer-ball-o:before,
.#{$fa-css-prefix}-futbol-o:before { content: $fa-var-futbol-o; }
.#{$fa-css-prefix}-tty:before { content: $fa-var-tty; }
.#{$fa-css-prefix}-binoculars:before { content: $fa-var-binoculars; }
.#{$fa-css-prefix}-plug:before { content: $fa-var-plug; }
.#{$fa-css-prefix}-slideshare:before { content: $fa-var-slideshare; }
.#{$fa-css-prefix}-twitch:before { content: $fa-var-twitch; }
.#{$fa-css-prefix}-yelp:before { content: $fa-var-yelp; }
.#{$fa-css-prefix}-newspaper-o:before { content: $fa-var-newspaper-o; }
.#{$fa-css-prefix}-wifi:before { content: $fa-var-wifi; }
.#{$fa-css-prefix}-calculator:before { content: $fa-var-calculator; }
.#{$fa-css-prefix}-paypal:before { content: $fa-var-paypal; }
.#{$fa-css-prefix}-google-wallet:before { content: $fa-var-google-wallet; }
.#{$fa-css-prefix}-cc-visa:before { content: $fa-var-cc-visa; }
.#{$fa-css-prefix}-cc-mastercard:before { content: $fa-var-cc-mastercard; }
.#{$fa-css-prefix}-cc-discover:before { content: $fa-var-cc-discover; }
.#{$fa-css-prefix}-cc-amex:before { content: $fa-var-cc-amex; }
.#{$fa-css-prefix}-cc-paypal:before { content: $fa-var-cc-paypal; }
.#{$fa-css-prefix}-cc-stripe:before { content: $fa-var-cc-stripe; }
.#{$fa-css-prefix}-bell-slash:before { content: $fa-var-bell-slash; }
.#{$fa-css-prefix}-bell-slash-o:before { content: $fa-var-bell-slash-o; }
.#{$fa-css-prefix}-trash:before { content: $fa-var-trash; }
.#{$fa-css-prefix}-copyright:before { content: $fa-var-copyright; }
.#{$fa-css-prefix}-at:before { content: $fa-var-at; }
.#{$fa-css-prefix}-eyedropper:before { content: $fa-var-eyedropper; }
.#{$fa-css-prefix}-paint-brush:before { content: $fa-var-paint-brush; }
.#{$fa-css-prefix}-birthday-cake:before { content: $fa-var-birthday-cake; }
.#{$fa-css-prefix}-area-chart:before { content: $fa-var-area-chart; }
.#{$fa-css-prefix}-pie-chart:before { content: $fa-var-pie-chart; }
.#{$fa-css-prefix}-line-chart:before { content: $fa-var-line-chart; }
.#{$fa-css-prefix}-lastfm:before { content: $fa-var-lastfm; }
.#{$fa-css-prefix}-lastfm-square:before { content: $fa-var-lastfm-square; }
.#{$fa-css-prefix}-toggle-off:before { content: $fa-var-toggle-off; }
.#{$fa-css-prefix}-toggle-on:before { content: $fa-var-toggle-on; }
.#{$fa-css-prefix}-bicycle:before { content: $fa-var-bicycle; }
.#{$fa-css-prefix}-bus:before { content: $fa-var-bus; }
.#{$fa-css-prefix}-ioxhost:before { content: $fa-var-ioxhost; }
.#{$fa-css-prefix}-angellist:before { content: $fa-var-angellist; }
.#{$fa-css-prefix}-cc:before { content: $fa-var-cc; }
.#{$fa-css-prefix}-shekel:before,
.#{$fa-css-prefix}-sheqel:before,
.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; }
.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; }
.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; }
.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; }
.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; }
.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; }
.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; }
.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; }
.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; }
.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; }
.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; }
.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; }
.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; }
.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; }
.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; }
.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; }
.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; }
.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; }
.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; }
.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; }
.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; }
.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; }
.#{$fa-css-prefix}-intersex:before,
.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; }
.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; }
.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; }
.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; }
.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; }
.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; }
.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; }
.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; }
.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; }
.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; }
.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; }
.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; }
.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; }
.#{$fa-css-prefix}-server:before { content: $fa-var-server; }
.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; }
.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; }
.#{$fa-css-prefix}-hotel:before,
.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; }
.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; }
.#{$fa-css-prefix}-train:before { content: $fa-var-train; }
.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; }
.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; }
.#{$fa-css-prefix}-yc:before,
.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; }
.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; }
.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; }
.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; }
.#{$fa-css-prefix}-battery-4:before,
.#{$fa-css-prefix}-battery:before,
.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; }
.#{$fa-css-prefix}-battery-3:before,
.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; }
.#{$fa-css-prefix}-battery-2:before,
.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; }
.#{$fa-css-prefix}-battery-1:before,
.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; }
.#{$fa-css-prefix}-battery-0:before,
.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; }
.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; }
.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; }
.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; }
.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; }
.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; }
.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; }
.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; }
.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; }
.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; }
.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; }
.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; }
.#{$fa-css-prefix}-hourglass-1:before,
.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; }
.#{$fa-css-prefix}-hourglass-2:before,
.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; }
.#{$fa-css-prefix}-hourglass-3:before,
.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; }
.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; }
.#{$fa-css-prefix}-hand-grab-o:before,
.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; }
.#{$fa-css-prefix}-hand-stop-o:before,
.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; }
.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; }
.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; }
.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; }
.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; }
.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; }
.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; }
.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; }
.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; }
.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; }
.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; }
.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; }
.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; }
.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; }
.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; }
.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; }
.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; }
.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; }
.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; }
.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; }
.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; }
.#{$fa-css-prefix}-tv:before,
.#{$fa-css-prefix}-television:before { content: $fa-var-television; }
.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; }
.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; }
.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; }
.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; }
.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; }
.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; }
.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; }
.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; }
.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; }
.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; }
.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; }
.#{$fa-css-prefix}-map:before { content: $fa-var-map; }
.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; }
.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; }
.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; }
.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; }
.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; }
.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; }
.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; }
.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; }
.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; }
.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; }
.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; }
.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; }
.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; }
.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; }
.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; }
.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; }
.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; }
.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; }
.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; }
.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; }
.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; }
.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; }
.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; }
.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; }
.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; }
.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; }
.#{$fa-css-prefix}-gitlab:before { content: $fa-var-gitlab; }
.#{$fa-css-prefix}-wpbeginner:before { content: $fa-var-wpbeginner; }
.#{$fa-css-prefix}-wpforms:before { content: $fa-var-wpforms; }
.#{$fa-css-prefix}-envira:before { content: $fa-var-envira; }
.#{$fa-css-prefix}-universal-access:before { content: $fa-var-universal-access; }
.#{$fa-css-prefix}-wheelchair-alt:before { content: $fa-var-wheelchair-alt; }
.#{$fa-css-prefix}-question-circle-o:before { content: $fa-var-question-circle-o; }
.#{$fa-css-prefix}-blind:before { content: $fa-var-blind; }
.#{$fa-css-prefix}-audio-description:before { content: $fa-var-audio-description; }
.#{$fa-css-prefix}-volume-control-phone:before { content: $fa-var-volume-control-phone; }
.#{$fa-css-prefix}-braille:before { content: $fa-var-braille; }
.#{$fa-css-prefix}-assistive-listening-systems:before { content: $fa-var-assistive-listening-systems; }
.#{$fa-css-prefix}-asl-interpreting:before,
.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: $fa-var-american-sign-language-interpreting; }
.#{$fa-css-prefix}-deafness:before,
.#{$fa-css-prefix}-hard-of-hearing:before,
.#{$fa-css-prefix}-deaf:before { content: $fa-var-deaf; }
.#{$fa-css-prefix}-glide:before { content: $fa-var-glide; }
.#{$fa-css-prefix}-glide-g:before { content: $fa-var-glide-g; }
.#{$fa-css-prefix}-signing:before,
.#{$fa-css-prefix}-sign-language:before { content: $fa-var-sign-language; }
.#{$fa-css-prefix}-low-vision:before { content: $fa-var-low-vision; }
.#{$fa-css-prefix}-viadeo:before { content: $fa-var-viadeo; }
.#{$fa-css-prefix}-viadeo-square:before { content: $fa-var-viadeo-square; }
.#{$fa-css-prefix}-snapchat:before { content: $fa-var-snapchat; }
.#{$fa-css-prefix}-snapchat-ghost:before { content: $fa-var-snapchat-ghost; }
.#{$fa-css-prefix}-snapchat-square:before { content: $fa-var-snapchat-square; }
.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; }
.#{$fa-css-prefix}-first-order:before { content: $fa-var-first-order; }
.#{$fa-css-prefix}-yoast:before { content: $fa-var-yoast; }
.#{$fa-css-prefix}-themeisle:before { content: $fa-var-themeisle; }
.#{$fa-css-prefix}-google-plus-circle:before,
.#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; }
.#{$fa-css-prefix}-fa:before,
.#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; }
.#{$fa-css-prefix}-handshake-o:before { content: $fa-var-handshake-o; }
.#{$fa-css-prefix}-envelope-open:before { content: $fa-var-envelope-open; }
.#{$fa-css-prefix}-envelope-open-o:before { content: $fa-var-envelope-open-o; }
.#{$fa-css-prefix}-linode:before { content: $fa-var-linode; }
.#{$fa-css-prefix}-address-book:before { content: $fa-var-address-book; }
.#{$fa-css-prefix}-address-book-o:before { content: $fa-var-address-book-o; }
.#{$fa-css-prefix}-vcard:before,
.#{$fa-css-prefix}-address-card:before { content: $fa-var-address-card; }
.#{$fa-css-prefix}-vcard-o:before,
.#{$fa-css-prefix}-address-card-o:before { content: $fa-var-address-card-o; }
.#{$fa-css-prefix}-user-circle:before { content: $fa-var-user-circle; }
.#{$fa-css-prefix}-user-circle-o:before { content: $fa-var-user-circle-o; }
.#{$fa-css-prefix}-user-o:before { content: $fa-var-user-o; }
.#{$fa-css-prefix}-id-badge:before { content: $fa-var-id-badge; }
.#{$fa-css-prefix}-drivers-license:before,
.#{$fa-css-prefix}-id-card:before { content: $fa-var-id-card; }
.#{$fa-css-prefix}-drivers-license-o:before,
.#{$fa-css-prefix}-id-card-o:before { content: $fa-var-id-card-o; }
.#{$fa-css-prefix}-quora:before { content: $fa-var-quora; }
.#{$fa-css-prefix}-free-code-camp:before { content: $fa-var-free-code-camp; }
.#{$fa-css-prefix}-telegram:before { content: $fa-var-telegram; }
.#{$fa-css-prefix}-thermometer-4:before,
.#{$fa-css-prefix}-thermometer:before,
.#{$fa-css-prefix}-thermometer-full:before { content: $fa-var-thermometer-full; }
.#{$fa-css-prefix}-thermometer-3:before,
.#{$fa-css-prefix}-thermometer-three-quarters:before { content: $fa-var-thermometer-three-quarters; }
.#{$fa-css-prefix}-thermometer-2:before,
.#{$fa-css-prefix}-thermometer-half:before { content: $fa-var-thermometer-half; }
.#{$fa-css-prefix}-thermometer-1:before,
.#{$fa-css-prefix}-thermometer-quarter:before { content: $fa-var-thermometer-quarter; }
.#{$fa-css-prefix}-thermometer-0:before,
.#{$fa-css-prefix}-thermometer-empty:before { content: $fa-var-thermometer-empty; }
.#{$fa-css-prefix}-shower:before { content: $fa-var-shower; }
.#{$fa-css-prefix}-bathtub:before,
.#{$fa-css-prefix}-s15:before,
.#{$fa-css-prefix}-bath:before { content: $fa-var-bath; }
.#{$fa-css-prefix}-podcast:before { content: $fa-var-podcast; }
.#{$fa-css-prefix}-window-maximize:before { content: $fa-var-window-maximize; }
.#{$fa-css-prefix}-window-minimize:before { content: $fa-var-window-minimize; }
.#{$fa-css-prefix}-window-restore:before { content: $fa-var-window-restore; }
.#{$fa-css-prefix}-times-rectangle:before,
.#{$fa-css-prefix}-window-close:before { content: $fa-var-window-close; }
.#{$fa-css-prefix}-times-rectangle-o:before,
.#{$fa-css-prefix}-window-close-o:before { content: $fa-var-window-close-o; }
.#{$fa-css-prefix}-bandcamp:before { content: $fa-var-bandcamp; }
.#{$fa-css-prefix}-grav:before { content: $fa-var-grav; }
.#{$fa-css-prefix}-etsy:before { content: $fa-var-etsy; }
.#{$fa-css-prefix}-imdb:before { content: $fa-var-imdb; }
.#{$fa-css-prefix}-ravelry:before { content: $fa-var-ravelry; }
.#{$fa-css-prefix}-eercast:before { content: $fa-var-eercast; }
.#{$fa-css-prefix}-microchip:before { content: $fa-var-microchip; }
.#{$fa-css-prefix}-snowflake-o:before { content: $fa-var-snowflake-o; }
.#{$fa-css-prefix}-superpowers:before { content: $fa-var-superpowers; }
.#{$fa-css-prefix}-wpexplorer:before { content: $fa-var-wpexplorer; }
.#{$fa-css-prefix}-meetup:before { content: $fa-var-meetup; }

View File

@ -1,13 +0,0 @@
// Icon Sizes
// -------------------------
/* makes the font 33% larger relative to the icon container */
.#{$fa-css-prefix}-lg {
font-size: (4em / 3);
line-height: (3em / 4);
vertical-align: -15%;
}
.#{$fa-css-prefix}-2x { font-size: 2em; }
.#{$fa-css-prefix}-3x { font-size: 3em; }
.#{$fa-css-prefix}-4x { font-size: 4em; }
.#{$fa-css-prefix}-5x { font-size: 5em; }

View File

@ -1,19 +0,0 @@
// List Icons
// -------------------------
.#{$fa-css-prefix}-ul {
padding-left: 0;
margin-left: $fa-li-width;
list-style-type: none;
> li { position: relative; }
}
.#{$fa-css-prefix}-li {
position: absolute;
left: -$fa-li-width;
width: $fa-li-width;
top: (2em / 14);
text-align: center;
&.#{$fa-css-prefix}-lg {
left: -$fa-li-width + (4em / 14);
}
}

Some files were not shown because too many files have changed in this diff Show More