├── .gitignore ├── LICENSE ├── README.md ├── config.json ├── gcal ├── __init__.py ├── gcal.py ├── gcalhelper.py └── quickstart.py ├── inkplate └── inkplate.ino ├── main.py ├── oai └── oai.py ├── owm └── owm.py └── render ├── background.jpg ├── css ├── bootstrap.min.css ├── bootstrap.min.css.map ├── styles.css └── weather-icons.min.css ├── dashboard_template.html ├── font ├── Lexend-Black.ttf ├── Lexend-Bold.ttf ├── Lexend-ExtraBold.ttf ├── Lexend-ExtraLight.ttf ├── Lexend-Light.ttf ├── Lexend-Medium.ttf ├── Lexend-Regular.ttf ├── Lexend-SemiBold.ttf ├── Lexend-Thin.ttf ├── TiltWarp-Regular.ttf ├── weathericons-regular-webfont.eot ├── weathericons-regular-webfont.svg ├── weathericons-regular-webfont.ttf ├── weathericons-regular-webfont.woff └── weathericons-regular-webfont.woff2 └── render.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # MagInkDash 3 | This repo contains the code needed to drive an E-Ink Magic Dashboard that uses a Raspberry Pi to automatically retrieve updated content from Google Calendar, OpenWeatherMap and OpenAI ChatGPT, format them into the desired layout, before serving it to a battery powered E-Ink display (Inkplate 10). Note that the code has only been tested on the specific hardware mentioned, but can be easily modified to work with other hardware (for both the server or display). 4 | 5 | ![20230412_214635](https://user-images.githubusercontent.com/5581989/231482915-154db674-9301-465d-8352-d2c4400093eb.JPG) 6 | 7 | ## Background 8 | Back in September 2021, I [shared about my E-Ink Calendar project (MagInkCal) on Reddit](https://www.reddit.com/r/raspberry_pi/comments/pugv7d/maginkcal_magic_calendar_project_completed_full/) (with [full source code on Github](https://github.com/speedyg0nz/MagInkCal/)), which was an attempt to replicate the [Android Magic Calendar concept](https://www.youtube.com/watch?v=2KDkFgOHZ5I) that inspired many DIY projects over the years. While the calendar has been serving me extremely well, I wanted a dashboard which offered additonal information that was rich, timely and glanceable, such as the weather for the next hour just before leaving the house. While there were many projects that might achieve a similar outcome, I wanted something that met my specific needs. Hence, this project was born. You can read more about the story and join the conversation [over on Reddit](https://www.reddit.com/r/raspberry_pi/comments/12joara/maginkdash_magic_eink_dashboard_project_full/). 9 | 10 | ## Hardware Required 11 | - [Raspberry Pi](https://www.raspberrypi.org/) - Used as a server to retrieve content and generate a dashboard for the E-Ink display so any model would do. Personally, I dug out an old Raspberry Pi Model B Revision 2.0 from 2011 and it works fine for this purpose. In fact, it doesn't even need to be a RPi. Any other Single Board Computer, or old computer, or even a cloud service that runs the code would suffice. 12 | - [Inkplate 10 Battery Powered E-Ink Display](https://soldered.com/product/soldered-inkplate-10-9-7-e-paper-board-with-enclosure-copy/) - Used as a client to display the generated dashboard. I went with this because it was an all-in-one with the enclosure and battery included so there's less hardware tinkering. But you could certainly go barebones and assemble the different parts yourself from scratch, i.e. display, microcontroller, case, and battery. 13 | 14 | 15 | ## How It Works 16 | A cron job on RPi will trigger a Python script to run every hour to fetch calendar events from Google Calendar, weather forecast from OpenWeatherMap and random factoids from OpenAI's ChatGPT. The retrieved content is then formatted into the desired layout and saved as an image. An Apache server on the RPi will then host this image such that it can be accessed by the Inkplate 10. On the Inkplate 10, the corresponding script will then connect to the RPi server on the local network via a WiFi connection, retrieve the image and display it on the E-Ink screen. The Inkplate 10 then goes to sleep to conserve battery. The dashboard remains displayed on the E-Ink screen, because well, E-Ink... 17 | 18 | Some features of the dashboard: 19 | - **Battery Life**: As with similar battery powered devices, the biggest question is the battery life. I'm currently using a 1500mAh battery on the Inkplate 10 and based on current usage, it should last me around 3-4 months. With the 3000mAh that comes with the manufacturer assembled Inkplate 10, we could potentially be looking at 6-8 month battery life. With this crazy battery life, there are much more options available. Perhaps solar power for unlimited battery life? Or reducing the refresh interval to 15 or 30min to increase the information timeliness? 20 | - **Calendar and Weather**: I'm currently displaying calendar events and weather forecast for current day and the upcoming two days. No real reason other than the desire to know what my weekend looks like on a Friday, and therefore helping me to better plan my weekend. Unfortunately, if you have a busy calendar with numerous events on a single day, the space on the dashboard will be consumed very quickly. If so, you might wish to modify the code to reduce/limit the number of days/events to be displayed. 21 | - **OpenAI ChatGPT**: As with any new projects in 2023, we can't avoid bringing in ChatGPT. So I've also included a section in the dashboard to retrieve ChatGPT responses via OpenAI's API (free for now, paid in the future). So far I'm using it to retrieve factoids on animals, historical figures, notable events, countries, world records, etc. It's a huge hit with the kids at home, and they'll be standing next to the dashboard on the hour to wait for the next refresh. The prompts fed to ChatGPT can certainly be customised, so please knock yourself out and think of the most outrageous things you can put on your dashboard. Note that you might have to test and adjust the prompts/parameters, else ChatGPT might return fairly repetitive responses, e.g. on Abraham Lincoln, Rosa Parks, Martin Luther King. 22 | - **Telegram Bot**: Although the battery life is crazy long on the Inkplate 10, I still wish to be notified when the battery runs low. To do so, I set up a Telegram Bot and the Inkplate will trigger the bot to send me a message if the measured battery voltage falls below a specified threshold. That said, with the bot set up, there's actually much more you could do, e.g. send yourself a message when it's to expected to rain in the next hour. 23 | 24 | ![MagInkDash Features](https://user-images.githubusercontent.com/5581989/231484018-6ff6a883-3226-42c7-a387-fcef7ee9d49c.png) 25 | 26 | ## Setting Up 27 | 28 | 1. Start by flashing [Raspberrypi OS Lite](https://www.raspberrypi.org/software/operating-systems/) to a SD/MicroSD Card. If you're using a Raspberry Pi with 32bit CPU, there are [known issues](https://forums.raspberrypi.com/viewtopic.php?t=323478) between the latest RPiOS "bullseye" release and chromium-browser, which is required to run this code. As such, I would recommend that you keep to the legacy "buster" OS if you're still running this on older RPi hardware. 29 | 30 | 2. After setting up the OS, run the following commmand in the RPi Terminal, and use the [raspi-config](https://www.raspberrypi.org/documentation/computers/configuration.html) interface to setup Wifi connection, and set the timezone to your location. You can skip this if the image is already preconfigured using the Raspberry Pi Imager. 31 | 32 | ```bash 33 | sudo raspi-config 34 | ``` 35 | 3. Run the following commands in the RPi Terminal to setup the environment to run the Python scripts and function as a web server. It'll take some time so be patient here. 36 | 37 | ```bash 38 | sudo apt update 39 | sudo apt-get install python3-pip 40 | sudo apt-get install chromium-chromedriver 41 | sudo apt-get install libopenjp2-7-dev 42 | pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib 43 | pip3 install pytz 44 | pip3 install selenium 45 | pip3 install Pillow 46 | pip3 install openai 47 | sudo apt-get install apache2 -y 48 | sudo chown pi:www-data /var/www/html 49 | sudo chmod 755 /var/www/html 50 | ``` 51 | 4. Download the over the files in this repo to a folder in your PC first. 52 | 53 | 5. In order for you to access your Google Calendar events, it's necessary to first grant the access. Follow the [instructions here](https://developers.google.com/calendar/api/quickstart/python) on your PC to get the credentials.json file from your Google API. Don't worry, take your time. I'll be waiting here. 54 | 55 | 6. Once done, copy the credentials.json file to the "gcal" folder in this project. Navigate to the "gcal" folder and run the following command on your PC. A web browser should appear, asking you to grant access to your calendar. Once done, you should see a "token.pickle" file in your "gcal" folder. 56 | 57 | ```bash 58 | python3 quickstart.py 59 | ``` 60 | 61 | 7. Copy all the files (other than the "inkplate" folder) over to your RPi using your preferred means. 62 | 63 | 8. Run the following command in the RPi Terminal to open crontab. 64 | ```bash 65 | crontab -e 66 | ``` 67 | 9. Specifically, add the following command to crontab so that the MagInkDash Python script runs on the hour, every hour. 68 | ```bash 69 | 0 * * * * cd /location/to/your/MagInkDash && python3 main.py 70 | ``` 71 | 10. As for the Inkplate, I'm not going to devote too much space here since there are [official resources that describe how to set it up](https://inkplate.readthedocs.io/en/latest/get-started.html). It may take some trial and error for those new to microcontroller programming but it's all worth it! Only the Arduino portion of the guide is relevant, and you'll need to be able to run *.ino scripts via Arduino IDE before proceeding. From there, run the "inkplate.ino" file from the "inkplate" folder from the Arduino IDE when connected to the Inkplate. 72 | 73 | 12. That's all! Your Magic Dashboard should now be refreshed every hour! 74 | 75 | ![20230412_214652](https://user-images.githubusercontent.com/5581989/231485348-35d7e0df-034e-49aa-8500-223b2b3bdcc0.JPG) 76 | ![20230412_215020](https://user-images.githubusercontent.com/5581989/231484068-aa6ce877-1e0a-49fe-b47e-7c024752f42c.JPG) 77 | Selfie and family portrait together with the MagInkCal 78 | 79 | ## Acknowledgements 80 | - [Lexend Font](https://fonts.google.com/specimen/Lexend) and [Tilt Warp Font](https://fonts.google.com/specimen/Tilt+Warp): Fonts used for the dashboard display 81 | - [Bootstrap](https://getbootstrap.com/): Styling toolkit to customise the look of the dashboard 82 | - [Weather Icons](https://erikflowers.github.io/weather-icons/): Icons used for displaying of weather forecast information 83 | - [Freepik](https://www.freepik.com/): For the background image used in this dashboard 84 | 85 | ## Contributing 86 | I won't be updating this code much, since it serves my needs well. Nevertheless, feel free to fork the repo and modify it for your own purpose. At the same time, check out other similar projects, such as [InkyCal](https://github.com/aceisace/Inkycal) by [/u/aceisace](https://www.reddit.com/user/aceisace/). It's much more polished and also actively developed. 87 | 88 | ## Buy Me A Coffee 89 | If this project has helped you in any way, do buy me a coffee so I can continue to build more of such projects in the future and share them with the community! 90 | 91 | Buy Me A Coffee 92 | 93 | 94 | ## What's Next 95 | Since building the Magic Calendar two years back, I've been looking at E-Ink tablets that emulate the experience of writing on paper, and allow the users to take notes on the go. Those familiar with this range of products would be aware of the Kindle Scribe, reMarkable tablet, Ratta Supernote, Kobo Elipsa and many others. I've had some limited success with getting a Kindle Paperwhite to display a calendar while sleeping but it felt too "hacky" and prone to breaking when Amazon updates the OS. I'm still looking for the right device (possibly a PineNote?), so if you're aware of any suitable candidates, do let me know! 96 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "displayTZ": "Asia/Hong_Kong", 3 | "calendars": ["primary"], 4 | "numCalDaysToShow": 3, 5 | "owm_api_key": "ENTER YOUR OWN API KEY HERE", 6 | "lat": 22.3193, 7 | "lon": 114.1694, 8 | "imageWidth": 1200, 9 | "imageHeight": 825, 10 | "rotateAngle": 0, 11 | "openai_api_key": "ENTER YOUR OWN API KEY HERE", 12 | "path_to_server_image": "/var/www/html/maginkdash.png" 13 | } -------------------------------------------------------------------------------- /gcal/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/gcal/__init__.py -------------------------------------------------------------------------------- /gcal/gcal.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is where we retrieve events from the Google Calendar. Before doing so, make sure you have both the 3 | credentials.json and token.pickle in the same folder as this file. If not, run quickstart.py first. 4 | """ 5 | 6 | from gcal.gcalhelper import GcalHelper 7 | import logging 8 | 9 | 10 | class GcalModule: 11 | def __init__(self): 12 | self.logger = logging.getLogger('maginkdash') 13 | self.calHelper = GcalHelper() 14 | 15 | def get_day_in_cal(self, startDate, eventDate): 16 | delta = eventDate - startDate 17 | return delta.days 18 | 19 | def get_short_time(self, datetimeObj): 20 | datetime_str = '' 21 | if datetimeObj.minute > 0: 22 | datetime_str = '.{:02d}'.format(datetimeObj.minute) 23 | 24 | if datetimeObj.hour == 0: 25 | datetime_str = '12{}am'.format(datetime_str) 26 | elif datetimeObj.hour == 12: 27 | datetime_str = '12{}pm'.format(datetime_str) 28 | elif datetimeObj.hour > 12: 29 | datetime_str = '{}{}pm'.format(str(datetimeObj.hour % 12), datetime_str) 30 | else: 31 | datetime_str = '{}{}am'.format(str(datetimeObj.hour), datetime_str) 32 | return datetime_str 33 | 34 | def get_events(self, currDate, calendars, calStartDatetime, calEndDatetime, displayTZ, numDays): 35 | eventList = self.calHelper.retrieve_events(calendars, calStartDatetime, calEndDatetime, displayTZ) 36 | 37 | # check if event stretches across multiple days 38 | calList = [] 39 | for i in range(numDays): 40 | calList.append([]) 41 | for event in eventList: 42 | idx = self.get_day_in_cal(currDate, event['startDatetime'].date()) 43 | if event['isMultiday']: 44 | end_idx = self.get_day_in_cal(currDate, event['endDatetime'].date()) 45 | if idx < 0: 46 | idx = 0 47 | if end_idx >= len(calList): 48 | end_idx = len(calList) - 1 49 | for i in range(idx, end_idx + 1): 50 | calList[i].append(event) 51 | elif idx >= 0: 52 | calList[idx].append(event) 53 | 54 | return calList -------------------------------------------------------------------------------- /gcal/gcalhelper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This is where we retrieve events from the Google Calendar. Before doing so, make sure you have both the 5 | credentials.json and token.pickle in the same folder as this file. If not, run quickstart.py first. 6 | """ 7 | 8 | from __future__ import print_function 9 | import datetime as dt 10 | import pickle 11 | import os.path 12 | import pathlib 13 | from googleapiclient.discovery import build 14 | from google_auth_oauthlib.flow import InstalledAppFlow 15 | from google.auth.transport.requests import Request 16 | import logging 17 | 18 | 19 | class GcalHelper: 20 | 21 | def __init__(self): 22 | self.logger = logging.getLogger('maginkdash') 23 | # Initialise the Google Calendar using the provided credentials and token 24 | SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'] 25 | self.currPath = str(pathlib.Path(__file__).parent.absolute()) 26 | 27 | creds = None 28 | # The file token.pickle stores the user's access and refresh tokens, and is 29 | # created automatically when the authorization flow completes for the first 30 | # time. 31 | if os.path.exists(self.currPath + '/token.pickle'): 32 | with open(self.currPath + '/token.pickle', 'rb') as token: 33 | creds = pickle.load(token) 34 | # If there are no (valid) credentials available, let the user log in. 35 | if not creds or not creds.valid: 36 | if creds and creds.expired and creds.refresh_token: 37 | creds.refresh(Request()) 38 | else: 39 | flow = InstalledAppFlow.from_client_secrets_file( 40 | self.currPath + '/credentials.json', SCOPES) 41 | creds = flow.run_local_server(port=0) 42 | # Save the credentials for the next run 43 | with open(self.currPath + '/token.pickle', 'wb') as token: 44 | pickle.dump(creds, token) 45 | 46 | self.service = build('calendar', 'v3', credentials=creds, cache_discovery=False) 47 | 48 | def list_calendars(self): 49 | # helps to retrieve ID for calendars within the account 50 | # calendar IDs added to config.json will then be queried for retrieval of events 51 | self.logger.info('Getting list of calendars') 52 | calendars_result = self.service.calendarList().list().execute() 53 | calendars = calendars_result.get('items', []) 54 | if not calendars: 55 | self.logger.info('No calendars found.') 56 | for calendar in calendars: 57 | summary = calendar['summary'] 58 | cal_id = calendar['id'] 59 | self.logger.info("%s\t%s" % (summary, cal_id)) 60 | 61 | def to_datetime(self, isoDatetime, localTZ): 62 | # replace Z with +00:00 is a workaround until datetime library decides what to do with the Z notation 63 | to_datetime = dt.datetime.fromisoformat(isoDatetime.replace('Z', '+00:00')) 64 | return to_datetime.astimezone(localTZ) 65 | 66 | def adjust_end_time(self, endTime, localTZ): 67 | # check if end time is at 00:00 of next day, if so set to max time for day before 68 | if endTime.hour == 0 and endTime.minute == 0 and endTime.second == 0: 69 | newEndtime = localTZ.localize( 70 | dt.datetime.combine(endTime.date() - dt.timedelta(days=1), dt.datetime.max.time())) 71 | return newEndtime 72 | else: 73 | return endTime 74 | 75 | def is_multiday(self, start, end): 76 | # check if event stretches across multiple days 77 | return start.date() != end.date() 78 | 79 | def retrieve_events(self, calendars, startDatetime, endDatetime, localTZ): 80 | # Call the Google Calendar API and return a list of events that fall within the specified dates 81 | event_list = [] 82 | 83 | min_time_str = startDatetime.isoformat() 84 | max_time_str = endDatetime.isoformat() 85 | if False: 86 | return event_list 87 | 88 | self.logger.info('Retrieving events between ' + min_time_str + ' and ' + max_time_str + '...') 89 | events_result = [] 90 | for cal in calendars: 91 | events_result.append( 92 | self.service.events().list(calendarId=cal, timeMin=min_time_str, 93 | timeMax=max_time_str, singleEvents=True, 94 | orderBy='startTime').execute() 95 | ) 96 | 97 | events = [] 98 | for eve in events_result: 99 | events += eve.get('items', []) 100 | # events = events_result.get('items', []) 101 | 102 | if not events: 103 | self.logger.info('No upcoming events found.') 104 | for event in events: 105 | # extracting and converting events data into a new list 106 | new_event = {'summary': event['summary']} 107 | 108 | if event['start'].get('dateTime') is None: 109 | new_event['allday'] = True 110 | new_event['startDatetime'] = self.to_datetime(event['start'].get('date'), localTZ) 111 | else: 112 | new_event['allday'] = False 113 | new_event['startDatetime'] = self.to_datetime(event['start'].get('dateTime'), localTZ) 114 | 115 | if event['end'].get('dateTime') is None: 116 | new_event['endDatetime'] = self.adjust_end_time(self.to_datetime(event['end'].get('date'), localTZ), 117 | localTZ) 118 | else: 119 | new_event['endDatetime'] = self.adjust_end_time(self.to_datetime(event['end'].get('dateTime'), localTZ), 120 | localTZ) 121 | 122 | new_event['updatedDatetime'] = self.to_datetime(event['updated'], localTZ) 123 | new_event['isMultiday'] = self.is_multiday(new_event['startDatetime'], new_event['endDatetime']) 124 | event_list.append(new_event) 125 | 126 | # We need to sort eventList because the event will be sorted in "calendar order" instead of hours order 127 | # TODO: improve because of double cycle for now is not much cost 128 | event_list = sorted(event_list, key=lambda k: k['startDatetime']) 129 | return event_list 130 | -------------------------------------------------------------------------------- /gcal/quickstart.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Run this script first to obtain the token. Credentials.json must be in the same folder first. 5 | To obtain Credentials.json, follow the instructions listed in the following link. 6 | https://developers.google.com/calendar/api/quickstart/python 7 | """ 8 | 9 | from __future__ import print_function 10 | import datetime 11 | import pickle 12 | import os.path 13 | from googleapiclient.discovery import build 14 | from google_auth_oauthlib.flow import InstalledAppFlow 15 | from google.auth.transport.requests import Request 16 | 17 | # If modifying these scopes, delete the file token.pickle. 18 | SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'] 19 | 20 | 21 | def main(): 22 | """Shows basic usage of the Google Calendar API. 23 | Prints the start and name of the next 10 events on the user's calendar. 24 | """ 25 | creds = None 26 | # The file token.pickle stores the user's access and refresh tokens, and is 27 | # created automatically when the authorization flow completes for the first 28 | # time. 29 | if os.path.exists('token.pickle'): 30 | with open('token.pickle', 'rb') as token: 31 | creds = pickle.load(token) 32 | # If there are no (valid) credentials available, let the user log in. 33 | if not creds or not creds.valid: 34 | if creds and creds.expired and creds.refresh_token: 35 | creds.refresh(Request()) 36 | else: 37 | flow = InstalledAppFlow.from_client_secrets_file( 38 | 'credentials.json', SCOPES) 39 | creds = flow.run_local_server(port=0) 40 | # Save the credentials for the next run 41 | with open('token.pickle', 'wb') as token: 42 | pickle.dump(creds, token) 43 | 44 | service = build('calendar', 'v3', credentials=creds) 45 | 46 | # Call the Calendar API 47 | now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time 48 | print('Getting the upcoming 10 events') 49 | events_result = service.events().list(calendarId='primary', timeMin=now, 50 | maxResults=10, singleEvents=True, 51 | orderBy='startTime').execute() 52 | events = events_result.get('items', []) 53 | 54 | if not events: 55 | print('No upcoming events found.') 56 | for event in events: 57 | start = event['start'].get('dateTime', event['start'].get('date')) 58 | end = event['end'].get('dateTime', event['start'].get('date')) 59 | updated = event['updated'] 60 | print(start + " | " + end + " | " + updated + " | " + event['summary']) 61 | 62 | 63 | if __name__ == '__main__': 64 | main() -------------------------------------------------------------------------------- /inkplate/inkplate.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Adapted from the Inkplate10_Image_Frame_From_Web example for Soldered Inkplate 10 3 | https://github.com/SolderedElectronics/Inkplate-Arduino-library/blob/master/examples/Inkplate10/Projects/Inkplate10_Image_Frame_From_Web/Inkplate10_Image_Frame_From_Web.ino 4 | 5 | What this code does: 6 | 1. Connect to a WiFi access point 7 | 2. Retrieve an image from a web address 8 | 3. Display the image on the Inkplate 10 device 9 | 4. (Optional) Check the battery level on the Inkplate device 10 | 5. (Optional) Send a message via Telegram if battery level is low 11 | 6. Set a sleep timer for 60 minutes, and allow the Inkplate to go into deep sleep to conserve battery 12 | */ 13 | 14 | // Next 3 lines are a precaution, you can ignore those, and the example would also work without them 15 | #if !defined(ARDUINO_INKPLATE10) && !defined(ARDUINO_INKPLATE10V2) 16 | #error "Wrong board selection for this example, please select e-radionica Inkplate10 or Soldered Inkplate10 in the boards menu." 17 | #endif 18 | 19 | #include "Inkplate.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | Inkplate display(INKPLATE_3BIT); 26 | 27 | const char ssid[] = "YOUR WIFI SSID"; // Your WiFi SSID 28 | const char *password = "YOUR WIFI PASSWORD"; // Your WiFi password 29 | const char *imgurl = "http://url.to.your.server/maginkdash.png"; // Your dashboard image web address 30 | 31 | // Initialize Telegram BOT 32 | #define BOTtoken "YOUR TELEGRAM BOT TOKEN" // your Bot Token (Get from Botfather) 33 | 34 | // Use @myidbot to find out the chat ID of an individual or a group 35 | // Also note that you need to click "start" on a bot before it can 36 | // message you 37 | #define CHAT_ID "YOUR TELEGRAM CHAT ID TO SEND MESSAGES TO" 38 | 39 | // Battery values 40 | #define BATTV_MAX 4.1 // maximum voltage of battery 41 | #define BATTV_MIN 3.2 // what we regard as an empty battery 42 | #define BATTV_LOW 3.4 // voltage considered to be low battery 43 | 44 | WiFiClientSecure client; 45 | UniversalTelegramBot bot(BOTtoken, client); 46 | 47 | void setup() 48 | { 49 | Serial.begin(115200); 50 | display.begin(); 51 | 52 | // Join wifi, retrieve image, update display 53 | display.joinAP(ssid, password); 54 | char url[256]; 55 | strcpy(url, imgurl); 56 | Serial.println(display.drawImage(url, display.PNG, 0, 0)); 57 | display.display(); 58 | 59 | //uncomment or delete the following section if not using Telegram to send message when battery is low 60 | double battvoltage = display.readBattery(); 61 | int battpc = calc_battery_percentage(battvoltage); 62 | if (battvoltage < BATTV_LOW) { 63 | char msg [100]; 64 | sprintf (msg, "Inkplate battery at %d%%, voltage at %.2fV", battpc, battvoltage); 65 | client.setCACert(TELEGRAM_CERTIFICATE_ROOT); 66 | bot.sendMessage(CHAT_ID, msg, ""); 67 | } 68 | 69 | // Let display go to sleep to conserve battery, and wake up an hour later 70 | Serial.println("Going to sleep"); 71 | delay(100); 72 | esp_sleep_enable_timer_wakeup(60ll * 60 * 1000 * 1000); //wakeup in 60min time - 60min * 60s * 1000ms * 1000us 73 | esp_deep_sleep_start(); 74 | } 75 | 76 | void loop() 77 | { 78 | // Never here, as deepsleep restarts esp32 79 | } 80 | 81 | 82 | int calc_battery_percentage(double battv) 83 | { 84 | int battery_percentage = (uint8_t)(((battv - BATTV_MIN) / (BATTV_MAX - BATTV_MIN)) * 100); 85 | 86 | if (battery_percentage < 0) 87 | battery_percentage = 0; 88 | if (battery_percentage > 100) 89 | battery_percentage = 100; 90 | 91 | return battery_percentage; 92 | } -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | """ 2 | This project is designed for the Inkplate 10 display. However, since the server code is only generating an image, it can 3 | be easily adapted to other display sizes and resolution by adjusting the config settings, HTML template and 4 | CSS stylesheet. This code is heavily adapted from my other project (MagInkCal) so do take a look at it if you're keen. 5 | As a dashboard, there are many other things that could be displayed, and it can be done as long as you are able to 6 | retrieve the information. So feel free to change up the code and amend it to your needs. 7 | """ 8 | 9 | import datetime 10 | import logging 11 | import sys 12 | import json 13 | from datetime import datetime as dt 14 | from pytz import timezone 15 | from gcal.gcal import GcalModule 16 | from owm.owm import OWMModule 17 | from oai.oai import OAIModule 18 | from render.render import RenderHelper 19 | 20 | 21 | if __name__ == '__main__': 22 | logger = logging.getLogger('maginkdash') 23 | 24 | # Basic configuration settings (user replaceable) 25 | configFile = open('config.json') 26 | config = json.load(configFile) 27 | 28 | calendars = config['calendars'] # Google Calendar IDs 29 | displayTZ = timezone(config['displayTZ']) # list of timezones - print(pytz.all_timezones) 30 | numCalDaysToShow = config['numCalDaysToShow'] # Number of days to retrieve from gcal, keep to 3 unless other parts of the code are changed too 31 | imageWidth = config['imageWidth'] # Width of image to be generated for display. 32 | imageHeight = config['imageHeight'] # Height of image to be generated for display. 33 | rotateAngle = config['rotateAngle'] # If image is rendered in portrait orientation, angle to rotate to fit screen 34 | lat = config["lat"] # Latitude in decimal of the location to retrieve weather forecast for 35 | lon = config["lon"] # Longitude in decimal of the location to retrieve weather forecast for 36 | owm_api_key = config["owm_api_key"] # OpenWeatherMap API key. Required to retrieve weather forecast. 37 | openai_api_key = config["openai_api_key"] # OpenAI API key. Required to retrieve response from ChatGPT 38 | path_to_server_image = config["path_to_server_image"] # Location to save the generated image 39 | 40 | # Create and configure logger 41 | logging.basicConfig(filename="logfile.log", format='%(asctime)s %(levelname)s - %(message)s', filemode='a') 42 | logger = logging.getLogger('maginkdash') 43 | logger.addHandler(logging.StreamHandler(sys.stdout)) # print logger to stdout 44 | logger.setLevel(logging.INFO) 45 | logger.info("Starting dashboard update") 46 | 47 | # Retrieve Weather Data 48 | owmModule = OWMModule() 49 | current_weather, hourly_forecast, daily_forecast = owmModule.get_weather(lat, lon, owm_api_key) 50 | 51 | # Retrieve Calendar Data 52 | currDate = dt.now(displayTZ).date() 53 | calStartDatetime = displayTZ.localize(dt.combine(currDate, dt.min.time())) 54 | calEndDatetime = displayTZ.localize(dt.combine(currDate + datetime.timedelta(days=numCalDaysToShow-1), dt.max.time())) 55 | calModule = GcalModule() 56 | eventList = calModule.get_events( 57 | currDate, calendars, calStartDatetime, calEndDatetime, displayTZ, numCalDaysToShow) 58 | 59 | # Retrieve Random Fact from OpenAI 60 | oaiModule = OAIModule() 61 | topic = oaiModule.get_random_fact(currDate, openai_api_key) 62 | 63 | # Render Dashboard Image 64 | renderService = RenderHelper(imageWidth, imageHeight, rotateAngle) 65 | renderService.process_inputs(currDate, current_weather, hourly_forecast, daily_forecast, eventList, numCalDaysToShow, 66 | topic, path_to_server_image) 67 | 68 | logger.info("Completed dashboard update") 69 | 70 | 71 | -------------------------------------------------------------------------------- /oai/oai.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is where we submit prompts to OpenAI ChatGPT and retrieve responses to be displayed. Before doing so, make sure 3 | you have both the signed up for an OpenAI account and also obtained a valid API key that is specified in the config.json 4 | file. After which, go crazy and amend the prompts below to your needs. Get ChatGPT to generate a new Haiku every hour, 5 | or tell you a joke. Knock yourself out! 6 | """ 7 | 8 | import logging 9 | import random 10 | import openai 11 | 12 | 13 | class OAIModule: 14 | def __init__(self): 15 | self.logger = logging.getLogger('maginkdash') 16 | 17 | def get_random_fact(self, curr_date, openai_api_key): 18 | curr_mth_str = curr_date.strftime("%B") 19 | # Generate random fact from OpenAI 20 | topics = [ 21 | {"title": "Did You Know?", 22 | "prompt": "Tell me a fun fact in 50 words that is suitable for children below 12"}, 23 | {"title": "All About Animals", 24 | "prompt": "Tell me an interesting fact about an animal in {} in 50 words that is suitable for children below 12".format( 25 | self.get_country()[1])}, 26 | {"title": "All About Countries", 27 | "prompt": "Tell me an interesting fact about the country {} in 50 words that is suitable for children below 12".format( 28 | self.get_country()[1])}, 29 | {"title": "Famous People", 30 | "prompt": "Tell me about a famous historical figure from {} in 50 words that is suitable for children below 12".format( 31 | self.get_country()[1])}, 32 | {"title": "Notable Events", 33 | "prompt": "Tell me about a notable historical event that happened in {} in 50 words that is suitable for children below 12".format( 34 | self.get_country()[1])}, 35 | {"title": "Notable World Records", 36 | "prompt": "Tell me about a notable world record in 50 words that is suitable for children below 12"}, 37 | ] 38 | topic = random.choice(topics) 39 | openai.api_key = openai_api_key 40 | response = openai.Completion.create( 41 | model="text-davinci-003", 42 | prompt=topic["prompt"], 43 | temperature=0.75, 44 | max_tokens=64, 45 | top_p=1.0, 46 | frequency_penalty=0.0, 47 | presence_penalty=0.0 48 | ) 49 | text = response["choices"][0]["text"] 50 | last_period = text.rfind('.') 51 | if last_period == -1: 52 | topic["text"] = text 53 | else: 54 | topic["text"] = text[0:last_period + 1] 55 | self.logger.info(topic["title"]) 56 | self.logger.info(topic["text"]) 57 | 58 | return topic 59 | 60 | 61 | def get_country(self): 62 | countries = [ 63 | ('US', 'United States'), 64 | ('AF', 'Afghanistan'), 65 | ('AL', 'Albania'), 66 | ('DZ', 'Algeria'), 67 | ('AS', 'American Samoa'), 68 | ('AD', 'Andorra'), 69 | ('AO', 'Angola'), 70 | ('AI', 'Anguilla'), 71 | ('AQ', 'Antarctica'), 72 | ('AG', 'Antigua And Barbuda'), 73 | ('AR', 'Argentina'), 74 | ('AM', 'Armenia'), 75 | ('AW', 'Aruba'), 76 | ('AU', 'Australia'), 77 | ('AT', 'Austria'), 78 | ('AZ', 'Azerbaijan'), 79 | ('BS', 'Bahamas'), 80 | ('BH', 'Bahrain'), 81 | ('BD', 'Bangladesh'), 82 | ('BB', 'Barbados'), 83 | ('BY', 'Belarus'), 84 | ('BE', 'Belgium'), 85 | ('BZ', 'Belize'), 86 | ('BJ', 'Benin'), 87 | ('BM', 'Bermuda'), 88 | ('BT', 'Bhutan'), 89 | ('BO', 'Bolivia'), 90 | ('BA', 'Bosnia And Herzegowina'), 91 | ('BW', 'Botswana'), 92 | ('BV', 'Bouvet Island'), 93 | ('BR', 'Brazil'), 94 | ('BN', 'Brunei Darussalam'), 95 | ('BG', 'Bulgaria'), 96 | ('BF', 'Burkina Faso'), 97 | ('BI', 'Burundi'), 98 | ('KH', 'Cambodia'), 99 | ('CM', 'Cameroon'), 100 | ('CA', 'Canada'), 101 | ('CV', 'Cape Verde'), 102 | ('KY', 'Cayman Islands'), 103 | ('CF', 'Central African Rep'), 104 | ('TD', 'Chad'), 105 | ('CL', 'Chile'), 106 | ('CN', 'China'), 107 | ('CX', 'Christmas Island'), 108 | ('CC', 'Cocos Islands'), 109 | ('CO', 'Colombia'), 110 | ('KM', 'Comoros'), 111 | ('CG', 'Congo'), 112 | ('CK', 'Cook Islands'), 113 | ('CR', 'Costa Rica'), 114 | ('CI', 'Cote D`ivoire'), 115 | ('HR', 'Croatia'), 116 | ('CU', 'Cuba'), 117 | ('CY', 'Cyprus'), 118 | ('CZ', 'Czech Republic'), 119 | ('DK', 'Denmark'), 120 | ('DJ', 'Djibouti'), 121 | ('DM', 'Dominica'), 122 | ('DO', 'Dominican Republic'), 123 | ('TP', 'East Timor'), 124 | ('EC', 'Ecuador'), 125 | ('EG', 'Egypt'), 126 | ('SV', 'El Salvador'), 127 | ('GQ', 'Equatorial Guinea'), 128 | ('ER', 'Eritrea'), 129 | ('EE', 'Estonia'), 130 | ('ET', 'Ethiopia'), 131 | ('FK', 'Falkland Islands (Malvinas)'), 132 | ('FO', 'Faroe Islands'), 133 | ('FJ', 'Fiji'), 134 | ('FI', 'Finland'), 135 | ('FR', 'France'), 136 | ('GF', 'French Guiana'), 137 | ('PF', 'French Polynesia'), 138 | ('TF', 'French S. Territories'), 139 | ('GA', 'Gabon'), 140 | ('GM', 'Gambia'), 141 | ('GE', 'Georgia'), 142 | ('DE', 'Germany'), 143 | ('GH', 'Ghana'), 144 | ('GI', 'Gibraltar'), 145 | ('GR', 'Greece'), 146 | ('GL', 'Greenland'), 147 | ('GD', 'Grenada'), 148 | ('GP', 'Guadeloupe'), 149 | ('GU', 'Guam'), 150 | ('GT', 'Guatemala'), 151 | ('GN', 'Guinea'), 152 | ('GW', 'Guinea-bissau'), 153 | ('GY', 'Guyana'), 154 | ('HT', 'Haiti'), 155 | ('HN', 'Honduras'), 156 | ('HK', 'Hong Kong'), 157 | ('HU', 'Hungary'), 158 | ('IS', 'Iceland'), 159 | ('IN', 'India'), 160 | ('ID', 'Indonesia'), 161 | ('IR', 'Iran'), 162 | ('IQ', 'Iraq'), 163 | ('IE', 'Ireland'), 164 | ('IL', 'Israel'), 165 | ('IT', 'Italy'), 166 | ('JM', 'Jamaica'), 167 | ('JP', 'Japan'), 168 | ('JO', 'Jordan'), 169 | ('KZ', 'Kazakhstan'), 170 | ('KE', 'Kenya'), 171 | ('KI', 'Kiribati'), 172 | ('KP', 'Korea (North)'), 173 | ('KR', 'Korea (South)'), 174 | ('KW', 'Kuwait'), 175 | ('KG', 'Kyrgyzstan'), 176 | ('LA', 'Laos'), 177 | ('LV', 'Latvia'), 178 | ('LB', 'Lebanon'), 179 | ('LS', 'Lesotho'), 180 | ('LR', 'Liberia'), 181 | ('LY', 'Libya'), 182 | ('LI', 'Liechtenstein'), 183 | ('LT', 'Lithuania'), 184 | ('LU', 'Luxembourg'), 185 | ('MO', 'Macau'), 186 | ('MK', 'Macedonia'), 187 | ('MG', 'Madagascar'), 188 | ('MW', 'Malawi'), 189 | ('MY', 'Malaysia'), 190 | ('MV', 'Maldives'), 191 | ('ML', 'Mali'), 192 | ('MT', 'Malta'), 193 | ('MH', 'Marshall Islands'), 194 | ('MQ', 'Martinique'), 195 | ('MR', 'Mauritania'), 196 | ('MU', 'Mauritius'), 197 | ('YT', 'Mayotte'), 198 | ('MX', 'Mexico'), 199 | ('FM', 'Micronesia'), 200 | ('MD', 'Moldova'), 201 | ('MC', 'Monaco'), 202 | ('MN', 'Mongolia'), 203 | ('MS', 'Montserrat'), 204 | ('MA', 'Morocco'), 205 | ('MZ', 'Mozambique'), 206 | ('MM', 'Myanmar'), 207 | ('NA', 'Namibia'), 208 | ('NR', 'Nauru'), 209 | ('NP', 'Nepal'), 210 | ('NL', 'Netherlands'), 211 | ('AN', 'Netherlands Antilles'), 212 | ('NC', 'New Caledonia'), 213 | ('NZ', 'New Zealand'), 214 | ('NI', 'Nicaragua'), 215 | ('NE', 'Niger'), 216 | ('NG', 'Nigeria'), 217 | ('NU', 'Niue'), 218 | ('NF', 'Norfolk Island'), 219 | ('MP', 'Northern Mariana Islands'), 220 | ('NO', 'Norway'), 221 | ('OM', 'Oman'), 222 | ('PK', 'Pakistan'), 223 | ('PW', 'Palau'), 224 | ('PA', 'Panama'), 225 | ('PG', 'Papua New Guinea'), 226 | ('PY', 'Paraguay'), 227 | ('PE', 'Peru'), 228 | ('PH', 'Philippines'), 229 | ('PN', 'Pitcairn'), 230 | ('PL', 'Poland'), 231 | ('PT', 'Portugal'), 232 | ('PR', 'Puerto Rico'), 233 | ('QA', 'Qatar'), 234 | ('RE', 'Reunion'), 235 | ('RO', 'Romania'), 236 | ('RU', 'Russian Federation'), 237 | ('RW', 'Rwanda'), 238 | ('KN', 'Saint Kitts And Nevis'), 239 | ('LC', 'Saint Lucia'), 240 | ('VC', 'St Vincent/Grenadines'), 241 | ('WS', 'Samoa'), 242 | ('SM', 'San Marino'), 243 | ('ST', 'Sao Tome'), 244 | ('SA', 'Saudi Arabia'), 245 | ('SN', 'Senegal'), 246 | ('SC', 'Seychelles'), 247 | ('SL', 'Sierra Leone'), 248 | ('SG', 'Singapore'), 249 | ('SK', 'Slovakia'), 250 | ('SI', 'Slovenia'), 251 | ('SB', 'Solomon Islands'), 252 | ('SO', 'Somalia'), 253 | ('ZA', 'South Africa'), 254 | ('ES', 'Spain'), 255 | ('LK', 'Sri Lanka'), 256 | ('SH', 'St. Helena'), 257 | ('PM', 'St.Pierre'), 258 | ('SD', 'Sudan'), 259 | ('SR', 'Suriname'), 260 | ('SZ', 'Swaziland'), 261 | ('SE', 'Sweden'), 262 | ('CH', 'Switzerland'), 263 | ('SY', 'Syrian Arab Republic'), 264 | ('TW', 'Taiwan'), 265 | ('TJ', 'Tajikistan'), 266 | ('TZ', 'Tanzania'), 267 | ('TH', 'Thailand'), 268 | ('TG', 'Togo'), 269 | ('TK', 'Tokelau'), 270 | ('TO', 'Tonga'), 271 | ('TT', 'Trinidad And Tobago'), 272 | ('TN', 'Tunisia'), 273 | ('TR', 'Turkey'), 274 | ('TM', 'Turkmenistan'), 275 | ('TV', 'Tuvalu'), 276 | ('UG', 'Uganda'), 277 | ('UA', 'Ukraine'), 278 | ('AE', 'United Arab Emirates'), 279 | ('UK', 'United Kingdom'), 280 | ('UY', 'Uruguay'), 281 | ('UZ', 'Uzbekistan'), 282 | ('VU', 'Vanuatu'), 283 | ('VA', 'Vatican City State'), 284 | ('VE', 'Venezuela'), 285 | ('VN', 'Viet Nam'), 286 | ('VG', 'Virgin Islands (British)'), 287 | ('VI', 'Virgin Islands (U.S.)'), 288 | ('YE', 'Yemen'), 289 | ('YU', 'Yugoslavia'), 290 | ('ZR', 'Zaire'), 291 | ('ZM', 'Zambia'), 292 | ('ZW', 'Zimbabwe') 293 | ] 294 | return random.choice(countries) 295 | -------------------------------------------------------------------------------- /owm/owm.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is where we retrieve weather forecast from OpenWeatherMap. Before doing so, make sure you have both the 3 | signed up for an OWM account and also obtained a valid API key that is specified in the config.json file. 4 | """ 5 | 6 | import logging 7 | import requests 8 | import json 9 | import string 10 | import datetime 11 | 12 | 13 | class OWMModule: 14 | def __init__(self): 15 | self.logger = logging.getLogger('maginkdash') 16 | 17 | def get_owm_weather(self, lat, lon, api_key): 18 | url = "https://api.openweathermap.org/data/3.0/onecall?lat=%s&lon=%s&appid=%s&exclude=minutely,alerts&units=metric" % ( 19 | lat, lon, api_key) 20 | response = requests.get(url) 21 | data = json.loads(response.text) 22 | curr_weather = data["current"] 23 | hourly_forecast = data["hourly"] 24 | # print(json.dumps(curr_weather, indent=2)) 25 | daily_forecast = data["daily"] 26 | # print(json.dumps(forecast, indent=2)) 27 | results = {"current_weather": curr_weather, "hourly_forecast": hourly_forecast, "daily_forecast": daily_forecast} 28 | return results 29 | 30 | def get_weather(self, lat, lon, owm_api_key): 31 | current_weather, daily_forecast = {}, {} 32 | 33 | weather_results = self.get_owm_weather(lat, lon, owm_api_key) 34 | current_weather = weather_results["current_weather"] 35 | hourly_forecast = weather_results["hourly_forecast"] 36 | daily_forecast = weather_results["daily_forecast"] 37 | 38 | """ 39 | print("Current weather is %s, and the temperature is %s." % ( 40 | string.capwords(current_weather["weather"][0]["description"]), current_weather["temp"])) 41 | 42 | print("") 43 | dt = datetime.datetime.fromtimestamp(hourly_forecast[1]["dt"]) 44 | print("Next Hour: " + dt.strftime("%m/%d/%Y, %H:%M:%S")) 45 | print("Type: " + string.capwords(hourly_forecast[1]["weather"][0]["description"])) 46 | print("Temp: " + str(round(hourly_forecast[1]["temp"]))) 47 | print("Chance of Rain: " + str(hourly_forecast[1]["pop"] * 100) + "%") 48 | 49 | for i in range(3): 50 | print("") 51 | dt = datetime.datetime.fromtimestamp(daily_forecast[i]["dt"]) 52 | print("Date: " + dt.strftime("%m/%d/%Y, %H:%M:%S")) 53 | print("Type: " + string.capwords(daily_forecast[i]["weather"][0]["description"])) 54 | print("Min: " + str(round(daily_forecast[i]["temp"]["min"]))) 55 | print("Max: " + str(round(daily_forecast[i]["temp"]["max"]))) 56 | print("Chance of Rain: " + str(daily_forecast[i]["pop"] * 100) + "%") 57 | """ 58 | 59 | return current_weather, hourly_forecast, daily_forecast 60 | -------------------------------------------------------------------------------- /render/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/background.jpg -------------------------------------------------------------------------------- /render/css/bootstrap.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} 6 | /*# sourceMappingURL=bootstrap.min.css.map */ -------------------------------------------------------------------------------- /render/css/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Lexend-Regular"; 3 | src: url('../font/Lexend-Regular.ttf'); 4 | } 5 | 6 | @font-face { 7 | font-family: "Lexend-Light"; 8 | src: url('../font/Lexend-Light.ttf'); 9 | } 10 | 11 | @font-face { 12 | font-family: "TiltWarp-Regular"; 13 | src: url('../font/TiltWarp-Regular.ttf'); 14 | } 15 | 16 | h1, h2, p, span, .h1, .h2, .p, .span { 17 | font-family: "Lexend-Regular", sans-serif; 18 | } 19 | 20 | .list-unstyled { 21 | text-overflow: ellipsis; 22 | } 23 | 24 | .event-time { 25 | color: gray 26 | } 27 | 28 | .big-day { 29 | font-family: "TiltWarp-Regular", sans-serif; 30 | font-size: 18rem; 31 | } 32 | 33 | .event { 34 | max-width: 95%; 35 | font-family: "Lexend-Regular", sans-serif; 36 | font-size: 2.5rem; 37 | display: list-item; /* This has to be "list-item" */ 38 | list-style-type: disc; /* See https://developer.mozilla.org/en-US/docs/Web/CSS/list-style-type */ 39 | list-style-position: inside; 40 | white-space: nowrap; 41 | overflow: hidden; 42 | text-overflow: ellipsis; 43 | } 44 | 45 | .did-you-know { 46 | font-family: "Lexend-Light", sans-serif; 47 | font-size: 2.5rem; 48 | max-width: 95%; 49 | } 50 | 51 | .date-padding { 52 | padding-right:1; 53 | padding-left:0; 54 | padding-top:0; 55 | padding-bottom:0; 56 | } 57 | 58 | .add-padding { 59 | padding-right:10; 60 | padding-left:10; 61 | padding-top:0; 62 | padding-bottom:0; 63 | } -------------------------------------------------------------------------------- /render/css/weather-icons.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Weather Icons 2.0.10 3 | * Updated November 1, 2020 4 | * Weather themed icons for Bootstrap 5 | * Author - Erik Flowers - erik@helloerik.com 6 | * Email: erik@helloerik.com 7 | * Twitter: http://twitter.com/Erik_UX 8 | * ------------------------------------------------------------------------------ 9 | * Maintained at http://erikflowers.github.io/weather-icons 10 | * 11 | * License 12 | * ------------------------------------------------------------------------------ 13 | * - Font licensed under SIL OFL 1.1 - 14 | * http://scripts.sil.org/OFL 15 | * - CSS, SCSS and LESS are licensed under MIT License - 16 | * http://opensource.org/licenses/mit-license.html 17 | * - Documentation licensed under CC BY 3.0 - 18 | * http://creativecommons.org/licenses/by/3.0/ 19 | * - Inspired by and works great as a companion with Font Awesome 20 | * "Font Awesome by Dave Gandy - http://fontawesome.io" 21 | */@font-face{font-family:'weathericons';src:url('../font/weathericons-regular-webfont.eot');src:url('../font/weathericons-regular-webfont.eot?#iefix') format('embedded-opentype'),url('../font/weathericons-regular-webfont.woff2') format('woff2'),url('../font/weathericons-regular-webfont.woff') format('woff'),url('../font/weathericons-regular-webfont.ttf') format('truetype'),url('../font/weathericons-regular-webfont.svg#weather_iconsregular') format('svg');font-weight:normal;font-style:normal}.wi{display:inline-block;font-family:'weathericons';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.wi-fw{text-align:center;width:1.4em}.wi-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.wi-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.wi-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.wi-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.wi-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}.wi-day-sunny:before{content:"\f00d"}.wi-day-cloudy:before{content:"\f002"}.wi-day-cloudy-gusts:before{content:"\f000"}.wi-day-cloudy-windy:before{content:"\f001"}.wi-day-fog:before{content:"\f003"}.wi-day-hail:before{content:"\f004"}.wi-day-haze:before{content:"\f0b6"}.wi-day-lightning:before{content:"\f005"}.wi-day-rain:before{content:"\f008"}.wi-day-rain-mix:before{content:"\f006"}.wi-day-rain-wind:before{content:"\f007"}.wi-day-showers:before{content:"\f009"}.wi-day-sleet:before{content:"\f0b2"}.wi-day-sleet-storm:before{content:"\f068"}.wi-day-snow:before{content:"\f00a"}.wi-day-snow-thunderstorm:before{content:"\f06b"}.wi-day-snow-wind:before{content:"\f065"}.wi-day-sprinkle:before{content:"\f00b"}.wi-day-storm-showers:before{content:"\f00e"}.wi-day-sunny-overcast:before{content:"\f00c"}.wi-day-thunderstorm:before{content:"\f010"}.wi-day-windy:before{content:"\f085"}.wi-solar-eclipse:before{content:"\f06e"}.wi-hot:before{content:"\f072"}.wi-day-cloudy-high:before{content:"\f07d"}.wi-day-light-wind:before{content:"\f0c4"}.wi-night-clear:before{content:"\f02e"}.wi-night-alt-cloudy:before{content:"\f086"}.wi-night-alt-cloudy-gusts:before{content:"\f022"}.wi-night-alt-cloudy-windy:before{content:"\f023"}.wi-night-alt-hail:before{content:"\f024"}.wi-night-alt-lightning:before{content:"\f025"}.wi-night-alt-rain:before{content:"\f028"}.wi-night-alt-rain-mix:before{content:"\f026"}.wi-night-alt-rain-wind:before{content:"\f027"}.wi-night-alt-showers:before{content:"\f029"}.wi-night-alt-sleet:before{content:"\f0b4"}.wi-night-alt-sleet-storm:before{content:"\f06a"}.wi-night-alt-snow:before{content:"\f02a"}.wi-night-alt-snow-thunderstorm:before{content:"\f06d"}.wi-night-alt-snow-wind:before{content:"\f067"}.wi-night-alt-sprinkle:before{content:"\f02b"}.wi-night-alt-storm-showers:before{content:"\f02c"}.wi-night-alt-thunderstorm:before{content:"\f02d"}.wi-night-cloudy:before{content:"\f031"}.wi-night-cloudy-gusts:before{content:"\f02f"}.wi-night-cloudy-windy:before{content:"\f030"}.wi-night-fog:before{content:"\f04a"}.wi-night-hail:before{content:"\f032"}.wi-night-lightning:before{content:"\f033"}.wi-night-partly-cloudy:before{content:"\f083"}.wi-night-rain:before{content:"\f036"}.wi-night-rain-mix:before{content:"\f034"}.wi-night-rain-wind:before{content:"\f035"}.wi-night-showers:before{content:"\f037"}.wi-night-sleet:before{content:"\f0b3"}.wi-night-sleet-storm:before{content:"\f069"}.wi-night-snow:before{content:"\f038"}.wi-night-snow-thunderstorm:before{content:"\f06c"}.wi-night-snow-wind:before{content:"\f066"}.wi-night-sprinkle:before{content:"\f039"}.wi-night-storm-showers:before{content:"\f03a"}.wi-night-thunderstorm:before{content:"\f03b"}.wi-lunar-eclipse:before{content:"\f070"}.wi-stars:before{content:"\f077"}.wi-storm-showers:before{content:"\f01d"}.wi-thunderstorm:before{content:"\f01e"}.wi-night-alt-cloudy-high:before{content:"\f07e"}.wi-night-cloudy-high:before{content:"\f080"}.wi-night-alt-partly-cloudy:before{content:"\f081"}.wi-cloud:before{content:"\f041"}.wi-cloudy:before{content:"\f013"}.wi-cloudy-gusts:before{content:"\f011"}.wi-cloudy-windy:before{content:"\f012"}.wi-fog:before{content:"\f014"}.wi-hail:before{content:"\f015"}.wi-rain:before{content:"\f019"}.wi-rain-mix:before{content:"\f017"}.wi-rain-wind:before{content:"\f018"}.wi-showers:before{content:"\f01a"}.wi-sleet:before{content:"\f0b5"}.wi-snow:before{content:"\f01b"}.wi-sprinkle:before{content:"\f01c"}.wi-storm-showers:before{content:"\f01d"}.wi-thunderstorm:before{content:"\f01e"}.wi-snow-wind:before{content:"\f064"}.wi-snow:before{content:"\f01b"}.wi-smog:before{content:"\f074"}.wi-smoke:before{content:"\f062"}.wi-lightning:before{content:"\f016"}.wi-raindrops:before{content:"\f04e"}.wi-raindrop:before{content:"\f078"}.wi-dust:before{content:"\f063"}.wi-snowflake-cold:before{content:"\f076"}.wi-windy:before{content:"\f021"}.wi-strong-wind:before{content:"\f050"}.wi-sandstorm:before{content:"\f082"}.wi-earthquake:before{content:"\f0c6"}.wi-fire:before{content:"\f0c7"}.wi-flood:before{content:"\f07c"}.wi-meteor:before{content:"\f071"}.wi-tsunami:before{content:"\f0c5"}.wi-volcano:before{content:"\f0c8"}.wi-hurricane:before{content:"\f073"}.wi-tornado:before{content:"\f056"}.wi-small-craft-advisory:before{content:"\f0cc"}.wi-gale-warning:before{content:"\f0cd"}.wi-storm-warning:before{content:"\f0ce"}.wi-hurricane-warning:before{content:"\f0cf"}.wi-wind-direction:before{content:"\f0b1"}.wi-alien:before{content:"\f075"}.wi-celsius:before{content:"\f03c"}.wi-fahrenheit:before{content:"\f045"}.wi-degrees:before{content:"\f042"}.wi-thermometer:before{content:"\f055"}.wi-thermometer-exterior:before{content:"\f053"}.wi-thermometer-internal:before{content:"\f054"}.wi-cloud-down:before{content:"\f03d"}.wi-cloud-up:before{content:"\f040"}.wi-cloud-refresh:before{content:"\f03e"}.wi-horizon:before{content:"\f047"}.wi-horizon-alt:before{content:"\f046"}.wi-sunrise:before{content:"\f051"}.wi-sunset:before{content:"\f052"}.wi-moonrise:before{content:"\f0c9"}.wi-moonset:before{content:"\f0ca"}.wi-refresh:before{content:"\f04c"}.wi-refresh-alt:before{content:"\f04b"}.wi-umbrella:before{content:"\f084"}.wi-barometer:before{content:"\f079"}.wi-humidity:before{content:"\f07a"}.wi-na:before{content:"\f07b"}.wi-train:before{content:"\f0cb"}.wi-moon-new:before{content:"\f095"}.wi-moon-waxing-crescent-1:before{content:"\f096"}.wi-moon-waxing-crescent-2:before{content:"\f097"}.wi-moon-waxing-crescent-3:before{content:"\f098"}.wi-moon-waxing-crescent-4:before{content:"\f099"}.wi-moon-waxing-crescent-5:before{content:"\f09a"}.wi-moon-waxing-crescent-6:before{content:"\f09b"}.wi-moon-first-quarter:before{content:"\f09c"}.wi-moon-waxing-gibbous-1:before{content:"\f09d"}.wi-moon-waxing-gibbous-2:before{content:"\f09e"}.wi-moon-waxing-gibbous-3:before{content:"\f09f"}.wi-moon-waxing-gibbous-4:before{content:"\f0a0"}.wi-moon-waxing-gibbous-5:before{content:"\f0a1"}.wi-moon-waxing-gibbous-6:before{content:"\f0a2"}.wi-moon-full:before{content:"\f0a3"}.wi-moon-waning-gibbous-1:before{content:"\f0a4"}.wi-moon-waning-gibbous-2:before{content:"\f0a5"}.wi-moon-waning-gibbous-3:before{content:"\f0a6"}.wi-moon-waning-gibbous-4:before{content:"\f0a7"}.wi-moon-waning-gibbous-5:before{content:"\f0a8"}.wi-moon-waning-gibbous-6:before{content:"\f0a9"}.wi-moon-third-quarter:before{content:"\f0aa"}.wi-moon-waning-crescent-1:before{content:"\f0ab"}.wi-moon-waning-crescent-2:before{content:"\f0ac"}.wi-moon-waning-crescent-3:before{content:"\f0ad"}.wi-moon-waning-crescent-4:before{content:"\f0ae"}.wi-moon-waning-crescent-5:before{content:"\f0af"}.wi-moon-waning-crescent-6:before{content:"\f0b0"}.wi-moon-alt-new:before{content:"\f0eb"}.wi-moon-alt-waxing-crescent-1:before{content:"\f0d0"}.wi-moon-alt-waxing-crescent-2:before{content:"\f0d1"}.wi-moon-alt-waxing-crescent-3:before{content:"\f0d2"}.wi-moon-alt-waxing-crescent-4:before{content:"\f0d3"}.wi-moon-alt-waxing-crescent-5:before{content:"\f0d4"}.wi-moon-alt-waxing-crescent-6:before{content:"\f0d5"}.wi-moon-alt-first-quarter:before{content:"\f0d6"}.wi-moon-alt-waxing-gibbous-1:before{content:"\f0d7"}.wi-moon-alt-waxing-gibbous-2:before{content:"\f0d8"}.wi-moon-alt-waxing-gibbous-3:before{content:"\f0d9"}.wi-moon-alt-waxing-gibbous-4:before{content:"\f0da"}.wi-moon-alt-waxing-gibbous-5:before{content:"\f0db"}.wi-moon-alt-waxing-gibbous-6:before{content:"\f0dc"}.wi-moon-alt-full:before{content:"\f0dd"}.wi-moon-alt-waning-gibbous-1:before{content:"\f0de"}.wi-moon-alt-waning-gibbous-2:before{content:"\f0df"}.wi-moon-alt-waning-gibbous-3:before{content:"\f0e0"}.wi-moon-alt-waning-gibbous-4:before{content:"\f0e1"}.wi-moon-alt-waning-gibbous-5:before{content:"\f0e2"}.wi-moon-alt-waning-gibbous-6:before{content:"\f0e3"}.wi-moon-alt-third-quarter:before{content:"\f0e4"}.wi-moon-alt-waning-crescent-1:before{content:"\f0e5"}.wi-moon-alt-waning-crescent-2:before{content:"\f0e6"}.wi-moon-alt-waning-crescent-3:before{content:"\f0e7"}.wi-moon-alt-waning-crescent-4:before{content:"\f0e8"}.wi-moon-alt-waning-crescent-5:before{content:"\f0e9"}.wi-moon-alt-waning-crescent-6:before{content:"\f0ea"}.wi-moon-0:before{content:"\f095"}.wi-moon-1:before{content:"\f096"}.wi-moon-2:before{content:"\f097"}.wi-moon-3:before{content:"\f098"}.wi-moon-4:before{content:"\f099"}.wi-moon-5:before{content:"\f09a"}.wi-moon-6:before{content:"\f09b"}.wi-moon-7:before{content:"\f09c"}.wi-moon-8:before{content:"\f09d"}.wi-moon-9:before{content:"\f09e"}.wi-moon-10:before{content:"\f09f"}.wi-moon-11:before{content:"\f0a0"}.wi-moon-12:before{content:"\f0a1"}.wi-moon-13:before{content:"\f0a2"}.wi-moon-14:before{content:"\f0a3"}.wi-moon-15:before{content:"\f0a4"}.wi-moon-16:before{content:"\f0a5"}.wi-moon-17:before{content:"\f0a6"}.wi-moon-18:before{content:"\f0a7"}.wi-moon-19:before{content:"\f0a8"}.wi-moon-20:before{content:"\f0a9"}.wi-moon-21:before{content:"\f0aa"}.wi-moon-22:before{content:"\f0ab"}.wi-moon-23:before{content:"\f0ac"}.wi-moon-24:before{content:"\f0ad"}.wi-moon-25:before{content:"\f0ae"}.wi-moon-26:before{content:"\f0af"}.wi-moon-27:before{content:"\f0b0"}.wi-time-1:before{content:"\f08a"}.wi-time-2:before{content:"\f08b"}.wi-time-3:before{content:"\f08c"}.wi-time-4:before{content:"\f08d"}.wi-time-5:before{content:"\f08e"}.wi-time-6:before{content:"\f08f"}.wi-time-7:before{content:"\f090"}.wi-time-8:before{content:"\f091"}.wi-time-9:before{content:"\f092"}.wi-time-10:before{content:"\f093"}.wi-time-11:before{content:"\f094"}.wi-time-12:before{content:"\f089"}.wi-direction-up:before{content:"\f058"}.wi-direction-up-right:before{content:"\f057"}.wi-direction-right:before{content:"\f04d"}.wi-direction-down-right:before{content:"\f088"}.wi-direction-down:before{content:"\f044"}.wi-direction-down-left:before{content:"\f043"}.wi-direction-left:before{content:"\f048"}.wi-direction-up-left:before{content:"\f087"}.wi-wind-beaufort-0:before{content:"\f0b7"}.wi-wind-beaufort-1:before{content:"\f0b8"}.wi-wind-beaufort-2:before{content:"\f0b9"}.wi-wind-beaufort-3:before{content:"\f0ba"}.wi-wind-beaufort-4:before{content:"\f0bb"}.wi-wind-beaufort-5:before{content:"\f0bc"}.wi-wind-beaufort-6:before{content:"\f0bd"}.wi-wind-beaufort-7:before{content:"\f0be"}.wi-wind-beaufort-8:before{content:"\f0bf"}.wi-wind-beaufort-9:before{content:"\f0c0"}.wi-wind-beaufort-10:before{content:"\f0c1"}.wi-wind-beaufort-11:before{content:"\f0c2"}.wi-wind-beaufort-12:before{content:"\f0c3"}.wi-yahoo-0:before{content:"\f056"}.wi-yahoo-1:before{content:"\f00e"}.wi-yahoo-2:before{content:"\f073"}.wi-yahoo-3:before{content:"\f01e"}.wi-yahoo-4:before{content:"\f01e"}.wi-yahoo-5:before{content:"\f017"}.wi-yahoo-6:before{content:"\f017"}.wi-yahoo-7:before{content:"\f017"}.wi-yahoo-8:before{content:"\f015"}.wi-yahoo-9:before{content:"\f01a"}.wi-yahoo-10:before{content:"\f015"}.wi-yahoo-11:before{content:"\f01a"}.wi-yahoo-12:before{content:"\f01a"}.wi-yahoo-13:before{content:"\f01b"}.wi-yahoo-14:before{content:"\f00a"}.wi-yahoo-15:before{content:"\f064"}.wi-yahoo-16:before{content:"\f01b"}.wi-yahoo-17:before{content:"\f015"}.wi-yahoo-18:before{content:"\f017"}.wi-yahoo-19:before{content:"\f063"}.wi-yahoo-20:before{content:"\f014"}.wi-yahoo-21:before{content:"\f021"}.wi-yahoo-22:before{content:"\f062"}.wi-yahoo-23:before{content:"\f050"}.wi-yahoo-24:before{content:"\f050"}.wi-yahoo-25:before{content:"\f076"}.wi-yahoo-26:before{content:"\f013"}.wi-yahoo-27:before{content:"\f031"}.wi-yahoo-28:before{content:"\f002"}.wi-yahoo-29:before{content:"\f031"}.wi-yahoo-30:before{content:"\f002"}.wi-yahoo-31:before{content:"\f02e"}.wi-yahoo-32:before{content:"\f00d"}.wi-yahoo-33:before{content:"\f083"}.wi-yahoo-34:before{content:"\f00c"}.wi-yahoo-35:before{content:"\f017"}.wi-yahoo-36:before{content:"\f072"}.wi-yahoo-37:before{content:"\f00e"}.wi-yahoo-38:before{content:"\f00e"}.wi-yahoo-39:before{content:"\f00e"}.wi-yahoo-40:before{content:"\f01a"}.wi-yahoo-41:before{content:"\f064"}.wi-yahoo-42:before{content:"\f01b"}.wi-yahoo-43:before{content:"\f064"}.wi-yahoo-44:before{content:"\f00c"}.wi-yahoo-45:before{content:"\f00e"}.wi-yahoo-46:before{content:"\f01b"}.wi-yahoo-47:before{content:"\f00e"}.wi-yahoo-3200:before{content:"\f077"}.wi-forecast-io-clear-day:before{content:"\f00d"}.wi-forecast-io-clear-night:before{content:"\f02e"}.wi-forecast-io-rain:before{content:"\f019"}.wi-forecast-io-snow:before{content:"\f01b"}.wi-forecast-io-sleet:before{content:"\f0b5"}.wi-forecast-io-wind:before{content:"\f050"}.wi-forecast-io-fog:before{content:"\f014"}.wi-forecast-io-cloudy:before{content:"\f013"}.wi-forecast-io-partly-cloudy-day:before{content:"\f002"}.wi-forecast-io-partly-cloudy-night:before{content:"\f031"}.wi-forecast-io-hail:before{content:"\f015"}.wi-forecast-io-thunderstorm:before{content:"\f01e"}.wi-forecast-io-tornado:before{content:"\f056"}.wi-wmo4680-0:before,.wi-wmo4680-00:before{content:"\f055"}.wi-wmo4680-1:before,.wi-wmo4680-01:before{content:"\f013"}.wi-wmo4680-2:before,.wi-wmo4680-02:before{content:"\f055"}.wi-wmo4680-3:before,.wi-wmo4680-03:before{content:"\f013"}.wi-wmo4680-4:before,.wi-wmo4680-04:before{content:"\f014"}.wi-wmo4680-5:before,.wi-wmo4680-05:before{content:"\f014"}.wi-wmo4680-10:before{content:"\f014"}.wi-wmo4680-11:before{content:"\f014"}.wi-wmo4680-12:before{content:"\f016"}.wi-wmo4680-18:before{content:"\f050"}.wi-wmo4680-20:before{content:"\f014"}.wi-wmo4680-21:before{content:"\f017"}.wi-wmo4680-22:before{content:"\f017"}.wi-wmo4680-23:before{content:"\f019"}.wi-wmo4680-24:before{content:"\f01b"}.wi-wmo4680-25:before{content:"\f015"}.wi-wmo4680-26:before{content:"\f01e"}.wi-wmo4680-27:before{content:"\f063"}.wi-wmo4680-28:before{content:"\f063"}.wi-wmo4680-29:before{content:"\f063"}.wi-wmo4680-30:before{content:"\f014"}.wi-wmo4680-31:before{content:"\f014"}.wi-wmo4680-32:before{content:"\f014"}.wi-wmo4680-33:before{content:"\f014"}.wi-wmo4680-34:before{content:"\f014"}.wi-wmo4680-35:before{content:"\f014"}.wi-wmo4680-40:before{content:"\f017"}.wi-wmo4680-41:before{content:"\f01c"}.wi-wmo4680-42:before{content:"\f019"}.wi-wmo4680-43:before{content:"\f01c"}.wi-wmo4680-44:before{content:"\f019"}.wi-wmo4680-45:before{content:"\f015"}.wi-wmo4680-46:before{content:"\f015"}.wi-wmo4680-47:before{content:"\f01b"}.wi-wmo4680-48:before{content:"\f01b"}.wi-wmo4680-50:before{content:"\f01c"}.wi-wmo4680-51:before{content:"\f01c"}.wi-wmo4680-52:before{content:"\f019"}.wi-wmo4680-53:before{content:"\f019"}.wi-wmo4680-54:before{content:"\f076"}.wi-wmo4680-55:before{content:"\f076"}.wi-wmo4680-56:before{content:"\f076"}.wi-wmo4680-57:before{content:"\f01c"}.wi-wmo4680-58:before{content:"\f019"}.wi-wmo4680-60:before{content:"\f01c"}.wi-wmo4680-61:before{content:"\f01c"}.wi-wmo4680-62:before{content:"\f019"}.wi-wmo4680-63:before{content:"\f019"}.wi-wmo4680-64:before{content:"\f015"}.wi-wmo4680-65:before{content:"\f015"}.wi-wmo4680-66:before{content:"\f015"}.wi-wmo4680-67:before{content:"\f017"}.wi-wmo4680-68:before{content:"\f017"}.wi-wmo4680-70:before{content:"\f01b"}.wi-wmo4680-71:before{content:"\f01b"}.wi-wmo4680-72:before{content:"\f01b"}.wi-wmo4680-73:before{content:"\f01b"}.wi-wmo4680-74:before{content:"\f076"}.wi-wmo4680-75:before{content:"\f076"}.wi-wmo4680-76:before{content:"\f076"}.wi-wmo4680-77:before{content:"\f01b"}.wi-wmo4680-78:before{content:"\f076"}.wi-wmo4680-80:before{content:"\f019"}.wi-wmo4680-81:before{content:"\f01c"}.wi-wmo4680-82:before{content:"\f019"}.wi-wmo4680-83:before{content:"\f019"}.wi-wmo4680-84:before{content:"\f01d"}.wi-wmo4680-85:before{content:"\f017"}.wi-wmo4680-86:before{content:"\f017"}.wi-wmo4680-87:before{content:"\f017"}.wi-wmo4680-89:before{content:"\f015"}.wi-wmo4680-90:before{content:"\f016"}.wi-wmo4680-91:before{content:"\f01d"}.wi-wmo4680-92:before{content:"\f01e"}.wi-wmo4680-93:before{content:"\f01e"}.wi-wmo4680-94:before{content:"\f016"}.wi-wmo4680-95:before{content:"\f01e"}.wi-wmo4680-96:before{content:"\f01e"}.wi-wmo4680-99:before{content:"\f056"}.wi-owm-200:before{content:"\f01e"}.wi-owm-201:before{content:"\f01e"}.wi-owm-202:before{content:"\f01e"}.wi-owm-210:before{content:"\f016"}.wi-owm-211:before{content:"\f016"}.wi-owm-212:before{content:"\f016"}.wi-owm-221:before{content:"\f016"}.wi-owm-230:before{content:"\f01e"}.wi-owm-231:before{content:"\f01e"}.wi-owm-232:before{content:"\f01e"}.wi-owm-300:before{content:"\f01c"}.wi-owm-301:before{content:"\f01c"}.wi-owm-302:before{content:"\f019"}.wi-owm-310:before{content:"\f017"}.wi-owm-311:before{content:"\f019"}.wi-owm-312:before{content:"\f019"}.wi-owm-313:before{content:"\f01a"}.wi-owm-314:before{content:"\f019"}.wi-owm-321:before{content:"\f01c"}.wi-owm-500:before{content:"\f01c"}.wi-owm-501:before{content:"\f019"}.wi-owm-502:before{content:"\f019"}.wi-owm-503:before{content:"\f019"}.wi-owm-504:before{content:"\f019"}.wi-owm-511:before{content:"\f017"}.wi-owm-520:before{content:"\f01a"}.wi-owm-521:before{content:"\f01a"}.wi-owm-522:before{content:"\f01a"}.wi-owm-531:before{content:"\f01d"}.wi-owm-600:before{content:"\f01b"}.wi-owm-601:before{content:"\f01b"}.wi-owm-602:before{content:"\f0b5"}.wi-owm-611:before{content:"\f017"}.wi-owm-612:before{content:"\f017"}.wi-owm-615:before{content:"\f017"}.wi-owm-616:before{content:"\f017"}.wi-owm-620:before{content:"\f017"}.wi-owm-621:before{content:"\f01b"}.wi-owm-622:before{content:"\f01b"}.wi-owm-701:before{content:"\f014"}.wi-owm-711:before{content:"\f062"}.wi-owm-721:before{content:"\f0b6"}.wi-owm-731:before{content:"\f063"}.wi-owm-741:before{content:"\f014"}.wi-owm-761:before{content:"\f063"}.wi-owm-762:before{content:"\f063"}.wi-owm-771:before{content:"\f011"}.wi-owm-781:before{content:"\f056"}.wi-owm-800:before{content:"\f00d"}.wi-owm-801:before{content:"\f041"}.wi-owm-802:before{content:"\f041"}.wi-owm-803:before{content:"\f013"}.wi-owm-804:before{content:"\f013"}.wi-owm-900:before{content:"\f056"}.wi-owm-901:before{content:"\f01d"}.wi-owm-902:before{content:"\f073"}.wi-owm-903:before{content:"\f076"}.wi-owm-904:before{content:"\f072"}.wi-owm-905:before{content:"\f021"}.wi-owm-906:before{content:"\f015"}.wi-owm-957:before{content:"\f050"}.wi-owm-day-200:before{content:"\f010"}.wi-owm-day-201:before{content:"\f010"}.wi-owm-day-202:before{content:"\f010"}.wi-owm-day-210:before{content:"\f005"}.wi-owm-day-211:before{content:"\f005"}.wi-owm-day-212:before{content:"\f005"}.wi-owm-day-221:before{content:"\f005"}.wi-owm-day-230:before{content:"\f010"}.wi-owm-day-231:before{content:"\f010"}.wi-owm-day-232:before{content:"\f010"}.wi-owm-day-300:before{content:"\f00b"}.wi-owm-day-301:before{content:"\f00b"}.wi-owm-day-302:before{content:"\f008"}.wi-owm-day-310:before{content:"\f008"}.wi-owm-day-311:before{content:"\f008"}.wi-owm-day-312:before{content:"\f008"}.wi-owm-day-313:before{content:"\f008"}.wi-owm-day-314:before{content:"\f008"}.wi-owm-day-321:before{content:"\f00b"}.wi-owm-day-500:before{content:"\f00b"}.wi-owm-day-501:before{content:"\f008"}.wi-owm-day-502:before{content:"\f008"}.wi-owm-day-503:before{content:"\f008"}.wi-owm-day-504:before{content:"\f008"}.wi-owm-day-511:before{content:"\f006"}.wi-owm-day-520:before{content:"\f009"}.wi-owm-day-521:before{content:"\f009"}.wi-owm-day-522:before{content:"\f009"}.wi-owm-day-531:before{content:"\f00e"}.wi-owm-day-600:before{content:"\f00a"}.wi-owm-day-601:before{content:"\f0b2"}.wi-owm-day-602:before{content:"\f00a"}.wi-owm-day-611:before{content:"\f006"}.wi-owm-day-612:before{content:"\f006"}.wi-owm-day-615:before{content:"\f006"}.wi-owm-day-616:before{content:"\f006"}.wi-owm-day-620:before{content:"\f006"}.wi-owm-day-621:before{content:"\f00a"}.wi-owm-day-622:before{content:"\f00a"}.wi-owm-day-701:before{content:"\f003"}.wi-owm-day-711:before{content:"\f062"}.wi-owm-day-721:before{content:"\f0b6"}.wi-owm-day-731:before{content:"\f063"}.wi-owm-day-741:before{content:"\f003"}.wi-owm-day-761:before{content:"\f063"}.wi-owm-day-762:before{content:"\f063"}.wi-owm-day-781:before{content:"\f056"}.wi-owm-day-800:before{content:"\f00d"}.wi-owm-day-801:before{content:"\f002"}.wi-owm-day-802:before{content:"\f002"}.wi-owm-day-803:before{content:"\f013"}.wi-owm-day-804:before{content:"\f013"}.wi-owm-day-900:before{content:"\f056"}.wi-owm-day-902:before{content:"\f073"}.wi-owm-day-903:before{content:"\f076"}.wi-owm-day-904:before{content:"\f072"}.wi-owm-day-906:before{content:"\f004"}.wi-owm-day-957:before{content:"\f050"}.wi-owm-night-200:before{content:"\f02d"}.wi-owm-night-201:before{content:"\f02d"}.wi-owm-night-202:before{content:"\f02d"}.wi-owm-night-210:before{content:"\f025"}.wi-owm-night-211:before{content:"\f025"}.wi-owm-night-212:before{content:"\f025"}.wi-owm-night-221:before{content:"\f025"}.wi-owm-night-230:before{content:"\f02d"}.wi-owm-night-231:before{content:"\f02d"}.wi-owm-night-232:before{content:"\f02d"}.wi-owm-night-300:before{content:"\f02b"}.wi-owm-night-301:before{content:"\f02b"}.wi-owm-night-302:before{content:"\f028"}.wi-owm-night-310:before{content:"\f028"}.wi-owm-night-311:before{content:"\f028"}.wi-owm-night-312:before{content:"\f028"}.wi-owm-night-313:before{content:"\f028"}.wi-owm-night-314:before{content:"\f028"}.wi-owm-night-321:before{content:"\f02b"}.wi-owm-night-500:before{content:"\f02b"}.wi-owm-night-501:before{content:"\f028"}.wi-owm-night-502:before{content:"\f028"}.wi-owm-night-503:before{content:"\f028"}.wi-owm-night-504:before{content:"\f028"}.wi-owm-night-511:before{content:"\f026"}.wi-owm-night-520:before{content:"\f029"}.wi-owm-night-521:before{content:"\f029"}.wi-owm-night-522:before{content:"\f029"}.wi-owm-night-531:before{content:"\f02c"}.wi-owm-night-600:before{content:"\f02a"}.wi-owm-night-601:before{content:"\f0b4"}.wi-owm-night-602:before{content:"\f02a"}.wi-owm-night-611:before{content:"\f026"}.wi-owm-night-612:before{content:"\f026"}.wi-owm-night-615:before{content:"\f026"}.wi-owm-night-616:before{content:"\f026"}.wi-owm-night-620:before{content:"\f026"}.wi-owm-night-621:before{content:"\f02a"}.wi-owm-night-622:before{content:"\f02a"}.wi-owm-night-701:before{content:"\f04a"}.wi-owm-night-711:before{content:"\f062"}.wi-owm-night-721:before{content:"\f0b6"}.wi-owm-night-731:before{content:"\f063"}.wi-owm-night-741:before{content:"\f04a"}.wi-owm-night-761:before{content:"\f063"}.wi-owm-night-762:before{content:"\f063"}.wi-owm-night-781:before{content:"\f056"}.wi-owm-night-800:before{content:"\f02e"}.wi-owm-night-801:before{content:"\f081"}.wi-owm-night-802:before{content:"\f086"}.wi-owm-night-803:before{content:"\f013"}.wi-owm-night-804:before{content:"\f013"}.wi-owm-night-900:before{content:"\f056"}.wi-owm-night-902:before{content:"\f073"}.wi-owm-night-903:before{content:"\f076"}.wi-owm-night-904:before{content:"\f072"}.wi-owm-night-906:before{content:"\f024"}.wi-owm-night-957:before{content:"\f050"}.wi-wu-chanceflurries:before{content:"\f064"}.wi-wu-chancerain:before{content:"\f019"}.wi-wu-chancesleat:before{content:"\f0b5"}.wi-wu-chancesnow:before{content:"\f01b"}.wi-wu-chancetstorms:before{content:"\f01e"}.wi-wu-clear:before{content:"\f00d"}.wi-wu-cloudy:before{content:"\f002"}.wi-wu-flurries:before{content:"\f064"}.wi-wu-hazy:before{content:"\f0b6"}.wi-wu-mostlycloudy:before{content:"\f002"}.wi-wu-mostlysunny:before{content:"\f00d"}.wi-wu-partlycloudy:before{content:"\f002"}.wi-wu-partlysunny:before{content:"\f00d"}.wi-wu-rain:before{content:"\f01a"}.wi-wu-sleat:before{content:"\f0b5"}.wi-wu-snow:before{content:"\f01b"}.wi-wu-sunny:before{content:"\f00d"}.wi-wu-tstorms:before{content:"\f01e"}.wi-wu-unknown:before{content:"\f00d"}/*# sourceMappingURL=weather-icons.min.css.map */ -------------------------------------------------------------------------------- /render/dashboard_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |

{day}

22 |
23 |
24 |
25 |
26 |
27 |

{weekday}
{month}

28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | 36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |

{current_weather_text} | {current_weather_temp}°

44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | 54 |
55 |
56 |
57 |
58 |

Today
{today_weather_pop}% | {today_weather_min}-{today_weather_max}°

59 |
60 |
61 |
62 |
63 |
64 |
65 | 66 |
67 |
68 |
69 |
70 |

{tomorrow}
{tomorrow_weather_pop}% | {tomorrow_weather_min}-{tomorrow_weather_max}°

71 |
72 |
73 |
74 |
75 |
76 |
77 | 78 |
79 |
80 |
81 |
82 |

{dayafter}
{dayafter_weather_pop}% | {dayafter_weather_min}-{dayafter_weather_max}°

83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |

Today

98 |
    99 | {events_today} 100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |

{tomorrow}

109 |
    110 | {events_tomorrow} 111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |

{dayafter}

120 |
    121 | {events_dayafter} 122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |

{topic_title}

131 |
{topic_text}
132 |
133 |
134 |
135 |
136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /render/font/Lexend-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/Lexend-Black.ttf -------------------------------------------------------------------------------- /render/font/Lexend-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/Lexend-Bold.ttf -------------------------------------------------------------------------------- /render/font/Lexend-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/Lexend-ExtraBold.ttf -------------------------------------------------------------------------------- /render/font/Lexend-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/Lexend-ExtraLight.ttf -------------------------------------------------------------------------------- /render/font/Lexend-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/Lexend-Light.ttf -------------------------------------------------------------------------------- /render/font/Lexend-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/Lexend-Medium.ttf -------------------------------------------------------------------------------- /render/font/Lexend-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/Lexend-Regular.ttf -------------------------------------------------------------------------------- /render/font/Lexend-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/Lexend-SemiBold.ttf -------------------------------------------------------------------------------- /render/font/Lexend-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/Lexend-Thin.ttf -------------------------------------------------------------------------------- /render/font/TiltWarp-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/TiltWarp-Regular.ttf -------------------------------------------------------------------------------- /render/font/weathericons-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/weathericons-regular-webfont.eot -------------------------------------------------------------------------------- /render/font/weathericons-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/weathericons-regular-webfont.ttf -------------------------------------------------------------------------------- /render/font/weathericons-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/weathericons-regular-webfont.woff -------------------------------------------------------------------------------- /render/font/weathericons-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speedyg0nz/MagInkDash/d907d35550805a93b9cc835532e9b3958fe8cd48/render/font/weathericons-regular-webfont.woff2 -------------------------------------------------------------------------------- /render/render.py: -------------------------------------------------------------------------------- 1 | """ 2 | This script essentially generates a HTML file of the calendar I wish to display. It then fires up a headless Chrome 3 | instance, sized to the resolution of the eInk display and takes a screenshot. 4 | 5 | This might sound like a convoluted way to generate the calendar, but I'm doing so mainly because (i) it's easier to 6 | format the calendar exactly the way I want it using HTML/CSS, and (ii) I can delink the generation of the 7 | calendar and refreshing of the eInk display. 8 | """ 9 | 10 | from selenium import webdriver 11 | from selenium.webdriver.chrome.options import Options 12 | from time import sleep 13 | from datetime import timedelta 14 | import pathlib 15 | import string 16 | from PIL import Image 17 | import logging 18 | from selenium.webdriver.common.by import By 19 | 20 | 21 | class RenderHelper: 22 | 23 | def __init__(self, width, height, angle): 24 | self.logger = logging.getLogger('maginkdash') 25 | self.currPath = str(pathlib.Path(__file__).parent.absolute()) 26 | self.htmlFile = 'file://' + self.currPath + '/dashboard.html' 27 | self.imageWidth = width 28 | self.imageHeight = height 29 | self.rotateAngle = angle 30 | 31 | def set_viewport_size(self, driver): 32 | 33 | # Extract the current window size from the driver 34 | current_window_size = driver.get_window_size() 35 | 36 | # Extract the client window size from the html tag 37 | html = driver.find_element(By.TAG_NAME,'html') 38 | inner_width = int(html.get_attribute("clientWidth")) 39 | inner_height = int(html.get_attribute("clientHeight")) 40 | 41 | # "Internal width you want to set+Set "outer frame width" to window size 42 | target_width = self.imageWidth + (current_window_size["width"] - inner_width) 43 | target_height = self.imageHeight + (current_window_size["height"] - inner_height) 44 | 45 | driver.set_window_rect( 46 | width=target_width, 47 | height=target_height) 48 | 49 | def get_screenshot(self, path_to_server_image): 50 | opts = Options() 51 | opts.add_argument("--headless") 52 | opts.add_argument("--hide-scrollbars"); 53 | opts.add_argument('--force-device-scale-factor=1') 54 | driver = webdriver.Chrome(options=opts) 55 | self.set_viewport_size(driver) 56 | driver.get(self.htmlFile) 57 | sleep(1) 58 | driver.get_screenshot_as_file(self.currPath + '/dashboard.png') 59 | driver.get_screenshot_as_file(path_to_server_image) 60 | self.logger.info('Screenshot captured and saved to file.') 61 | 62 | def get_short_time(self, datetimeObj, is24hour=False): 63 | datetime_str = '' 64 | if is24hour: 65 | datetime_str = '{}:{:02d}'.format(datetimeObj.hour, datetimeObj.minute) 66 | else: 67 | if datetimeObj.minute > 0: 68 | datetime_str = '.{:02d}'.format(datetimeObj.minute) 69 | 70 | if datetimeObj.hour == 0: 71 | datetime_str = '12{}am'.format(datetime_str) 72 | elif datetimeObj.hour == 12: 73 | datetime_str = '12{}pm'.format(datetime_str) 74 | elif datetimeObj.hour > 12: 75 | datetime_str = '{}{}pm'.format(str(datetimeObj.hour % 12), datetime_str) 76 | else: 77 | datetime_str = '{}{}am'.format(str(datetimeObj.hour), datetime_str) 78 | return datetime_str 79 | 80 | def process_inputs(self, current_date, current_weather, hourly_forecast, daily_forecast, event_list, num_cal_days, topic, path_to_server_image): 81 | 82 | # Read html template 83 | with open(self.currPath + '/dashboard_template.html', 'r') as file: 84 | dashboard_template = file.read() 85 | 86 | # Populate the date and events 87 | cal_events_list = [] 88 | for i in range(num_cal_days): 89 | if len(event_list[i]) > 0: 90 | cal_events_text = "" 91 | else: 92 | cal_events_text = '
None
' 93 | for event in event_list[i]: 94 | cal_events_text += '
' 95 | if event["isMultiday"] or event["allday"]: 96 | cal_events_text += event['summary'] 97 | else: 98 | cal_events_text += '' + self.get_short_time(event['startDatetime']) + ' ' + event['summary'] 99 | cal_events_text += '
\n' 100 | cal_events_list.append(cal_events_text) 101 | 102 | # Append the bottom and write the file 103 | htmlFile = open(self.currPath + '/dashboard.html', "w") 104 | htmlFile.write(dashboard_template.format( 105 | day=current_date.strftime("%-d"), 106 | month=current_date.strftime("%B"), 107 | weekday=current_date.strftime("%A"), 108 | tomorrow=(current_date + timedelta(days=1)).strftime("%A"), 109 | dayafter=(current_date + timedelta(days=2)).strftime("%A"), 110 | events_today=cal_events_list[0], 111 | events_tomorrow=cal_events_list[1], 112 | events_dayafter=cal_events_list[2], 113 | # I'm choosing to show the forecast for the next hour instead of the current weather 114 | # current_weather_text=string.capwords(current_weather["weather"][0]["description"]), 115 | # current_weather_id=current_weather["weather"][0]["id"], 116 | # current_weather_temp=round(current_weather["temp"]), 117 | current_weather_text=string.capwords(hourly_forecast[1]["weather"][0]["description"]), 118 | current_weather_id=hourly_forecast[1]["weather"][0]["id"], 119 | current_weather_temp=round(hourly_forecast[1]["temp"]), 120 | today_weather_id=daily_forecast[0]["weather"][0]["id"], 121 | tomorrow_weather_id=daily_forecast[1]["weather"][0]["id"], 122 | dayafter_weather_id=daily_forecast[2]["weather"][0]["id"], 123 | today_weather_pop=str(round(daily_forecast[0]["pop"] * 100)), 124 | tomorrow_weather_pop=str(round(daily_forecast[1]["pop"] * 100)), 125 | dayafter_weather_pop=str(round(daily_forecast[2]["pop"] * 100)), 126 | today_weather_min=str(round(daily_forecast[0]["temp"]["min"])), 127 | tomorrow_weather_min=str(round(daily_forecast[1]["temp"]["min"])), 128 | dayafter_weather_min=str(round(daily_forecast[2]["temp"]["min"])), 129 | today_weather_max=str(round(daily_forecast[0]["temp"]["max"])), 130 | tomorrow_weather_max=str(round(daily_forecast[1]["temp"]["max"])), 131 | dayafter_weather_max=str(round(daily_forecast[2]["temp"]["max"])), 132 | topic_title=topic["title"], 133 | topic_text=topic["text"] 134 | )) 135 | htmlFile.close() 136 | 137 | self.get_screenshot(path_to_server_image) 138 | --------------------------------------------------------------------------------