From 42a7c03560647f32f4b3c6754282245270938b82 Mon Sep 17 00:00:00 2001 From: blavenie <benoit.lavenier@e-is.pro> Date: Mon, 10 Apr 2017 14:48:39 +0200 Subject: [PATCH] ES: add subscriptoin email / send --- README.md | 2 +- doc/fr/development_tutorial.md | 10 +- .../i18n/duniter4j-client_en_GB.properties | 8 +- .../i18n/duniter4j-client_fr_FR.properties | 8 +- .../core/client/model/bma/TxSource.java | 2 +- .../model/bma/jackson/JacksonUtils.java | 7 +- .../model/elasticsearch/DeleteRecord.java | 2 +- .../client/model/elasticsearch/Record.java | 17 +- .../core/client/model/local/Wallet.java | 2 +- .../service/local/NetworkServiceImpl.java | 3 + .../org/duniter/core/model/SmtpConfig.java | 69 + .../duniter/core/service/CryptoService.java | 10 + .../service/Ed25519CryptoServiceImpl.java | 68 +- .../org/duniter/core/service/MailService.java | 34 +- .../duniter/core/service/MailServiceImpl.java | 251 +- .../duniter/core/util/crypto/CryptoUtils.java | 4 + .../util/protocols/classpath/Handler.java | 32 + .../java/org/duniter/core/util/url/URLs.java | 44 + .../service/Ed25519CryptoServiceTest.java | 54 +- duniter4j-es-assembly/pom.xml | 12 +- .../main/assembly/config/elasticsearch.yml | 4 + .../src/test/es-home/config/elasticsearch.yml | 18 +- .../src/test/es-home/config/logging.yml | 12 +- .../org/duniter/elasticsearch/Plugin.java | 1 + .../org/duniter/elasticsearch/PluginInit.java | 13 +- .../duniter/elasticsearch/PluginSettings.java | 4 + .../elasticsearch/client/Duniter4jClient.java | 4 + .../client/Duniter4jClientImpl.java | 14 + .../elasticsearch/dao/IndexTypeDao.java | 2 +- .../elasticsearch/service/ServiceLocator.java | 14 +- .../services/org.duniter.core.beans.Bean | 2 - ...rg.nuiton.config.ApplicationConfigProvider | 1 - .../src/test/es-home/config/elasticsearch.yml | 6 +- .../duniter/elasticsearch/TestResource.java | 74 +- .../service/BlockchainServiceTest.java | 116 +- .../service/CurrencyServiceTest.java | 81 + .../services/org.duniter.core.beans.Bean | 7 +- ...4j-elasticsearch-localhost-node.properties | 12 - .../duniter4j-elasticsearch-test.properties | 16 - .../duniter4j-es-core-test.properties | 1 + .../gchange/dao/AbstractCommentDaoImpl.java | 155 - .../gchange/dao/AbstractRecordDaoImpl.java | 210 - .../elasticsearch/gchange/dao/CommentDao.java | 41 - .../elasticsearch/gchange/dao/DaoModule.java | 52 - .../dao/location/CitiesLocationDaoImpl.java | 349 - .../gchange/dao/market/MarketCommentDao.java | 9 - .../dao/market/MarketCommentDaoImpl.java | 22 - .../gchange/dao/market/MarketIndexDao.java | 11 - .../dao/market/MarketIndexDaoImpl.java | 111 - .../gchange/dao/market/MarketRecordDao.java | 9 - .../dao/market/MarketRecordDaoImpl.java | 182 - .../dao/registry/RegistryCommentDao.java | 9 - .../dao/registry/RegistryCommentDaoImpl.java | 17 - .../dao/registry/RegistryIndexDao.java | 11 - .../dao/registry/RegistryIndexDaoImpl.java | 117 - .../dao/registry/RegistryRecordDao.java | 9 - .../dao/registry/RegistryRecordDaoImpl.java | 16 - .../model/event/GchangeEventCodes.java | 34 - .../gchange/model/market/MarketRecord.java | 96 - .../model/registry/RegistryRecord.java | 67 - .../gchange/rest/RestModule.java | 50 - .../market/RestMarketCommentIndexAction.java | 45 - .../market/RestMarketCommentUpdateAction.java | 45 - .../rest/market/RestMarketImageAction.java | 45 - .../market/RestMarketRecordIndexAction.java | 45 - .../market/RestMarketRecordUpdateAction.java | 45 - .../RestRegistryCommentUpdateAction.java | 45 - .../registry/RestRegistryImageAction.java | 45 - .../RestRegistryRecordIndexAction.java | 45 - .../service/CommentUserEventService.java | 273 - .../gchange/service/MarketService.java | 150 - .../gchange/service/RegistryService.java | 147 - .../src/main/misc/cities-fr.geoJson.txt | 8 - .../registry-categories-naf2008_liste_n5.ods | Bin 70946 -> 0 bytes .../duniter4j-es-gchange_en_GB.properties | 12 - .../duniter4j-es-gchange_fr_FR.properties | 12 - .../market-categories-bulk-insert.json | 151 - .../registry-categories-bulk-insert.json | 1506 --- .../duniter/elasticsearch/TestResource.java | 141 - .../RegistryRecordIndexerServiceTest.java | 57 - .../services/org.duniter.core.beans.Bean | 14 - ...4j-elasticsearch-localhost-node.properties | 12 - .../duniter4j-elasticsearch-test.properties | 16 - .../test/resources/registry-test-records.json | 23 - .../pom.xml | 59 +- .../src/license/THIRD-PARTY.properties | 0 .../src/main/assembly/plugin.xml | 0 .../main/filtered-resources/log4j.properties | 0 .../plugin-descriptor.properties | 2 +- .../elasticsearch/subscription}/Plugin.java | 12 +- .../subscription}/PluginInit.java | 35 +- .../subscription}/PluginSettings.java | 65 +- .../dao/AbstractSubscriptionIndexTypeDao.java | 63 + .../subscription/dao/DaoModule.java | 24 +- .../dao/SubscriptionIndexDao.java | 14 + .../dao/SubscriptionIndexDaoImpl.java | 100 + .../dao/SubscriptionIndexTypeDao.java | 6 +- .../dao/record/SubscriptionRecordDao.java | 16 + .../dao/record/SubscriptionRecordDaoImpl.java | 141 + .../subscription}/model/Protocol.java | 4 +- .../subscription/model/Subscription.java | 101 + .../model/email/EmailSubscription.java | 83 + .../subscription/rest/RestModule.java | 40 + .../RestSubscriptionCategoryGetAction.java | 10 +- .../RestSubscriptionRecordIndexAction.java | 20 +- .../RestSubscriptionRecordUpdateAction.java | 18 +- .../service/AbstractService.java | 7 +- .../subscription}/service/ServiceModule.java | 9 +- .../service/SubscriptionService.java | 358 + .../subscription}/service/SynchroService.java | 34 +- .../util/stringtemplate/DateRenderer.java | 43 + .../util/stringtemplate/I18nRenderer.java | 24 + .../src/main/misc/index.sh | 0 ...duniter4j-es-subscription_en_GB.properties | 7 + ...duniter4j-es-subscription_fr_FR.properties | 11 + .../src/main/resources/plugin-security.policy | 0 .../subscription-categories-bulk-insert.json | 9 + .../src/main/resources/templates/css.st | 10738 ++++++++++++++++ .../src/main/resources/templates/css_logo.st | 22 + .../main/resources/templates/event_item.st | 6 + .../src/main/resources/templates/html.st | 19 + .../resources/templates/html_email_content.st | 33 + .../src/main/resources/templates/i18n.st | 2 + .../src/main/resources/templates/i18n_args.st | 2 + .../main/resources/templates/text_email.st | 13 + .../resources/templates/text_event_item.st | 3 + .../src/test/es-home/config/elasticsearch.yml | 20 +- .../src/test/es-home/config/logging.yml | 0 .../plugin-descriptor.properties | 80 + .../mapper-attachments/plugin-security.policy | 34 + .../subscription}/TestFixtures.java | 5 +- .../subscription/TestResource.java | 109 + .../service/SubscriptionServiceTest.java | 168 + .../service/SubscriptionTemplateTest.java | 129 + .../services/org.duniter.core.beans.Bean | 0 .../src/test/resources/curl_test.sh | 0 .../duniter4j-es-subscription-test.properties | 2 + .../src/test/resources/log4j.properties | 9 +- .../elasticsearch/user/PluginInit.java | 30 +- .../elasticsearch/user/PluginSettings.java | 67 +- .../user/service/AdminService.java | 105 + .../service/BlockchainUserEventService.java | 26 +- .../user/service/GroupService.java | 4 +- .../user/service/HistoryService.java | 12 +- .../user/service/MailService.java | 139 + .../user/service/MessageService.java | 16 +- .../user/service/ServiceModule.java | 2 + .../user/service/UserEventService.java | 162 +- .../user/service/UserInvitationService.java | 6 +- .../user/service/UserService.java | 4 +- .../websocket/WebsocketUserEventEndPoint.java | 9 +- .../i18n/duniter4j-es-user_en_GB.properties | 14 +- .../i18n/duniter4j-es-user_fr_FR.properties | 22 +- pom.xml | 9 +- 154 files changed, 13754 insertions(+), 5082 deletions(-) create mode 100644 duniter4j-core-shared/src/main/java/org/duniter/core/model/SmtpConfig.java create mode 100644 duniter4j-core-shared/src/main/java/org/duniter/core/util/protocols/classpath/Handler.java create mode 100644 duniter4j-core-shared/src/main/java/org/duniter/core/util/url/URLs.java delete mode 100644 duniter4j-es-core/src/main/resources/META-INF/services/org.nuiton.config.ApplicationConfigProvider create mode 100644 duniter4j-es-core/src/test/java/org/duniter/elasticsearch/service/CurrencyServiceTest.java delete mode 100644 duniter4j-es-core/src/test/resources/duniter4j-elasticsearch-localhost-node.properties delete mode 100644 duniter4j-es-core/src/test/resources/duniter4j-elasticsearch-test.properties create mode 100644 duniter4j-es-core/src/test/resources/duniter4j-es-core-test.properties delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/AbstractCommentDaoImpl.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/AbstractRecordDaoImpl.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/CommentDao.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/DaoModule.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/location/CitiesLocationDaoImpl.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketCommentDao.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketCommentDaoImpl.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketIndexDao.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketIndexDaoImpl.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketRecordDao.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketRecordDaoImpl.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryCommentDao.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryCommentDaoImpl.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryIndexDao.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryIndexDaoImpl.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryRecordDao.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryRecordDaoImpl.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/event/GchangeEventCodes.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/market/MarketRecord.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/registry/RegistryRecord.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/RestModule.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCommentIndexAction.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCommentUpdateAction.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketImageAction.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketRecordIndexAction.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketRecordUpdateAction.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCommentUpdateAction.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryImageAction.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryRecordIndexAction.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/CommentUserEventService.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/MarketService.java delete mode 100644 duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/RegistryService.java delete mode 100644 duniter4j-es-gchange/src/main/misc/cities-fr.geoJson.txt delete mode 100644 duniter4j-es-gchange/src/main/misc/registry-categories-naf2008_liste_n5.ods delete mode 100644 duniter4j-es-gchange/src/main/resources/i18n/duniter4j-es-gchange_en_GB.properties delete mode 100644 duniter4j-es-gchange/src/main/resources/i18n/duniter4j-es-gchange_fr_FR.properties delete mode 100644 duniter4j-es-gchange/src/main/resources/market-categories-bulk-insert.json delete mode 100644 duniter4j-es-gchange/src/main/resources/registry-categories-bulk-insert.json delete mode 100644 duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/TestResource.java delete mode 100644 duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/service/RegistryRecordIndexerServiceTest.java delete mode 100644 duniter4j-es-gchange/src/test/resources/META-INF/services/org.duniter.core.beans.Bean delete mode 100644 duniter4j-es-gchange/src/test/resources/duniter4j-elasticsearch-localhost-node.properties delete mode 100644 duniter4j-es-gchange/src/test/resources/duniter4j-elasticsearch-test.properties delete mode 100644 duniter4j-es-gchange/src/test/resources/registry-test-records.json rename {duniter4j-es-gchange => duniter4j-es-subscription}/pom.xml (68%) rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/license/THIRD-PARTY.properties (100%) rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/main/assembly/plugin.xml (100%) rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/main/filtered-resources/log4j.properties (100%) rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/main/filtered-resources/plugin-descriptor.properties (73%) rename {duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription}/Plugin.java (87%) rename {duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription}/PluginInit.java (73%) rename {duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription}/PluginSettings.java (75%) create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/AbstractSubscriptionIndexTypeDao.java rename duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCategoryAction.java => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/DaoModule.java (53%) create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexDao.java create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexDaoImpl.java rename duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/RecordDao.java => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexTypeDao.java (86%) create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/record/SubscriptionRecordDao.java create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/record/SubscriptionRecordDaoImpl.java rename {duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription}/model/Protocol.java (90%) create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/Subscription.java create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/email/EmailSubscription.java create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/RestModule.java rename duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCategoryAction.java => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionCategoryGetAction.java (75%) rename duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCommentIndexAction.java => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionRecordIndexAction.java (62%) rename duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryRecordUpdateAction.java => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionRecordUpdateAction.java (62%) rename {duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription}/service/AbstractService.java (88%) rename {duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription}/service/ServiceModule.java (82%) create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SubscriptionService.java rename {duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange => duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription}/service/SynchroService.java (56%) create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/DateRenderer.java create mode 100644 duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/I18nRenderer.java rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/main/misc/index.sh (100%) create mode 100644 duniter4j-es-subscription/src/main/resources/i18n/duniter4j-es-subscription_en_GB.properties create mode 100644 duniter4j-es-subscription/src/main/resources/i18n/duniter4j-es-subscription_fr_FR.properties rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/main/resources/plugin-security.policy (100%) create mode 100644 duniter4j-es-subscription/src/main/resources/subscription-categories-bulk-insert.json create mode 100644 duniter4j-es-subscription/src/main/resources/templates/css.st create mode 100644 duniter4j-es-subscription/src/main/resources/templates/css_logo.st create mode 100644 duniter4j-es-subscription/src/main/resources/templates/event_item.st create mode 100644 duniter4j-es-subscription/src/main/resources/templates/html.st create mode 100644 duniter4j-es-subscription/src/main/resources/templates/html_email_content.st create mode 100644 duniter4j-es-subscription/src/main/resources/templates/i18n.st create mode 100644 duniter4j-es-subscription/src/main/resources/templates/i18n_args.st create mode 100644 duniter4j-es-subscription/src/main/resources/templates/text_email.st create mode 100644 duniter4j-es-subscription/src/main/resources/templates/text_event_item.st rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/test/es-home/config/elasticsearch.yml (90%) rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/test/es-home/config/logging.yml (100%) create mode 100644 duniter4j-es-subscription/src/test/es-home/plugins/mapper-attachments/plugin-descriptor.properties create mode 100644 duniter4j-es-subscription/src/test/es-home/plugins/mapper-attachments/plugin-security.policy rename {duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch => duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription}/TestFixtures.java (87%) create mode 100644 duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/TestResource.java create mode 100644 duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionServiceTest.java create mode 100644 duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionTemplateTest.java create mode 100644 duniter4j-es-subscription/src/test/resources/META-INF/services/org.duniter.core.beans.Bean rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/test/resources/curl_test.sh (100%) create mode 100644 duniter4j-es-subscription/src/test/resources/duniter4j-es-subscription-test.properties rename {duniter4j-es-gchange => duniter4j-es-subscription}/src/test/resources/log4j.properties (68%) create mode 100644 duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/AdminService.java create mode 100644 duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/MailService.java diff --git a/README.md b/README.md index 18606e49..fd86c9e7 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ duniter4j has four main components : sudo apt-get install openjdk-8-jre ``` - - Install [libsodium](https://download.libsodium.org/doc/index.html) (Linux only) + - Install [libsodium](https://download.libsodium.org/doc/index.html) v1.0.11 (Linux only) - Linux: See [installation](https://download.libsodium.org/doc/installation/index.html). After installation, make sure the file 'libsodium.so' exists on: /usr/local/lib or /opt/local/lib. If not, create a symbolic link. diff --git a/doc/fr/development_tutorial.md b/doc/fr/development_tutorial.md index 11f04346..69fd5d6d 100644 --- a/doc/fr/development_tutorial.md +++ b/doc/fr/development_tutorial.md @@ -16,7 +16,7 @@ Le projet Duniter4j est composé de plusieurs sous-modules : - `duniter4j-es-*`: Les plugins ElasticSearch, qui implémentent : * `duniter4j-es-core`: Indexation de BlockChain Duniter (ESA ou ES API); * `duniter4j-es-user`: Indexation de données utilisateurs (profils, des messages privées, paramètres chiffrés) (ESUA ou ES USER API); - * `duniter4j-es-gchange`: Indexation d'annonces, registre des profesionnels (GChange API ). Note : cette partie sera pas la suite sortie dans un autre projet. + * `duniter4j-es-subscription`: Indexation d'annonces, registre des profesionnels (GChange API ). Note : cette partie sera pas la suite sortie dans un autre projet. ## Niveau I : récupérer le code source @@ -394,10 +394,10 @@ Duniter4j permet aussi de stocker et d'indexer les données hors BlockChain, com - `/user/profile` : les profiles utilisateurs (nom complet, réseaux sociaux, avatar, etc.) - `/message/inbox` : les messages privées envoyés -- `/market/record` : les annonces de la [place de maché](http://cesium.duniter.fr/#/app/market/lg) Ğchange; - * `/market/record` : les commentaires sur les annonces -- `/registry/record` : les référencement de l'[annuaire pro](http://cesium.duniter.fr/#/app/registry/lg) Ğchange; - * `/market/comment` : les commentaires sur les référencements +- `/mail/record` : les annonces de la [place de maché](http://cesium.duniter.fr/#/app/market/lg) Ğchange; + * `/mail/record` : les commentaires sur les annonces +- `/mail/record` : les référencement de l'[annuaire pro](http://cesium.duniter.fr/#/app/registry/lg) Ğchange; + * `/mail/comment` : les commentaires sur les référencements > La document de l'API HTTP est disponible [ici](../API.md). diff --git a/duniter4j-client/src/main/resources/i18n/duniter4j-client_en_GB.properties b/duniter4j-client/src/main/resources/i18n/duniter4j-client_en_GB.properties index ff30b8ca..e161ce0f 100644 --- a/duniter4j-client/src/main/resources/i18n/duniter4j-client_en_GB.properties +++ b/duniter4j-client/src/main/resources/i18n/duniter4j-client_en_GB.properties @@ -10,10 +10,14 @@ duniter4j.client.network.noPeers=No peers found duniter4j.client.network.params.continue=Continue scanning? (Will refresh on new peer/block). duniter4j.client.network.params.output=Output CSV file duniter4j.client.network.ssl=SSL +duniter4j.client.params.authScrypt=Authenticate using salt (Scrypt) ? duniter4j.client.params.authScrypt.ask.passwd=Please enter your Scrypt password\: duniter4j.client.params.authScrypt.ask.salt=Please enter your Scrypt Salt (Secret identifier)\: duniter4j.client.params.authScrypt.ask.scryptParams=Please enter your Scrypt parameters (N,r,p)\: [%d,%d,%d] duniter4j.client.params.authScrypt.error.scryptParams=Invalid Scrypt parameters (expected 3 values)" +duniter4j.client.params.authScrypt.passwd=Password +duniter4j.client.params.authScrypt.salt=Secret identifier (Salt) +duniter4j.client.params.authScrypt.scryptParams=Scrypt parameters (N,r,p) duniter4j.client.params.config=Configuration file path duniter4j.client.params.debug=Show debug logs duniter4j.client.params.error.invalidOption=Invalid value of option [%s] @@ -34,7 +38,3 @@ duniter4j.client.transaction.loadingMemberPeers=Retrieving member's peers... duniter4j.client.transaction.params.amount.ask=Please enter the amount (integer value)\: duniter4j.client.transaction.params.output.ask=Please enter output (public key)\: duniter4j.client.transaction.sent=Transaction successfully sent. -duniter4j.client.params.authScrypt=Authenticate using salt (Scrypt) ? -duniter4j.client.params.authScrypt.salt=Secret identifier (Salt) -duniter4j.client.params.authScrypt.passwd=Password -duniter4j.client.params.authScrypt.scryptParams=Scrypt parameters (N,r,p) diff --git a/duniter4j-client/src/main/resources/i18n/duniter4j-client_fr_FR.properties b/duniter4j-client/src/main/resources/i18n/duniter4j-client_fr_FR.properties index 958f291e..0e5a4cb7 100644 --- a/duniter4j-client/src/main/resources/i18n/duniter4j-client_fr_FR.properties +++ b/duniter4j-client/src/main/resources/i18n/duniter4j-client_fr_FR.properties @@ -10,10 +10,14 @@ duniter4j.client.network.noPeers=Aucun noeud trouvé duniter4j.client.network.params.continue=Continue scanning? (Will refresh on new peer/block). duniter4j.client.network.params.output=Output CSV file duniter4j.client.network.ssl=SSL +duniter4j.client.params.authScrypt=Authentification par salage Scrypt ? duniter4j.client.params.authScrypt.ask.passwd=Veuillez entrer votre mot de passe Scrypt (password) \: duniter4j.client.params.authScrypt.ask.salt=Veuillez entrer votre identifiant secret Scrypt (Salt)\: duniter4j.client.params.authScrypt.ask.scryptParams=Veuillez entrer les paramètres de Scrypt (N,r,p)\: [%d,%d,%d] duniter4j.client.params.authScrypt.error.scryptParams=Paramètre Scrypt non valide (3 valeurs attendues - format 'N,r,p')" +duniter4j.client.params.authScrypt.passwd=Mot de passe +duniter4j.client.params.authScrypt.salt=Identifiant secret (salt) +duniter4j.client.params.authScrypt.scryptParams=Paramètre de salage Scrypt (N,r,p) duniter4j.client.params.config=Fichier de configuration duniter4j.client.params.debug=Activer les logs de débuggage duniter4j.client.params.error.invalidOption=Valeur d'option [%s] invalid @@ -34,7 +38,3 @@ duniter4j.client.transaction.loadingMemberPeers=Récupération des noeuds membre duniter4j.client.transaction.params.amount.ask=Veuillez entrer le montant (valeur entière) \: duniter4j.client.transaction.params.output.ask=Veuillez entrer le destinataire (clef publique) \: duniter4j.client.transaction.sent=Transaction envoyé avec succès. -duniter4j.client.params.authScrypt=Authentification par salage Scrypt ? -duniter4j.client.params.authScrypt.salt=Identifiant secret (salt) -duniter4j.client.params.authScrypt.passwd=Mot de passe -duniter4j.client.params.authScrypt.scryptParams=Paramètre de salage Scrypt (N,r,p) diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/TxSource.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/TxSource.java index 4c0a05e0..36e4901a 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/TxSource.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/TxSource.java @@ -89,7 +89,7 @@ public class TxSource { } /** - * Source sortType : <ul> + * Source type : <ul> * <li><code>D</code> : Universal Dividend</li> * <li><code>T</code> : Transaction</li> * </ul> diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/jackson/JacksonUtils.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/jackson/JacksonUtils.java index 11aed3fd..9f754aef 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/jackson/JacksonUtils.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/jackson/JacksonUtils.java @@ -22,7 +22,9 @@ package org.duniter.core.client.model.bma.jackson; * #L% */ +import com.fasterxml.jackson.core.util.MinimalPrettyPrinter; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationConfig; import com.fasterxml.jackson.databind.module.SimpleModule; import org.duniter.core.client.model.bma.BlockchainBlock; import org.duniter.core.client.model.bma.NetworkPeering; @@ -36,7 +38,7 @@ import java.util.List; */ public abstract class JacksonUtils extends SimpleModule { - public static final String REGEX_ATTRIBUTE_REPLACE = "[,]?[\"\\s\\n\\r]*%s[\"]?[\\s\\n\\r]*:[\\s\\n\\r]*\"[^\"]+\""; + public static final String REGEX_ATTRIBUTE_REPLACE = "[,]?(?:\"%s\"|%s)[\\s\\n\\r]*:[\\s\\n\\r]*(?:\"[^\"]+\"|null)"; public static ObjectMapper newObjectMapper() { @@ -80,7 +82,8 @@ public abstract class JacksonUtils extends SimpleModule { } public static String removeAttribute(String jsonString, String attributeName) { - return jsonString.replaceAll(String.format(REGEX_ATTRIBUTE_REPLACE, attributeName), ""); + String regex = String.format(REGEX_ATTRIBUTE_REPLACE, attributeName, attributeName); + return jsonString.replaceAll(regex, ""); } } diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/DeleteRecord.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/DeleteRecord.java index d87291d7..c09fe0d1 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/DeleteRecord.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/DeleteRecord.java @@ -28,7 +28,7 @@ package org.duniter.core.client.model.elasticsearch; public class DeleteRecord extends Record { public static final String PROPERTY_INDEX="index"; - public static final String PROPERTY_TYPE="sortType"; + public static final String PROPERTY_TYPE="type"; public static final String PROPERTY_ID="id"; private String index; diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/Record.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/Record.java index 65ad743c..38a94d02 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/Record.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/elasticsearch/Record.java @@ -22,16 +22,20 @@ package org.duniter.core.client.model.elasticsearch; * #L% */ +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.duniter.core.client.model.local.LocalEntity; + /** * Created by blavenie on 01/03/16. */ -public class Record { +public class Record implements LocalEntity<String> { public static final String PROPERTY_ISSUER="issuer"; public static final String PROPERTY_HASH="hash"; public static final String PROPERTY_SIGNATURE="signature"; public static final String PROPERTY_TIME="time"; + private String id; private String issuer; private String hash; private String signature; @@ -41,12 +45,23 @@ public class Record { } public Record(Record another) { + this.id = another.getId(); this.issuer = another.getIssuer(); this.hash = another.getHash(); this.signature = another.getSignature(); this.time = another.getTime(); } + @JsonIgnore + public String getId() { + return id; + } + + @JsonIgnore + public void setId(String id) { + this.id = id; + } + public String getIssuer() { return issuer; } diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Wallet.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Wallet.java index 675f5d9b..c22dbf12 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Wallet.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Wallet.java @@ -151,7 +151,7 @@ public class Wallet extends KeyPair implements LocalEntity<Long>, Serializable { } public String toString() { - return name; + return name != null ? name : identity.getPubkey(); } public String getUid() { diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/NetworkServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/NetworkServiceImpl.java index 70d4dbef..52e2fb97 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/NetworkServiceImpl.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/NetworkServiceImpl.java @@ -174,6 +174,9 @@ public class NetworkServiceImpl extends BaseRemoteServiceImpl implements Network return peersFuture.join().stream() .map(peer -> { if (mainPeer.getUrl().equals(peer.getUrl())) { + mainPeer.setPubkey(peer.getPubkey()); + mainPeer.setHash(peer.getHash()); + mainPeer.setCurrency(peer.getCurrency()); return asyncRefreshPeer(mainPeer, memberUids, pool); } return asyncRefreshPeer(peer, memberUids, pool); diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/model/SmtpConfig.java b/duniter4j-core-shared/src/main/java/org/duniter/core/model/SmtpConfig.java new file mode 100644 index 00000000..67ebaa21 --- /dev/null +++ b/duniter4j-core-shared/src/main/java/org/duniter/core/model/SmtpConfig.java @@ -0,0 +1,69 @@ +package org.duniter.core.model; + +public class SmtpConfig { + + + private String smtpHost; + private int smtpPort; + private String smtpUsername; + private String smtpPassword; + private String senderAddress; + private boolean useSsl; + private boolean startTLS; + + public String getSmtpHost() { + return smtpHost; + } + + public void setSmtpHost(String smtpHost) { + this.smtpHost = smtpHost; + } + + public int getSmtpPort() { + return smtpPort; + } + + public void setSmtpPort(int smtpPort) { + this.smtpPort = smtpPort; + } + + public String getSmtpUsername() { + return smtpUsername; + } + + public void setSmtpUsername(String smtpUsername) { + this.smtpUsername = smtpUsername; + } + + public String getSmtpPassword() { + return smtpPassword; + } + + public void setSmtpPassword(String smtpPassword) { + this.smtpPassword = smtpPassword; + } + + public String getSenderAddress() { + return senderAddress; + } + + public void setSenderAddress(String senderAddress) { + this.senderAddress = senderAddress; + } + + public boolean isUseSsl() { + return useSsl; + } + + public void setUseSsl(boolean useSsl) { + this.useSsl = useSsl; + } + + public boolean isStartTLS() { + return startTLS; + } + + public void setStartTLS(boolean startTLS) { + this.startTLS = startTLS; + } +} \ No newline at end of file diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/service/CryptoService.java b/duniter4j-core-shared/src/main/java/org/duniter/core/service/CryptoService.java index 4702a46c..7c3a6458 100644 --- a/duniter4j-core-shared/src/main/java/org/duniter/core/service/CryptoService.java +++ b/duniter4j-core-shared/src/main/java/org/duniter/core/service/CryptoService.java @@ -68,6 +68,16 @@ public interface CryptoService extends Bean { String sign(String message, String secretKey); + String box(String message, byte[] nonce, String senderSignSk, String receiverSignPk); + + String box(String message, byte[] nonce, byte[] senderSignSk, byte[] receiverSignPk); + + byte[] getBoxRandomNonce(); + + String openBox(String cypherText, String nonce, String senderSignPk, String receiverSignSk); + + String openBox(String cypherText, byte[] nonce, byte[] senderSignPk, byte[] receiverSignSk); + boolean verify(String message, String signature, String publicKey); /** diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/service/Ed25519CryptoServiceImpl.java b/duniter4j-core-shared/src/main/java/org/duniter/core/service/Ed25519CryptoServiceImpl.java index 6448f79a..59bc0264 100644 --- a/duniter4j-core-shared/src/main/java/org/duniter/core/service/Ed25519CryptoServiceImpl.java +++ b/duniter4j-core-shared/src/main/java/org/duniter/core/service/Ed25519CryptoServiceImpl.java @@ -32,8 +32,15 @@ import org.abstractj.kalium.NaCl; import org.abstractj.kalium.NaCl.Sodium; import org.abstractj.kalium.crypto.Util; +import java.nio.charset.Charset; import java.security.GeneralSecurityException; +import static org.abstractj.kalium.NaCl.Sodium.CRYPTO_BOX_CURVE25519XSALSA20POLY1305_BOXZEROBYTES; +import static org.abstractj.kalium.NaCl.Sodium.CRYPTO_BOX_CURVE25519XSALSA20POLY1305_NONCEBYTES; +import static org.abstractj.kalium.NaCl.Sodium.CRYPTO_BOX_CURVE25519XSALSA20POLY1305_ZEROBYTES; +import static org.abstractj.kalium.NaCl.sodium; +import static org.abstractj.kalium.crypto.Util.*; + /** * Crypto services (sign...) @@ -132,12 +139,71 @@ public class Ed25519CryptoServiceImpl implements CryptoService { @Override public String hash(String message) { - byte[] hash = new byte[Sodium.SHA256BYTES]; + byte[] hash = new byte[Sodium.CRYPTO_HASH_SHA256_BYTES]; byte[] messageBinary = CryptoUtils.decodeUTF8(message); naCl.crypto_hash_sha256(hash, messageBinary, messageBinary.length); return bytesToHex(hash).toUpperCase(); } + @Override + public byte[] getBoxRandomNonce() { + byte[] nonce = new byte[Sodium.CRYPTO_BOX_CURVE25519XSALSA20POLY1305_NONCEBYTES]; + naCl.randombytes(nonce, nonce.length); + + return nonce; + } + + @Override + public String box(String message, byte[] nonce, String senderSignSk, String receiverSignPk) { + byte[] senderSignSkBinary = CryptoUtils.decodeBase58(senderSignSk); + byte[] receiverSignPkBinary = CryptoUtils.decodeBase58(receiverSignPk); + return box(message, nonce, senderSignSkBinary, receiverSignPkBinary); + } + + @Override + public String box(String message, byte[] nonce, byte[] senderSignSk, byte[] receiverSignPk) { + checkLength(nonce, CRYPTO_BOX_CURVE25519XSALSA20POLY1305_NONCEBYTES); + + byte[] messageBinary = prependZeros(CRYPTO_BOX_CURVE25519XSALSA20POLY1305_ZEROBYTES, CryptoUtils.decodeBase64(message)); + + byte[] senderBoxSk = new byte[Sodium.CRYPTO_BOX_CURVE25519XSALSA20POLY1305_SECRETKEYBYTES]; + naCl.crypto_sign_ed25519_sk_to_curve25519(senderBoxSk, senderSignSk); + + byte[] receiverBoxPk = new byte[Sodium.CRYPTO_BOX_CURVE25519XSALSA20POLY1305_PUBLICKEYBYTES]; + naCl.crypto_sign_ed25519_pk_to_curve25519(receiverBoxPk, receiverSignPk); + + byte[] cypherTextBinary = new byte[messageBinary.length]; + isValid(sodium().crypto_box_curve25519xsalsa20poly1305(cypherTextBinary, messageBinary, + cypherTextBinary.length, nonce, senderBoxSk, receiverBoxPk), "Encryption failed"); + return CryptoUtils.encodeBase64(removeZeros(CRYPTO_BOX_CURVE25519XSALSA20POLY1305_BOXZEROBYTES, cypherTextBinary)); + } + + @Override + public String openBox(String cypherText, String nonce, String senderSignPk, String receiverSignSk) { + return openBox(cypherText, + CryptoUtils.decodeBase58(nonce), + CryptoUtils.decodeBase58(senderSignPk), + CryptoUtils.decodeBase58(receiverSignSk)); + } + + @Override + public String openBox(String cypherText, byte[] nonce, byte[] senderSignPk, byte[] receiverSignSk) { + checkLength(nonce, CRYPTO_BOX_CURVE25519XSALSA20POLY1305_NONCEBYTES); + byte[] cypherTextBinary = prependZeros(CRYPTO_BOX_CURVE25519XSALSA20POLY1305_BOXZEROBYTES, CryptoUtils.decodeBase64(cypherText)); + + byte[] receiverBoxSk = new byte[Sodium.CRYPTO_BOX_CURVE25519XSALSA20POLY1305_SECRETKEYBYTES]; + naCl.crypto_sign_ed25519_sk_to_curve25519(receiverBoxSk, receiverSignSk); + + byte[] senderBoxPk = new byte[Sodium.CRYPTO_BOX_CURVE25519XSALSA20POLY1305_PUBLICKEYBYTES]; + naCl.crypto_sign_ed25519_pk_to_curve25519(senderBoxPk, senderSignPk); + + byte[] messageBinary = new byte[cypherTextBinary.length]; + isValid(sodium().crypto_box_curve25519xsalsa20poly1305_open( + messageBinary, cypherTextBinary, cypherTextBinary.length, nonce, senderBoxPk, receiverBoxSk), + "Decryption failed. Ciphertext failed verification."); + return CryptoUtils.encodeUTF8(removeZeros(CRYPTO_BOX_CURVE25519XSALSA20POLY1305_ZEROBYTES, messageBinary)); + } + /* -- Internal methods -- */ protected byte[] sign(byte[] message, byte[] secretKey) { diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/service/MailService.java b/duniter4j-core-shared/src/main/java/org/duniter/core/service/MailService.java index 64975b25..1a11960e 100644 --- a/duniter4j-core-shared/src/main/java/org/duniter/core/service/MailService.java +++ b/duniter4j-core-shared/src/main/java/org/duniter/core/service/MailService.java @@ -24,6 +24,7 @@ package org.duniter.core.service; import org.duniter.core.beans.Bean; import org.duniter.core.exception.TechnicalException; +import org.duniter.core.model.SmtpConfig; import javax.mail.internet.ContentType; import javax.mail.internet.ParseException; @@ -33,22 +34,21 @@ import javax.mail.internet.ParseException; */ public interface MailService extends Bean { - void sendTextEmail(String smtpHost, - int smtpPort, - String smtpUsername, - String smtpPassword, - String issuer, - String recipients, - String subject, - String textContent); - - void sendEmail(String smtpHost, - int smtpPort, - String smtpUsername, - String smtpPassword, - String issuer, - String recipients, + void setSmtpConfig(SmtpConfig config); + + void sendTextEmail(String subject, + String textContent, + String... recipients); + + void sendHtmlEmail( String subject, - ContentType contentType, - String content); + String utf8HtmlContent, + String... recipients); + + void sendHtmlEmailWithText( + String subject, + String utf8textContent, + String utf8HtmlContent, + String... recipients); + } diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/service/MailServiceImpl.java b/duniter4j-core-shared/src/main/java/org/duniter/core/service/MailServiceImpl.java index ec7bb898..6a19564a 100644 --- a/duniter4j-core-shared/src/main/java/org/duniter/core/service/MailServiceImpl.java +++ b/duniter4j-core-shared/src/main/java/org/duniter/core/service/MailServiceImpl.java @@ -22,19 +22,24 @@ package org.duniter.core.service; * #L% */ +import com.google.common.base.Joiner; import org.duniter.core.exception.TechnicalException; +import org.duniter.core.model.SmtpConfig; +import org.duniter.core.util.CollectionUtils; import org.duniter.core.util.StringUtils; +import javax.activation.CommandMap; +import javax.activation.MailcapCommandMap; import javax.mail.*; -import javax.mail.internet.ContentType; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.ParseException; +import javax.mail.internet.*; import java.io.Closeable; +import java.util.Arrays; import java.util.Properties; +import java.util.stream.Collectors; public class MailServiceImpl implements MailService, Closeable { + private SmtpConfig smtpConfig; private static Session session; private static Transport transport; @@ -43,82 +48,85 @@ public class MailServiceImpl implements MailService, Closeable { } @Override - public void sendTextEmail(String smtpHost, - int smtpPort, - String smtpUsername, - String smtpPassword, - String issuer, - String recipients, - String subject, - String textContent) { + public void setSmtpConfig(SmtpConfig smtpConfig) { + this.smtpConfig = smtpConfig; + } + + @Override + public void sendTextEmail(String subject, + String textContent, + String... recipients) { try{ ContentType contentType = new ContentType("text/plain"); contentType.setParameter("charset", "UTF-8"); - - sendEmail(smtpHost, smtpPort, smtpUsername, smtpPassword, - issuer, - recipients, - subject, - contentType, - textContent); + sendEmail(subject, contentType.toString(), textContent, recipients); } catch(ParseException e) { // Should never occur throw new TechnicalException(e); } - } @Override - public void sendEmail(String smtpHost, - int smtpPort, - String smtpUsername, - String smtpPassword, - String issuer, - String recipients, - String subject, - ContentType contentType, - String content) { + public void sendHtmlEmail(String subject, + String htmlContent, + String... recipients) { + try{ + ContentType contentType = new ContentType("text/html"); + contentType.setParameter("charset", "UTF-8"); - // check arguments - if (StringUtils.isBlank(smtpHost) || smtpPort <= 0) { - throw new TechnicalException("Invalid arguments: 'smtpHost' could not be null or empty, and 'smtpPort' could not be <= 0"); - } - if (StringUtils.isBlank(issuer)) { - throw new TechnicalException("Invalid arguments: 'issuer' could not be null or empty"); + Multipart content = new MimeMultipart(); + MimeBodyPart mbp = new MimeBodyPart(); + mbp.setContent(htmlContent, contentType.toString()); + content.addBodyPart(mbp); + + sendEmail(subject, content.getContentType(), content, recipients); } - if (StringUtils.isBlank(recipients) || StringUtils.isBlank(subject) || StringUtils.isBlank(content) || contentType == null) { - throw new TechnicalException("Invalid arguments: 'recipients', 'subject', 'contentType' or 'content' could not be null or empty"); + catch(MessagingException e) { + // Should never occur + throw new TechnicalException(e); } - if (!isConnected()) { - connect(smtpHost, smtpPort, smtpUsername, smtpPassword, issuer); - } + } - // send email to recipients - try { - Message message = new MimeMessage(session); - message.setFrom(new InternetAddress(issuer)); - message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients)); - message.setSubject(subject); + @Override + public void sendHtmlEmailWithText(String subject, + String textContent, + String htmlContent, + String... recipients) { + try{ - message.setContent(content, contentType.toString()); - message.saveChanges(); - transport.sendMessage(message, message.getAllRecipients()); + Multipart content = new MimeMultipart("alternative"); - } catch (MessagingException e) { - throw new TechnicalException(String.format("Error while sending email to [%s] using smtp server [%s]", - recipients, - getSmtpServerAsString(smtpHost, smtpPort, smtpUsername) - ), e); - } catch (IllegalStateException e) { - throw new TechnicalException(String.format("Error while sending email to [%s] using smtp server [%s]", - recipients, - getSmtpServerAsString(smtpHost, smtpPort, smtpUsername) - ), e); + // Add text part + { + MimeBodyPart mbp = new MimeBodyPart(); + ContentType contentType = new ContentType("text/plain"); + contentType.setParameter("charset", "UTF-8"); + mbp.setContent(textContent, contentType.toString()); + content.addBodyPart(mbp); + } + + // Add html part + { + MimeBodyPart mbp = new MimeBodyPart(); + ContentType contentType = new ContentType("text/html"); + contentType.setParameter("charset", "UTF-8"); + mbp.setContent(htmlContent, contentType.toString()); + content.addBodyPart(mbp); + } + + sendEmail(subject, content.getContentType(), content, recipients); + } + catch(MessagingException e) { + // Should never occur + throw new TechnicalException(e); } + } + + public void close() { if (isConnected()) { try { @@ -134,6 +142,54 @@ public class MailServiceImpl implements MailService, Closeable { /* -- private methods -- */ + public void sendEmail(String subject, + String contentType, + Object content, + String... recipients) { + + if (CollectionUtils.isEmpty(recipients) || StringUtils.isBlank(subject) || content == null || contentType == null) { + throw new TechnicalException("Invalid arguments: 'recipients', 'subject', 'contentType' or 'content' could not be null or empty"); + } + + if (!isConnected()) { + connect(smtpConfig); + } + + // send email to recipients + try { + Message message = new MimeMessage(session); + message.setFrom(new InternetAddress(smtpConfig.getSenderAddress())); + + Address[] recipientsAddresses = Arrays.asList(recipients).stream().map(recipient -> { + try { + return new InternetAddress(recipient); + } + catch (AddressException e) { + throw new TechnicalException(String.format("Error while sending email. Bad recipient address [%s]", recipient), e); + } + }).collect(Collectors.toList()).toArray(new InternetAddress[recipients.length]); + + message.setRecipients(Message.RecipientType.TO, recipientsAddresses); + message.setSubject(subject); + + message.setContent(content, contentType); + message.setSentDate(new java.util.Date()); + message.saveChanges(); + transport.sendMessage(message, message.getAllRecipients()); + + } catch (MessagingException e) { + throw new TechnicalException(String.format("Error while sending email to [%s] using smtp server [%s]: %s", + Joiner.on(',').join(recipients), getSmtpServerAsString(), + e.getMessage() + ), e); + } + } + + private String getSmtpServerAsString() { + if (smtpConfig == null) return ""; + return getSmtpServerAsString(smtpConfig.getSmtpHost(), smtpConfig.getSmtpPort(), smtpConfig.getSmtpUsername()); + } + private String getSmtpServerAsString(String smtpHost, int smtpPort, String smtpUsername) { StringBuilder buffer = new StringBuilder(); if (StringUtils.isNotBlank(smtpUsername)) { @@ -149,19 +205,64 @@ public class MailServiceImpl implements MailService, Closeable { private void connect(String smtpHost, int smtpPort, String smtpUsername, String smtpPassword, - String issuer) { + String issuer, + boolean useSsl, + boolean starttls) { + // check arguments + if (StringUtils.isBlank(smtpHost) || smtpPort <= 0) { + throw new TechnicalException("Invalid arguments: 'smtpHost' could not be null or empty, and 'smtpPort' could not be <= 0"); + } + if (StringUtils.isBlank(issuer)) { + throw new TechnicalException("Invalid arguments: 'issuer' could not be null or empty"); + } + + this.smtpConfig = new SmtpConfig(); + smtpConfig.setSmtpHost(smtpHost); + smtpConfig.setSmtpPort(smtpPort); + smtpConfig.setSmtpUsername(smtpUsername); + smtpConfig.setSmtpPassword(smtpPassword); + smtpConfig.setSenderAddress(issuer); + smtpConfig.setUseSsl(useSsl); + smtpConfig.setStartTLS(starttls); + connect(this.smtpConfig); + } + + private void connect(SmtpConfig config) { + + // Workaround, to avoid error on content type + // http://stackoverflow.com/questions/21856211/javax-activation-unsupporteddatatypeexception-no-object-dch-for-mime-type-multi + Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); + + configureJavaMailMimeTypes(); + Properties props = new Properties(); - props.put("mail.smtp.host", smtpHost); - props.put("mail.smtp.port", smtpPort); - if (StringUtils.isNotBlank(issuer)) { - props.put("mail.from", issuer); + // check arguments + if (StringUtils.isBlank(config.getSmtpHost()) || config.getSmtpPort() <= 0) { + throw new TechnicalException("Invalid arguments: 'smtpHost' could not be null or empty, and 'smtpPort' could not be <= 0"); + } + if (StringUtils.isBlank(config.getSenderAddress())) { + throw new TechnicalException("Invalid arguments: 'senderAddress' could not be null or empty"); + } + + props.put("mail.smtp.host", config.getSmtpHost()); + props.put("mail.smtp.port", config.getSmtpPort()); + if (StringUtils.isNotBlank(config.getSenderAddress())) { + props.put("mail.from", config.getSenderAddress()); + } + if (config.isUseSsl()) { + props.put("mail.smtp.socketFactory.port", config.getSmtpPort()); + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.fallback", "false"); + } + if (config.isStartTLS()) { + props.put("mail.smtp.starttls.enable", "true"); } + boolean useAuth = false; // auto set authentification if smtp user name is provided - if (StringUtils.isNotBlank(smtpUsername)) { - props.put("mail.smtp.auth", "true"); - //props.put("mail.smtp.starttls.enable", "true"); + if (StringUtils.isNotBlank(config.getSmtpUsername())) { + props.put("mail.smtp.auth", true); useAuth = true; } @@ -170,7 +271,7 @@ public class MailServiceImpl implements MailService, Closeable { try { transport = session.getTransport("smtp"); if (useAuth) { - transport.connect(smtpUsername, smtpPassword); + transport.connect(config.getSmtpUsername(), config.getSmtpPassword()); } else { transport.connect(); } @@ -188,4 +289,18 @@ public class MailServiceImpl implements MailService, Closeable { return transport.isConnected(); } + + /** + * Workaround to define javax.mail MIME types to classes WITHOUT using classpath file. + * See http://stackoverflow.com/questions/21856211/javax-activation-unsupporteddatatypeexception-no-object-dch-for-mime-type-multi + */ + protected void configureJavaMailMimeTypes() { + + MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); + mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); + mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); + mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); + mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed"); + mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); + } } \ No newline at end of file diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/util/crypto/CryptoUtils.java b/duniter4j-core-shared/src/main/java/org/duniter/core/util/crypto/CryptoUtils.java index 3451ff62..ae062df9 100644 --- a/duniter4j-core-shared/src/main/java/org/duniter/core/util/crypto/CryptoUtils.java +++ b/duniter4j-core-shared/src/main/java/org/duniter/core/util/crypto/CryptoUtils.java @@ -60,6 +60,10 @@ public class CryptoUtils extends Util { public static byte[] decodeUTF8(String string) { return string.getBytes(CHARSET_UTF8); } + + public static String encodeUTF8(byte[] bytes) { + return new String(bytes, CHARSET_UTF8); + } public static byte[] decodeAscii(String string) { return string.getBytes(CHARSET_ASCII); diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/util/protocols/classpath/Handler.java b/duniter4j-core-shared/src/main/java/org/duniter/core/util/protocols/classpath/Handler.java new file mode 100644 index 00000000..a0c08c28 --- /dev/null +++ b/duniter4j-core-shared/src/main/java/org/duniter/core/util/protocols/classpath/Handler.java @@ -0,0 +1,32 @@ +package org.duniter.core.util.protocols.classpath; + +import org.duniter.core.exception.TechnicalException; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** A {@link URLStreamHandler} that handles resources on the classpath. */ +public class Handler extends URLStreamHandler { + /** The classloader to find resources from. */ + private final ClassLoader classLoader; + + public Handler() { + this.classLoader = getClass().getClassLoader(); + } + + public Handler(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + @Override + protected URLConnection openConnection(final URL u) throws IOException { + final URL resourceUrl = classLoader.getResource(u.getPath()); + if (resourceUrl == null) { + throw new FileNotFoundException("Unable to load classpath resources: " + u.getPath()); + } + return resourceUrl.openConnection(); + } +} \ No newline at end of file diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/util/url/URLs.java b/duniter4j-core-shared/src/main/java/org/duniter/core/util/url/URLs.java new file mode 100644 index 00000000..1d4f99b7 --- /dev/null +++ b/duniter4j-core-shared/src/main/java/org/duniter/core/util/url/URLs.java @@ -0,0 +1,44 @@ +package org.duniter.core.util.url; + +import org.duniter.core.exception.TechnicalException; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Created by blavenie on 08/04/17. + */ +public final class URLs { + + static { + init(); + } + + private void URLs() { + // helper class + } + + public static URL newClasspathURL(String classpathResource, ClassLoader cl) throws MalformedURLException { + final URL resourceUrl = cl.getResource(classpathResource); + return resourceUrl; + } + + protected static void init() { + // Extend default JRE protocols (add classpath://) + // System.setProperty("java.protocol.handler.pkgs", "org.duniter.core.util.protocols"); + + } + + public static URL getClasspathResourceURL(String aClasspathFile, ClassLoader cl) throws MalformedURLException { + final URL resourceUrl = cl.getResource(aClasspathFile); + if (resourceUrl == null) { + throw new TechnicalException("File not found : " + aClasspathFile); + } + return resourceUrl; + } + + public static URL getParentURL(URL resourceUrl) throws MalformedURLException { + String filePath = resourceUrl.getPath(); + return new URL(filePath.substring(0, filePath.lastIndexOf('/'))); + } +} diff --git a/duniter4j-core-shared/src/test/java/org/duniter/core/service/Ed25519CryptoServiceTest.java b/duniter4j-core-shared/src/test/java/org/duniter/core/service/Ed25519CryptoServiceTest.java index 9473e6fd..1595285c 100644 --- a/duniter4j-core-shared/src/test/java/org/duniter/core/service/Ed25519CryptoServiceTest.java +++ b/duniter4j-core-shared/src/test/java/org/duniter/core/service/Ed25519CryptoServiceTest.java @@ -23,26 +23,39 @@ package org.duniter.core.service; */ +import com.google.common.primitives.UnsignedBytes; +import org.abstractj.kalium.NaCl; +import org.abstractj.kalium.crypto.Box; +import org.abstractj.kalium.crypto.Util; import org.duniter.core.test.TestFixtures; import org.duniter.core.util.crypto.Base58; +import org.duniter.core.util.crypto.CryptoUtils; import org.duniter.core.util.crypto.SecretBox; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; + +import static org.abstractj.kalium.NaCl.Sodium.CRYPTO_BOX_CURVE25519XSALSA20POLY1305_ZEROBYTES; +import static org.abstractj.kalium.NaCl.Sodium.CRYPTO_SECRETBOX_XSALSA20POLY1305_NONCEBYTES; +import static org.abstractj.kalium.crypto.Util.checkLength; +import static org.abstractj.kalium.crypto.Util.isValid; public class Ed25519CryptoServiceTest { private String message; private byte[] messageAsBytes; private CryptoService service; + private TestFixtures fixtures; @Before public void setUp() throws UnsupportedEncodingException { message = "my message to encrypt !"; messageAsBytes = message.getBytes("UTF-8"); service = new Ed25519CryptoServiceImpl(); + fixtures = new TestFixtures(); } @Test @@ -75,12 +88,51 @@ public class Ed25519CryptoServiceTest { Assert.assertEquals("AC31F1E3EAEB7A535A3BF1182AA53100BB3B610C5D63643ACB145EB99764B0CA", hash); } + @Test + public void packThenOpenBox() throws Exception { + + // + String originalMessage = "test@test"; + String nonce = "AHHfny8igAJp1h7P5d8bEobKZfgoRcXs9"; + + // Sender + SecretBox receiver = createSecretBox(); + SecretBox sender = createSecretBox(); + + // Create box + String cypherText = service.box(originalMessage, + CryptoUtils.decodeBase58(nonce), + receiver.getSecretKey(), sender.getPublicKey()); + + // Open box + String decryptedText = service.openBox( + cypherText, + nonce, + sender.getPublicKey(), receiver.getSecretKey()); + + Assert.assertEquals(originalMessage, decryptedText); + + } + + @Test + public void openBox() throws Exception { + // Receiver & Receiver + SecretBox receiver = createSecretBox(); + SecretBox sender = createSecretBox(); + + // Open box + String decryptedText = service.openBox( + "RZwBeUpjGH2f4GUP0UW32WC82iiWfcrKbw==", + "AHHfny8igAJp1h7P5d8bEobKZfgoRcXs9", + sender.getPublicKey(), receiver.getSecretKey()); + + Assert.assertEquals("test@test", decryptedText); + } /* -- internal methods */ protected SecretBox createSecretBox() { - TestFixtures fixtures = new TestFixtures(); String salt = fixtures.getUserSalt(); String password = fixtures.getUserPassword(); SecretBox secretBox = new SecretBox(salt, password); diff --git a/duniter4j-es-assembly/pom.xml b/duniter4j-es-assembly/pom.xml index e89d4dd9..07c3f36d 100644 --- a/duniter4j-es-assembly/pom.xml +++ b/duniter4j-es-assembly/pom.xml @@ -163,9 +163,9 @@ </configuration> </execution> - <!-- unpack ES gchange plugin --> + <!-- unpack ES subscription plugin --> <execution> - <id>unpack-es-gchange-plugin</id> + <id>unpack-es-subscription-plugin</id> <goals> <goal>unpack</goal> </goals> @@ -174,12 +174,12 @@ <artifactItems> <artifactItem> <groupId>org.duniter</groupId> - <artifactId>duniter4j-es-gchange</artifactId> + <artifactId>duniter4j-es-subscription</artifactId> <version>${project.version}</version> <type>zip</type> </artifactItem> </artifactItems> - <outputDirectory>${project.build.directory}/elasticsearch-${elasticsearch.version}/plugins/duniter4j-es-gchange</outputDirectory> + <outputDirectory>${project.build.directory}/elasticsearch-${elasticsearch.version}/plugins/duniter4j-es-subscription</outputDirectory> <silent>true</silent> <skip>${assembly.skip}</skip> </configuration> @@ -270,8 +270,8 @@ <fileset dir="../duniter4j-es-user/target" includes="duniter4j-*${project.version}.jar"> </fileset> </copy> - <copy todir="${run.es.home}/plugins/duniter4j-es-gchange" overwrite="true"> - <fileset dir="../duniter4j-es-gchange/target" includes="duniter4j-*${project.version}.jar"> + <copy todir="${run.es.home}/plugins/duniter4j-es-subscription" overwrite="true"> + <fileset dir="../duniter4j-es-subscription/target" includes="duniter4j-*${project.version}.jar"> </fileset> </copy> </then> diff --git a/duniter4j-es-assembly/src/main/assembly/config/elasticsearch.yml b/duniter4j-es-assembly/src/main/assembly/config/elasticsearch.yml index 31be3af2..a7f0e815 100644 --- a/duniter4j-es-assembly/src/main/assembly/config/elasticsearch.yml +++ b/duniter4j-es-assembly/src/main/assembly/config/elasticsearch.yml @@ -176,3 +176,7 @@ duniter.mail.enable: false duniter.changes.listenSource: '*/block' duniter.ws.port: 9400 + +duniter.subscription.enable: true + +duniter.subscription.email.cesium.url: 'https://g1.duniter.fr' \ No newline at end of file diff --git a/duniter4j-es-assembly/src/test/es-home/config/elasticsearch.yml b/duniter4j-es-assembly/src/test/es-home/config/elasticsearch.yml index b1129209..67c8e332 100644 --- a/duniter4j-es-assembly/src/test/es-home/config/elasticsearch.yml +++ b/duniter4j-es-assembly/src/test/es-home/config/elasticsearch.yml @@ -162,14 +162,20 @@ duniter.data.sync.port: 443 # # SMTP server configuration (host and port) # -duniter.mail.enable: false -#duniter.mail.smtp.host: localhost -#duniter.mail.smtp.port: 25 +duniter.mail.enable: true +duniter.mail.smtp.host: smtp.gmail.com +duniter.mail.smtp.port: 465 +duniter.mail.smtp.ssl: true +duniter.mail.smtp.starttls: true +duniter.mail.smtp.username: benoit.lavenier@e-is.pro +duniter.mail.smtp.password: .2hainepourDieu + # # Mail 'from' address # #duniter.mail.from: no-reply@domain.com -#duniter.mail.from: root@EIS-DEV +duniter.mail.from: benoit.lavenier@e-is.pro + # # Mail: admin address # @@ -182,3 +188,7 @@ duniter.mail.enable: false duniter.changes.listenSource: '*/block' duniter.ws.port: 9400 + +# = 10s +duniter.subscription.enable: true +duniter.subscription.email.interval: 10000 \ No newline at end of file diff --git a/duniter4j-es-assembly/src/test/es-home/config/logging.yml b/duniter4j-es-assembly/src/test/es-home/config/logging.yml index c9b46939..ad829d20 100644 --- a/duniter4j-es-assembly/src/test/es-home/config/logging.yml +++ b/duniter4j-es-assembly/src/test/es-home/config/logging.yml @@ -20,14 +20,18 @@ logger: org.duniter: INFO org.duniter.core.beans: DEBUG + org.duniter.core.client.service: DEBUG org.duniter.elasticsearch: DEBUG org.duniter.elasticsearch.service: DEBUG - org.duniter.core.client.service: DEBUG + org.duniter.elasticsearch.user.service: DEBUG + org.duniter.elasticsearch.subscription.service: DEBUG + - duniter : DEBUG - duniter.security : ERROR - duniter.user.event : INFO + duniter: DEBUG + duniter.security: ERROR + duniter.user.event: INFO duniter.network.p2p: INFO + duniter.mail: DEBUG security: DEBUG diff --git a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/Plugin.java b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/Plugin.java index 4c8b851d..693feb1b 100644 --- a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/Plugin.java +++ b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/Plugin.java @@ -46,6 +46,7 @@ public class Plugin extends org.elasticsearch.plugins.Plugin { @Inject public Plugin(Settings settings) { this.enable = settings.getAsBoolean("duniter.enabled", true); + } @Override diff --git a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/PluginInit.java b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/PluginInit.java index d91277ec..6f285aed 100644 --- a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/PluginInit.java +++ b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/PluginInit.java @@ -50,7 +50,7 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { private final static ESLogger logger = Loggers.getLogger("duniter.core"); @Inject - public PluginInit(Client client, Settings settings, PluginSettings pluginSettings, ThreadPool threadPool, final Injector injector) { + public PluginInit(Settings settings, PluginSettings pluginSettings, ThreadPool threadPool, final Injector injector) { super(settings); this.pluginSettings = pluginSettings; this.threadPool = threadPool; @@ -62,10 +62,9 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { threadPool.scheduleOnClusterHealthStatus(() -> { createIndices(); - // Waiting cluster back to GREEN or YELLOW state, before synchronize - threadPool.scheduleOnClusterHealthStatus(() -> { - synchronize(); - }, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); + // Waiting cluster back to GREEN or YELLOW state, before doAfterStart + threadPool.scheduleOnClusterHealthStatus(this::doAfterStart, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); + }, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); } @@ -110,7 +109,9 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { } } - protected void synchronize() { + protected void doAfterStart() { + + // Synchronize blockchain if (pluginSettings.enableBlockchainSync()) { Peer peer = pluginSettings.checkAndGetPeer(); diff --git a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/PluginSettings.java b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/PluginSettings.java index e95270d3..2a6140c6 100644 --- a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/PluginSettings.java +++ b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/PluginSettings.java @@ -324,6 +324,10 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { } } + public Locale getI18nLocale() { + return clientConfig.getI18nLocale(); + } + /** * Override the version default option, from the MANIFEST implementation version (if any) * @param applicationConfig diff --git a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/client/Duniter4jClient.java b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/client/Duniter4jClient.java index a0076035..cdaea5b3 100644 --- a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/client/Duniter4jClient.java +++ b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/client/Duniter4jClient.java @@ -1,10 +1,12 @@ package org.duniter.elasticsearch.client; import org.duniter.core.beans.Bean; +import org.duniter.core.client.model.local.LocalEntity; import org.duniter.elasticsearch.dao.handler.StringReaderHandler; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.client.Client; +import org.elasticsearch.search.SearchHit; import java.io.File; import java.io.InputStream; @@ -56,6 +58,8 @@ public interface Duniter4jClient extends Bean, Client { */ <T extends Object> T getSourceById(String index, String type, String docId, Class<T> classOfT, String... fieldNames); + <C extends LocalEntity<String>> C readSourceOrNull(SearchHit searchHit, Class<? extends C> clazz); + void bulkFromClasspathFile(String classpathFile, String indexName, String indexType); void bulkFromClasspathFile(String classpathFile, String indexName, String indexType, StringReaderHandler handler); diff --git a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/client/Duniter4jClientImpl.java b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/client/Duniter4jClientImpl.java index 158b86b4..54942a82 100644 --- a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/client/Duniter4jClientImpl.java +++ b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/client/Duniter4jClientImpl.java @@ -28,6 +28,7 @@ import com.google.common.base.Joiner; import org.apache.commons.collections4.MapUtils; import org.duniter.core.client.model.bma.jackson.JacksonUtils; import org.duniter.core.client.model.elasticsearch.Record; +import org.duniter.core.client.model.local.LocalEntity; import org.duniter.core.exception.TechnicalException; import org.duniter.core.util.CollectionUtils; import org.duniter.core.util.ObjectUtils; @@ -377,6 +378,19 @@ public class Duniter4jClientImpl implements Duniter4jClient { } } + @Override + public <C extends LocalEntity<String>> C readSourceOrNull(SearchHit searchHit, Class<? extends C> clazz) { + try { + C value = objectMapper.readValue(searchHit.getSourceRef().streamInput(), clazz); + value.setId(searchHit.getId()); + return value; + } + catch(IOException e) { + logger.warn(String.format("Unable to deserialize source [%s/%s/%s] into [%s]: %s", searchHit.getIndex(), searchHit.getType(), searchHit.getId(), clazz.getName(), e.getMessage())); + return null; + } + } + @Override public void bulkFromClasspathFile(String classpathFile, String indexName, String indexType) { bulkFromClasspathFile(classpathFile, indexName, indexType, null); diff --git a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/dao/IndexTypeDao.java b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/dao/IndexTypeDao.java index 047280fb..dd4ff061 100644 --- a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/dao/IndexTypeDao.java +++ b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/dao/IndexTypeDao.java @@ -8,7 +8,7 @@ import java.util.Map; /** * Created by blavenie on 03/04/17. */ -public interface IndexTypeDao<T extends IndexTypeDao> { +public interface IndexTypeDao<T extends IndexTypeDao> extends IndexDao<T> { T createIndexIfNotExists(); diff --git a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/service/ServiceLocator.java b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/service/ServiceLocator.java index 7c773b05..cdc9b9c3 100644 --- a/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/service/ServiceLocator.java +++ b/duniter4j-es-core/src/main/java/org/duniter/elasticsearch/service/ServiceLocator.java @@ -30,8 +30,8 @@ import org.duniter.core.client.service.DataContext; import org.duniter.core.client.service.HttpService; import org.duniter.core.client.service.HttpServiceImpl; import org.duniter.core.client.service.bma.*; -import org.duniter.core.client.service.local.*; import org.duniter.core.client.service.local.CurrencyService; +import org.duniter.core.client.service.local.*; import org.duniter.core.exception.TechnicalException; import org.duniter.core.service.CryptoService; import org.duniter.core.service.Ed25519CryptoServiceImpl; @@ -39,10 +39,8 @@ import org.duniter.core.service.MailService; import org.duniter.core.service.MailServiceImpl; import org.duniter.elasticsearch.beans.ESBeanFactory; import org.duniter.elasticsearch.dao.BlockDao; -import org.duniter.elasticsearch.client.Duniter4jClient; import org.duniter.elasticsearch.dao.impl.BlockDaoImpl; import org.duniter.elasticsearch.dao.impl.CurrencyDaoImpl; -import org.duniter.elasticsearch.client.Duniter4jClientImpl; import org.duniter.elasticsearch.dao.impl.PeerDaoImpl; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Injector; @@ -61,15 +59,12 @@ public class ServiceLocator private static ESBeanFactory beanFactory = null; @Inject - public ServiceLocator(Injector injector/*, PeerDao peerDao, CurrencyDao currencyDao*/) { + public ServiceLocator(Injector injector) { super(getOrCreateBeanFactory()); if (logger.isDebugEnabled()) { logger.debug("Starting Duniter4j ServiceLocator..."); } beanFactory.setInjector(injector); -/* - beanFactory.setBean(peerDao, PeerDao.class); - beanFactory.setBean(currencyDao, CurrencyDao.class);*/ org.duniter.core.client.service.ServiceLocator.setInstance(this); } @@ -122,10 +117,7 @@ public class ServiceLocator } public T get() { - logger.debug("Loading class [" + clazz.getName() + "]..."); - T result = getOrCreateBeanFactory().getBean(clazz); - logger.debug("...end of loading [" + clazz.getName() + "]"); - return result; + return getOrCreateBeanFactory().getBean(clazz); } } } diff --git a/duniter4j-es-core/src/main/resources/META-INF/services/org.duniter.core.beans.Bean b/duniter4j-es-core/src/main/resources/META-INF/services/org.duniter.core.beans.Bean index 1cf6cb3c..c3c31986 100644 --- a/duniter4j-es-core/src/main/resources/META-INF/services/org.duniter.core.beans.Bean +++ b/duniter4j-es-core/src/main/resources/META-INF/services/org.duniter.core.beans.Bean @@ -10,6 +10,4 @@ org.duniter.core.client.service.DataContext org.duniter.core.client.service.local.PeerServiceImpl org.duniter.core.client.service.local.CurrencyServiceImpl org.duniter.core.client.service.local.NetworkServiceImpl -org.duniter.core.client.dao.mem.MemoryCurrencyDaoImpl -org.duniter.core.client.dao.mem.MemoryPeerDaoImpl diff --git a/duniter4j-es-core/src/main/resources/META-INF/services/org.nuiton.config.ApplicationConfigProvider b/duniter4j-es-core/src/main/resources/META-INF/services/org.nuiton.config.ApplicationConfigProvider deleted file mode 100644 index f70e2417..00000000 --- a/duniter4j-es-core/src/main/resources/META-INF/services/org.nuiton.config.ApplicationConfigProvider +++ /dev/null @@ -1 +0,0 @@ -org.duniter.elasticsearch.config.ConfigurationProvider diff --git a/duniter4j-es-core/src/test/es-home/config/elasticsearch.yml b/duniter4j-es-core/src/test/es-home/config/elasticsearch.yml index 828ddbd0..b9d91647 100644 --- a/duniter4j-es-core/src/test/es-home/config/elasticsearch.yml +++ b/duniter4j-es-core/src/test/es-home/config/elasticsearch.yml @@ -125,8 +125,8 @@ duniter.blockchain.sync.enable: false # # Duniter node to synchronize # -duniter.host: cgeek.fr -duniter.port: 9330 +duniter.host: gtest.duniter.org +duniter.port: 10900 # # ---------------------------------- Duniter4j security ------------------------- # @@ -174,5 +174,5 @@ duniter.mail.admin: blavenie@EIS-DEV # #duniter.mail.subject.prefix: [Duniter4j ES] -duniter.changes.listenSource: */block +duniter.changes.listenSource: '*/block' duniter.ws.port: 9400 diff --git a/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/TestResource.java b/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/TestResource.java index 2b27a3e5..82860796 100644 --- a/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/TestResource.java +++ b/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/TestResource.java @@ -24,10 +24,13 @@ package org.duniter.elasticsearch; import com.google.common.collect.Lists; +import org.apache.commons.io.FileUtils; +import org.duniter.core.client.config.Configuration; import org.duniter.core.client.config.ConfigurationOption; import org.duniter.core.client.service.ServiceLocator; -import org.apache.commons.io.FileUtils; +import org.elasticsearch.bootstrap.Elasticsearch; import org.junit.runner.Description; +import org.nuiton.config.ApplicationConfig; import org.nuiton.i18n.I18n; import org.nuiton.i18n.init.DefaultI18nInitializer; import org.nuiton.i18n.init.UserI18nInitializer; @@ -64,14 +67,15 @@ public class TestResource extends org.duniter.core.test.TestResource { protected void before(Description description) throws Throwable { super.before(description); - // Initialize configuration - initConfiguration(getConfigFileName()); + // Prepare ES home + File esHomeDir = getResourceDirectory("es-home"); - // Init i18n - initI18n(); + System.setProperty("es.path.home", esHomeDir.getCanonicalPath()); - // Initialize service locator - ServiceLocator.instance().init(); + FileUtils.copyDirectory(new File("src/test/es-home"), esHomeDir); + FileUtils.copyDirectory(new File("target/classes"), new File(esHomeDir, "plugins/duniter4j-es-core")); + + Elasticsearch.main(new String[]{"start"}); } /** @@ -81,61 +85,7 @@ public class TestResource extends org.duniter.core.test.TestResource { * @return the prefix to use to retrieve configuration files */ protected String getConfigFilesPrefix() { - return "duniter4j-elasticsearch-test"; - } - - protected String getI18nBundleName() { - return "duniter4j-elasticsearch-i18n"; - } - - /* -- -- */ - - /** - * Convenience methods that could be override to initialize other configuration - * - * @param configFilename - * @param configArgs - */ - protected void initConfiguration(String configFilename) { - String[] configArgs = getConfigArgs(); - //PluginSettings config = new PluginSettings(configFilename, configArgs); - //PluginSettings.setInstance(config); - } - - protected void initI18n() throws IOException { - /*PluginSettings config ;//= PluginSettings.instance(); - - // --------------------------------------------------------------------// - // init i18n - // --------------------------------------------------------------------// - File i18nDirectory = new File(config.getDataDirectory(), "i18n"); - if (i18nDirectory.exists()) { - // clean i18n cache - FileUtils.cleanDirectory(i18nDirectory); - } - - FileUtils.forceMkdir(i18nDirectory); - - if (log.isDebugEnabled()) { - log.debug("I18N directory: " + i18nDirectory); - } - - Locale i18nLocale = config.getI18nLocale(); - - if (log.isInfoEnabled()) { - log.info(String.format("Starts i18n with locale [%s] at [%s]", - i18nLocale, i18nDirectory)); - } - I18n.init(new UserI18nInitializer( - i18nDirectory, new DefaultI18nInitializer(getI18nBundleName())), - i18nLocale);*/ - } - - protected String[] getConfigArgs() { - List<String> configArgs = Lists.newArrayList(); - configArgs.addAll(Lists.newArrayList( - "--option", ConfigurationOption.BASEDIR.getKey(), getResourceDirectory().getAbsolutePath())); - return configArgs.toArray(new String[configArgs.size()]); + return "duniter4j-es-core-test"; } } diff --git a/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/service/BlockchainServiceTest.java b/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/service/BlockchainServiceTest.java index a305ac1b..bb17bab8 100644 --- a/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/service/BlockchainServiceTest.java +++ b/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/service/BlockchainServiceTest.java @@ -23,18 +23,22 @@ package org.duniter.elasticsearch.service; */ +import com.fasterxml.jackson.databind.ObjectMapper; import org.duniter.core.client.config.Configuration; import org.duniter.core.client.model.bma.BlockchainBlock; +import org.duniter.core.client.model.bma.jackson.JacksonUtils; import org.duniter.core.client.model.local.Peer; import org.duniter.core.client.service.bma.BlockchainRemoteService; import org.duniter.elasticsearch.TestResource; -import org.junit.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; -@Ignore public class BlockchainServiceTest { private static final Logger log = LoggerFactory.getLogger(BlockchainServiceTest.class); @@ -43,115 +47,47 @@ public class BlockchainServiceTest { public static final TestResource resource = TestResource.create(); private BlockchainService service; - private BlockchainRemoteService blockchainRemoteService; + private BlockchainRemoteService remoteService; private Configuration config; private Peer peer; + private ObjectMapper objectMapper; @Before public void setUp() throws Exception { - //service = ServiceLocator.instance().getBlockIndexerService(); - //blockchainRemoteService = ServiceLocator.instance().getBlockchainRemoteService(); + service = ServiceLocator.instance().getBean(BlockchainService.class); + remoteService = ServiceLocator.instance().getBlockchainRemoteService(); config = Configuration.instance(); peer = createTestPeer(); + objectMapper = JacksonUtils.newObjectMapper(); - initLocalNode(); + // Init the currency + CurrencyService currencyService = ServiceLocator.instance().getBean(CurrencyService.class); + currencyService.createIndexIfNotExists() + .indexCurrencyFromPeer(peer); } @Test - public void createIndex() throws Exception { - String currencyName = resource.getFixtures().getCurrency(); - - // drop and recreate index - service.deleteIndex(currencyName); - - service.createIndex(currencyName); + public void indexLastBlocks() { + service.indexLastBlocks(peer); } - @Test - public void indexBlock() throws Exception { - // Read a block - BlockchainBlock currentBlock = blockchainRemoteService.getCurrentBlock(peer); - - // Create a new non-existing block - service.indexBlock(currentBlock, true); + public void indexBlock() { + BlockchainBlock current = remoteService.getCurrentBlock(peer); + service.indexCurrentBlock(current, true/*wait*/); - // Update a existing block - { - currentBlock.setMembersCount(1000000); + try { + String blockStr = objectMapper.writeValueAsString(current); - service.indexBlock(currentBlock, true); + service.indexBlockFromJson(peer, blockStr, true/*is rurrent*/, false/*detected fork*/, true/*wait*/); + } + catch(Exception e) { + Assert.fail(e.getMessage()); } - } - - @Test - public void indexCurrentBlock() throws Exception { - // Create a block with a fake hash - BlockchainBlock aBlock = blockchainRemoteService.getBlock(peer, 8450); - service.indexCurrentBlock(aBlock, true); - } - - @Test - // FIXME make this works - @Ignore - public void searchBlocks() throws Exception { - String currencyName = resource.getFixtures().getCurrency(); - - // Create a block with a fake hash - BlockchainBlock aBlock = blockchainRemoteService.getCurrentBlock(peer); - aBlock.setHash("myUnitTestHash"); - service.saveBlock(aBlock, true, true); - - Thread.sleep(5 * 1000); // wait 5s that ES process the block - - // match multi words - String queryText = aBlock.getHash(); - List<BlockchainBlock> blocks = service.findBlocksByHash(currencyName, queryText); - //assertResults(queryText, blocks); - - Thread.sleep(5 * 1000); // wait 5s that ES process the block - - BlockchainBlock loadBlock = service.getBlockById(currencyName, aBlock.getNumber()); - Assert.assertNotNull(loadBlock); - Assert.assertEquals(aBlock.getHash(), loadBlock.getHash()); - } - - @Test - public void getMaxBlockNumber() throws Exception { - String currencyName = resource.getFixtures().getCurrency(); - - // match multi words - Integer maxBlockNumber = service.getMaxBlockNumber(currencyName); - Assert.assertNotNull(maxBlockNumber); - } - - - @Test - @Ignore - public void allInOne() throws Exception { - - createIndex(); - indexBlock(); - searchBlocks(); } /* -- internal methods */ - protected void initLocalNode() throws Exception { - String currencyName = resource.getFixtures().getCurrency(); - - // Make sure the index exists - service.deleteIndex(currencyName); - service.createIndex(currencyName); - - // Get the first block from peer - BlockchainBlock firstBlock = blockchainRemoteService.getBlock(peer, 0); - - // Make sure the block has been indexed - service.indexBlock(firstBlock, true); - - } - protected void assertResults(String queryText, List<BlockchainBlock> result) { log.info(String.format("Results for a search on [%s]", queryText)); Assert.assertNotNull(result); diff --git a/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/service/CurrencyServiceTest.java b/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/service/CurrencyServiceTest.java new file mode 100644 index 00000000..a7626d6e --- /dev/null +++ b/duniter4j-es-core/src/test/java/org/duniter/elasticsearch/service/CurrencyServiceTest.java @@ -0,0 +1,81 @@ +package org.duniter.elasticsearch.service; + +/* + * #%L + * UCoin Java Client :: Core API + * %% + * Copyright (C) 2014 - 2015 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import org.duniter.core.client.config.Configuration; +import org.duniter.core.client.model.bma.BlockchainBlock; +import org.duniter.core.client.model.local.Peer; +import org.duniter.core.client.service.bma.BlockchainRemoteService; +import org.duniter.elasticsearch.TestResource; +import org.junit.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +@Ignore +public class CurrencyServiceTest { + + private static final Logger log = LoggerFactory.getLogger(CurrencyServiceTest.class); + + @ClassRule + public static final TestResource resource = TestResource.create(); + + private BlockchainRemoteService blockchainRemoteService; + private CurrencyService service; + private Configuration config; + private Peer peer; + + @Before + public void setUp() throws Exception { + service = ServiceLocator.instance().getBean(CurrencyService.class); + blockchainRemoteService = ServiceLocator.instance().getBlockchainRemoteService(); + config = Configuration.instance(); + peer = createTestPeer(); + } + + @Test + public void createIndexIfNotExists() throws Exception { + + // drop and recreate index + service.deleteIndex().createIndexIfNotExists(); + } + + @Test + public void indexCurrencyFromPeer() throws Exception { + service.createIndexIfNotExists() + .indexCurrencyFromPeer(peer); + } + + /* -- internal methods */ + + protected Peer createTestPeer() { + Peer peer = new Peer( + Configuration.instance().getNodeHost(), + Configuration.instance().getNodePort()); + + return peer; + } + +} diff --git a/duniter4j-es-core/src/test/resources/META-INF/services/org.duniter.core.beans.Bean b/duniter4j-es-core/src/test/resources/META-INF/services/org.duniter.core.beans.Bean index 1d327a74..6613b03e 100644 --- a/duniter4j-es-core/src/test/resources/META-INF/services/org.duniter.core.beans.Bean +++ b/duniter4j-es-core/src/test/resources/META-INF/services/org.duniter.core.beans.Bean @@ -8,7 +8,6 @@ org.duniter.core.client.service.HttpServiceImpl org.duniter.core.client.service.DataContext org.duniter.core.client.service.local.PeerServiceImpl org.duniter.core.client.service.local.CurrencyServiceImpl -org.duniter.core.client.dao.mem.MemoryCurrencyDaoImpl -org.duniter.core.client.dao.mem.MemoryPeerDaoImpl -org.duniter.elasticsearch.service.ElasticSearchService -org.duniter.elasticsearch.service.registry.CurrencyRegistryService \ No newline at end of file +org.duniter.elasticsearch.dao.impl.CurrencyDaoImpl +org.duniter.elasticsearch.dao.impl.PeerDaoImpl +org.duniter.elasticsearch.dao.impl.BlockDaoImpl diff --git a/duniter4j-es-core/src/test/resources/duniter4j-elasticsearch-localhost-node.properties b/duniter4j-es-core/src/test/resources/duniter4j-elasticsearch-localhost-node.properties deleted file mode 100644 index a7974bcf..00000000 --- a/duniter4j-es-core/src/test/resources/duniter4j-elasticsearch-localhost-node.properties +++ /dev/null @@ -1,12 +0,0 @@ -duniter4j.node.host=g1.duniter.fr -duniter4j.node.port=10901 - -duniter4j.elasticsearch.embedded.enable=false -duniter4j.elasticsearch.local=false -duniter4j.elasticsearch.http.enable=false -duniter4j.elasticsearch.cluster.name=duniter4j-elacticsearch-test - -#duniter4j.elasticsearch.cluster.name=duniter4j-elacticsearch - -duniter4j.elasticsearch.host=localhost -duniter4j.elasticsearch.port=9300 diff --git a/duniter4j-es-core/src/test/resources/duniter4j-elasticsearch-test.properties b/duniter4j-es-core/src/test/resources/duniter4j-elasticsearch-test.properties deleted file mode 100644 index 301e4735..00000000 --- a/duniter4j-es-core/src/test/resources/duniter4j-elasticsearch-test.properties +++ /dev/null @@ -1,16 +0,0 @@ -duniter4j.node.host=g1.duniter.org -duniter4j.node.port=10901 - -duniter4j.basedir=target/es-home - -#duniter4j.elasticsearch.data -#duniter4j.elasticsearch.embedded.enable=true -duniter4j.elasticsearch.local=false -duniter4j.elasticsearch.http.enable=true -duniter4j.elasticsearch.cluster.name=duniter4j-elasticsearch - -#duniter4j.elasticsearch.cluster.name=duniter4j-elacticsearch - -duniter4j.elasticsearch.embedded.enable=false -duniter4j.elasticsearch.host=192.168.0.5 -duniter4j.elasticsearch.port=9300 diff --git a/duniter4j-es-core/src/test/resources/duniter4j-es-core-test.properties b/duniter4j-es-core/src/test/resources/duniter4j-es-core-test.properties new file mode 100644 index 00000000..608cea0e --- /dev/null +++ b/duniter4j-es-core/src/test/resources/duniter4j-es-core-test.properties @@ -0,0 +1 @@ +#Empty test file (need for inherited TestResource). See files 'src/test/es-home/config' \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/AbstractCommentDaoImpl.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/AbstractCommentDaoImpl.java deleted file mode 100644 index 52944b00..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/AbstractCommentDaoImpl.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao; - -/* - * #%L - * UCoin Java Client :: Core API - * %% - * Copyright (C) 2014 - 2015 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - - -import com.fasterxml.jackson.core.JsonProcessingException; -import org.duniter.core.client.model.elasticsearch.RecordComment; -import org.duniter.core.exception.TechnicalException; -import org.duniter.elasticsearch.dao.AbstractIndexTypeDao; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.CommentDao; -import org.elasticsearch.action.search.SearchPhaseExecutionException; -import org.elasticsearch.action.search.SearchRequestBuilder; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.SearchType; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.index.query.TermQueryBuilder; - -import java.io.IOException; - -/** - * Created by Benoit on 30/03/2015. - */ -public class AbstractCommentDaoImpl<T extends AbstractCommentDaoImpl> extends AbstractIndexTypeDao<T> implements CommentDao<T> { - - - protected PluginSettings pluginSettings; - - public AbstractCommentDaoImpl(String index, PluginSettings pluginSettings) { - super(index, CommentDao.TYPE); - this.pluginSettings = pluginSettings; - } - - @Override - protected void createIndex() throws JsonProcessingException { - throw new TechnicalException("not implemented"); - } - - public String create(final String json) { - return super.indexDocumentFromJson(json); - } - - public void update(final String id, final String json) { - super.updateDocumentFromJson(id, json); - } - - @Override - public long countReplies(String id) { - - // Prepare count request - SearchRequestBuilder searchRequest = client - .prepareSearch(getIndex()) - .setTypes(getType()) - .setFetchSource(false) - .setSearchType(SearchType.QUERY_AND_FETCH) - .setSize(0); - - // Query = filter on reference - TermQueryBuilder query = QueryBuilders.termQuery(RecordComment.PROPERTY_REPLY_TO_JSON, id); - searchRequest.setQuery(query); - - // Execute query - try { - SearchResponse response = searchRequest.execute().actionGet(); - return response.getHits().getTotalHits(); - } - catch(SearchPhaseExecutionException e) { - // Failed or no item on index - logger.error(String.format("Error while counting comment replies: %s", e.getMessage()), e); - } - return 1; - } - - - public XContentBuilder createTypeMapping() { - String stringAnalyzer = pluginSettings.getDefaultStringAnalyzer(); - - try { - XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject(getType()) - .startObject("properties") - - // issuer - .startObject("issuer") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - // time - .startObject("time") - .field("type", "integer") - .endObject() - - // message - .startObject("message") - .field("type", "string") - .field("analyzer", stringAnalyzer) - .endObject() - - // record - .startObject("record") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - // reply to - .startObject("reply_to") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - // aggregations - .startObject("aggregations") - .field("type", "nested") - .field("dynamic", "true") - .startObject("properties") - .startObject("reply_count") - .field("type", "integer") - .field("index", "not_analyzed") - .endObject() - .endObject() - .endObject() - - .endObject() - .endObject().endObject(); - - return mapping; - } - catch(IOException ioe) { - throw new TechnicalException(String.format("Error while getting mapping for index [%s]: %s", getType(), ioe.getMessage()), ioe); - } - } - -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/AbstractRecordDaoImpl.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/AbstractRecordDaoImpl.java deleted file mode 100644 index 64813724..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/AbstractRecordDaoImpl.java +++ /dev/null @@ -1,210 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao; - -/* - * #%L - * UCoin Java Client :: Core API - * %% - * Copyright (C) 2014 - 2015 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - - -import com.fasterxml.jackson.core.JsonProcessingException; -import org.duniter.core.client.model.elasticsearch.Record; -import org.duniter.core.exception.TechnicalException; -import org.duniter.core.util.ObjectUtils; -import org.duniter.elasticsearch.dao.AbstractIndexTypeDao; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.RecordDao; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; - -import java.io.IOException; - -/** - * Created by Benoit on 30/03/2015. - */ -public class AbstractRecordDaoImpl<T extends AbstractRecordDaoImpl> extends AbstractIndexTypeDao<T> implements RecordDao<T> { - - protected PluginSettings pluginSettings; - - public AbstractRecordDaoImpl(String index, PluginSettings pluginSettings) { - super(index, RecordDao.TYPE); - this.pluginSettings = pluginSettings; - } - - @Override - protected void createIndex() throws JsonProcessingException { - throw new TechnicalException("not implemented"); - } - - @Override - public void checkSameDocumentIssuer(String id, String expectedIssuer) { - String issuer = getMandatoryFieldsById(id, Record.PROPERTY_ISSUER).get(Record.PROPERTY_ISSUER).toString(); - if (!ObjectUtils.equals(expectedIssuer, issuer)) { - throw new TechnicalException("Not same issuer"); - } - } - - public XContentBuilder createTypeMapping() { - String stringAnalyzer = pluginSettings.getDefaultStringAnalyzer(); - - try { - XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject(getType()) - .startObject("properties") - - // title - .startObject("title") - .field("type", "string") - .field("analyzer", stringAnalyzer) - .endObject() - - // description - .startObject("description") - .field("type", "string") - .field("analyzer", stringAnalyzer) - .endObject() - - // creationTime - .startObject("creationTime") - .field("type", "integer") - .endObject() - - // time - .startObject("time") - .field("type", "integer") - .endObject() - - // issuer - .startObject("issuer") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - // pubkey - .startObject("pubkey") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - // address - .startObject("address") - .field("type", "string") - .field("analyzer", stringAnalyzer) - .endObject() - - // city - .startObject("city") - .field("type", "string") - .endObject() - - // geoPoint - .startObject("geoPoint") - .field("type", "geo_point") - .endObject() - - // thumbnail - .startObject("thumbnail") - .field("type", "attachment") - .startObject("fields") // src - .startObject("content") // title - .field("index", "no") - .endObject() - .startObject("title") // title - .field("type", "string") - .field("store", "no") - .endObject() - .startObject("author") // title - .field("store", "no") - .endObject() - .startObject("content_type") // title - .field("store", "yes") - .endObject() - .endObject() - .endObject() - - // pictures - .startObject("pictures") - .field("type", "nested") - .field("dynamic", "false") - .startObject("properties") - .startObject("file") // file - .field("type", "attachment") - .startObject("fields") - .startObject("content") // content - .field("index", "no") - .endObject() - .startObject("title") // title - .field("type", "string") - .field("store", "yes") - .field("analyzer", stringAnalyzer) - .endObject() - .startObject("author") // author - .field("type", "string") - .field("store", "no") - .endObject() - .startObject("content_type") // content_type - .field("store", "yes") - .endObject() - .endObject() - .endObject() - .endObject() - .endObject() - - // picturesCount - .startObject("picturesCount") - .field("type", "integer") - .endObject() - - // category - .startObject("category") - .field("type", "nested") - .field("dynamic", "false") - .startObject("properties") - .startObject("id") // id - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - .startObject("parent") // parent - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - .startObject("name") // name - .field("type", "string") - .field("analyzer", stringAnalyzer) - .endObject() - .endObject() - .endObject() - - // tags - .startObject("tags") - .field("type", "completion") - .field("search_analyzer", "simple") - .field("analyzer", "simple") - .field("preserve_separators", "false") - .endObject() - - .endObject() - .endObject().endObject(); - - return mapping; - } - catch(IOException ioe) { - throw new TechnicalException(String.format("Error while getting mapping for index [%s/%s]: %s", getIndex(), getType(), ioe.getMessage()), ioe); - } - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/CommentDao.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/CommentDao.java deleted file mode 100644 index 3cefe399..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/CommentDao.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao; - -/* - * #%L - * UCoin Java Client :: Core API - * %% - * Copyright (C) 2014 - 2015 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - - -import org.duniter.elasticsearch.dao.IndexTypeDao; - -/** - * Created by Benoit on 30/03/2015. - */ -public interface CommentDao<T extends CommentDao> extends IndexTypeDao<T> { - - String TYPE = "comment"; - - String create(final String json); - - void update(final String id, final String json); - - long countReplies(String id); - -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/DaoModule.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/DaoModule.java deleted file mode 100644 index 65625ab0..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/DaoModule.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.core.beans.Bean; -import org.duniter.elasticsearch.client.Duniter4jClientImpl; -import org.duniter.elasticsearch.gchange.dao.market.*; -import org.duniter.elasticsearch.gchange.dao.registry.*; -import org.duniter.elasticsearch.service.ServiceLocator; -import org.elasticsearch.common.inject.AbstractModule; -import org.elasticsearch.common.inject.Module; - -public class DaoModule extends AbstractModule implements Module { - - @Override protected void configure() { - - bind(RegistryIndexDao.class).to(RegistryIndexDaoImpl.class).asEagerSingleton(); - bind(RegistryCommentDao.class).to(RegistryCommentDaoImpl.class).asEagerSingleton(); - bind(RegistryRecordDao.class).to(RegistryRecordDaoImpl.class).asEagerSingleton(); - - bind(MarketIndexDao.class).to(MarketIndexDaoImpl.class).asEagerSingleton(); - bind(MarketCommentDao.class).to(MarketCommentDaoImpl.class).asEagerSingleton(); - bind(MarketRecordDao.class).to(MarketRecordDaoImpl.class).asEagerSingleton(); - } - - /* protected methods */ - - protected <T extends Bean> void bindWithLocator(Class<T> clazz) { - bind(clazz).toProvider(new ServiceLocator.Provider<>(clazz)); - } - -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/location/CitiesLocationDaoImpl.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/location/CitiesLocationDaoImpl.java deleted file mode 100644 index bcdf9807..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/location/CitiesLocationDaoImpl.java +++ /dev/null @@ -1,349 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.location; - -/* - * #%L - * UCoin Java Client :: Core API - * %% - * Copyright (C) 2014 - 2015 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - - -import com.fasterxml.jackson.core.JsonProcessingException; -import org.duniter.core.exception.TechnicalException; -import org.duniter.elasticsearch.PluginSettings; -import org.duniter.elasticsearch.dao.AbstractDao; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.logging.ESLogger; -import org.elasticsearch.common.logging.ESLoggerFactory; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; - -import java.io.IOException; - -/** - * Created by Benoit on 30/03/2015. - */ -public class CitiesLocationDaoImpl extends AbstractDao { - - private static final ESLogger log = ESLoggerFactory.getLogger(CitiesLocationDaoImpl.class.getName()); - - private static final String CITIES_BULK_FILENAME = "registry-cities-bulk-insert.json"; - - private static final String CITIES_SOURCE_CLASSPATH_FILE = "cities/countriesToCities.json"; - - private static final String CITIES_SOURCE_FILE2 = "/home/blavenie/git/ucoin-io/duniter4j/duniter4j-elasticsearch/src/main/misc/geoflar-communes-2015.geojson"; - - public static final String INDEX = "location"; - public static final String CITY_TYPE = "city"; - - public CitiesLocationDaoImpl() { - super("gchange.location.cities"); - } - - /** - * Delete blockchain index, and all data - * @throws JsonProcessingException - */ - public void deleteIndex() throws JsonProcessingException { - client.deleteIndexIfExists(INDEX); - } - - - public boolean existsIndex() { - return client.existsIndex(INDEX); - } - - /** - * Create index need for blockchain registry, if need - */ - public void createIndexIfNotExists() { - try { - if (!client.existsIndex(INDEX)) { - createIndex(); - } - } - catch(JsonProcessingException e) { - throw new TechnicalException(String.format("Error while creating index [%s]", INDEX)); - } - } - - /** - * Create index need for category registry - * @throws JsonProcessingException - */ - public void createIndex() throws JsonProcessingException { - log.info(String.format("Creating index [%s/%s]", INDEX, CITY_TYPE)); - - CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(INDEX); - org.elasticsearch.common.settings.Settings indexSettings = org.elasticsearch.common.settings.Settings.settingsBuilder() - .put("number_of_shards", 1) - .put("number_of_replicas", 1) - //.put("analyzer", createDefaultAnalyzer()) - .build(); - createIndexRequestBuilder.setSettings(indexSettings); - createIndexRequestBuilder.addMapping(CITY_TYPE, createIndexMapping()); - createIndexRequestBuilder.execute().actionGet(); - } - - public void initCities() { - if (log.isDebugEnabled()) { - log.debug("Initializing allOfToList registry cities"); - } - - //File bulkFile = createCitiesBulkFile2(); - - // Insert cities - //bulkFromFile(bulkFile, INDEX, CITY_TYPE); - } - - - /* -- Internal methods -- */ - - - public XContentBuilder createIndexMapping() { - - try { - XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject(CITY_TYPE) - .startObject("properties") - - // city - .startObject("name") - .field("type", "string") - .endObject() - - // country - .startObject("country") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - .endObject() - .endObject().endObject(); - - return mapping; - } - catch(IOException ioe) { - throw new TechnicalException(String.format("Error while getting mapping for index [%s/%s]: %s", INDEX, CITY_TYPE, ioe.getMessage()), ioe); - } - } - - /* - public File createCitiesBulkFile() { - - File result = new File(pluginSettings.getTempDirectory(), CITIES_BULK_FILENAME); - - InputStream ris = null; - BufferedReader bf = null; - FileWriter fw = null; - try { - if (result.exists()) { - FileUtils.forceDelete(result); - } - else if (!result.getParentFile().exists()) { - FileUtils.forceMkdir(result.getParentFile()); - } - - ris = getClass().getClassLoader().getResourceAsStream(CITIES_SOURCE_CLASSPATH_FILE); - if (ris == null) { - throw new TechnicalException(String.format("Could not retrieve file [%s] from test classpath. Make sure git submodules has been initialized before building.", CITIES_SOURCE_CLASSPATH_FILE)); - } - - boolean firstLine = true; - java.lang.reflect.Type typeOfHashMap = new TypeToken<Map<String, String[]>>() { }.getType(); - - Gson gson = GsonUtils.newBuilder().create(); - - StringBuilder builder = new StringBuilder(); - bf = new BufferedReader( - new InputStreamReader( - ris, "UTF-16LE"), 2048); - - fw = new FileWriter(result); - char[] buf = new char[2048]; - int len; - - while((len = bf.read(buf)) != -1) { - String bufStr = new String(buf, 0, len); - - if (firstLine) { - // Remove UTF-16 BOM char - int objectStartIndex = bufStr.indexOf('\uFEFF'); - if (objectStartIndex != -1) { - bufStr = bufStr.substring(objectStartIndex); - } - firstLine=false; - } - - int arrayEndIndex = bufStr.indexOf("],\""); - if (arrayEndIndex == -1) { - arrayEndIndex = bufStr.indexOf("]}"); - } - - if (arrayEndIndex == -1) { - builder.append(bufStr); - } - else { - builder.append(bufStr.substring(0, arrayEndIndex+1)); - builder.append("}"); - if (log.isTraceEnabled()) { - log.trace(builder.toString()); - } - Map<String, String[]> citiesByCountry = gson.fromJson(builder.toString(), typeOfHashMap); - - builder.setLength(0); - for (String country: citiesByCountry.keySet()) { - if (StringUtils.isNotBlank(country)) { - for (String city : citiesByCountry.get(country)) { - if (StringUtils.isNotBlank(city)) { - fw.write(String.format("{\"index\":{\"_id\" : \"%s-%s\"}}\n", country, city)); - fw.write(String.format("{\"country\":\"%s\", \"name\":\"%s\"}\n", country, city)); - } - } - } - } - - fw.flush(); - - // reset and prepare buffer for next country - builder.setLength(0); - builder.append("{"); - if (arrayEndIndex+2 < bufStr.length()) { - builder.append(bufStr.substring(arrayEndIndex+2)); - } - } - } - - fw.close(); - bf.close(); - - } catch(Exception e) { - throw new TechnicalException(String.format("Error while creating cities file [%s]", result.getName()), e); - } - finally { - IOUtils.closeQuietly(bf); - IOUtils.closeQuietly(ris); - IOUtils.closeQuietly(fw); - } - - return result; - } - - public File createCitiesBulkFile2() { - - File result = new File(pluginSettings.getTempDirectory(), CITIES_BULK_FILENAME); - File inputFile = new File(CITIES_SOURCE_FILE2); - - InputStream ris = null; - BufferedReader bf = null; - FileWriter fw = null; - try { - if (result.exists()) { - FileUtils.forceDelete(result); - } - else if (!result.getParentFile().exists()) { - FileUtils.forceMkdir(result.getParentFile()); - } - - ris = new BufferedInputStream(new FileInputStream(inputFile)); - if (ris == null) { - throw new TechnicalException(String.format("Could not retrieve file [%s] from test classpath. Make sure git submodules has been initialized before building.", CITIES_SOURCE_FILE2)); - } - - boolean firstLine = true; - java.lang.reflect.Type typeOfHashMap = new TypeToken<Map<String, String[]>>() { }.getType(); - - Gson gson = GsonUtils.newBuilder().create(); - - StringBuilder builder = new StringBuilder(); - bf = new BufferedReader( - new InputStreamReader( - ris, "UTF-16LE"), 2048); - - fw = new FileWriter(result); - char[] buf = new char[2048]; - int len; - - while((len = bf.read(buf)) != -1) { - String bufStr = new String(buf, 0, len); - - if (firstLine) { - // Remove UTF-16 BOM char - int objectStartIndex = bufStr.indexOf('\uFEFF'); - if (objectStartIndex != -1) { - bufStr = bufStr.substring(objectStartIndex); - } - firstLine=false; - } - - int arrayEndIndex = bufStr.indexOf("],\""); - if (arrayEndIndex == -1) { - arrayEndIndex = bufStr.indexOf("]}"); - } - - if (arrayEndIndex == -1) { - builder.append(bufStr); - } - else { - builder.append(bufStr.substring(0, arrayEndIndex+1)); - builder.append("}"); - if (log.isTraceEnabled()) { - log.trace(builder.toString()); - } - Map<String, String[]> citiesByCountry = gson.fromJson(builder.toString(), typeOfHashMap); - - builder.setLength(0); - for (String country: citiesByCountry.keySet()) { - if (StringUtils.isNotBlank(country)) { - for (String city : citiesByCountry.get(country)) { - if (StringUtils.isNotBlank(city)) { - fw.write(String.format("{\"index\":{\"_id\" : \"%s-%s\"}}\n", country, city)); - fw.write(String.format("{\"country\":\"%s\", \"name\":\"%s\"}\n", country, city)); - } - } - } - } - - fw.flush(); - - // reset and prepare buffer for next country - builder.setLength(0); - builder.append("{"); - if (arrayEndIndex+2 < bufStr.length()) { - builder.append(bufStr.substring(arrayEndIndex+2)); - } - } - } - - fw.close(); - bf.close(); - - } catch(Exception e) { - throw new TechnicalException(String.format("Error while creating cities file [%s]", result.getName()), e); - } - finally { - IOUtils.closeQuietly(bf); - IOUtils.closeQuietly(ris); - IOUtils.closeQuietly(fw); - } - - return result; - } - */ -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketCommentDao.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketCommentDao.java deleted file mode 100644 index a3f16efa..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketCommentDao.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.market; - -import org.duniter.elasticsearch.gchange.dao.CommentDao; - -/** - * Created by blavenie on 03/04/17. - */ -public interface MarketCommentDao extends CommentDao { -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketCommentDaoImpl.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketCommentDaoImpl.java deleted file mode 100644 index 415f3ba1..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketCommentDaoImpl.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.market; - -import org.duniter.core.exception.TechnicalException; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.AbstractCommentDaoImpl; -import org.duniter.elasticsearch.gchange.dao.AbstractRecordDaoImpl; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; - -import java.io.IOException; - -/** - * Created by blavenie on 03/04/17. - */ -public class MarketCommentDaoImpl extends AbstractCommentDaoImpl implements MarketCommentDao { - - @Inject - public MarketCommentDaoImpl(PluginSettings pluginSettings) { - super(MarketIndexDao.INDEX, pluginSettings); - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketIndexDao.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketIndexDao.java deleted file mode 100644 index 2e3f3617..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketIndexDao.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.market; - -import org.duniter.elasticsearch.dao.IndexDao; - -/** - * Created by blavenie on 03/04/17. - */ -public interface MarketIndexDao extends IndexDao<MarketIndexDao> { - String INDEX = "market"; - String CATEGORY_TYPE = "category"; -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketIndexDaoImpl.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketIndexDaoImpl.java deleted file mode 100644 index 69548e97..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketIndexDaoImpl.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.market; - -import com.fasterxml.jackson.core.JsonProcessingException; -import org.duniter.core.exception.TechnicalException; -import org.duniter.elasticsearch.dao.AbstractIndexDao; -import org.duniter.elasticsearch.dao.AbstractIndexTypeDao; -import org.duniter.elasticsearch.dao.IndexTypeDao; -import org.duniter.elasticsearch.dao.handler.AddSequenceAttributeHandler; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.CommentDao; -import org.duniter.elasticsearch.gchange.dao.RecordDao; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; - -import java.io.IOException; - -/** - * Created by blavenie on 03/04/17. - */ -public class MarketIndexDaoImpl extends AbstractIndexDao<MarketIndexDao> implements MarketIndexDao { - - private static final String CATEGORIES_BULK_CLASSPATH_FILE = "registry-categories-bulk-insert.json"; - - private PluginSettings pluginSettings; - private IndexTypeDao<?> categoryDao; - private RecordDao recordDao; - private CommentDao commentDao; - - @Inject - public MarketIndexDaoImpl(PluginSettings pluginSettings, MarketRecordDao recordDao, MarketCommentDao commentDao) { - super(MarketIndexDao.INDEX); - - this.pluginSettings = pluginSettings; - this.commentDao = commentDao; - this.recordDao = recordDao; - this.categoryDao = createCategoryDao(pluginSettings); - } - - - @Override - protected void createIndex() throws JsonProcessingException { - logger.info(String.format("Creating index [%s]", INDEX)); - - CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(INDEX); - org.elasticsearch.common.settings.Settings indexSettings = org.elasticsearch.common.settings.Settings.settingsBuilder() - .put("number_of_shards", 3) - .put("number_of_replicas", 1) - //.put("analyzer", createDefaultAnalyzer()) - .build(); - createIndexRequestBuilder.setSettings(indexSettings); - createIndexRequestBuilder.addMapping(recordDao.getType(), recordDao.createTypeMapping()); - createIndexRequestBuilder.addMapping(commentDao.getType(), commentDao.createTypeMapping()); - createIndexRequestBuilder.addMapping(categoryDao.getType(), categoryDao.createTypeMapping()); - createIndexRequestBuilder.execute().actionGet(); - - // Fill categories - fillRecordCategories(); - } - - public void fillRecordCategories() { - if (logger.isDebugEnabled()) { - logger.debug(String.format("[%s/%s] Fill data", INDEX, MarketIndexDao.CATEGORY_TYPE)); - } - - // Insert categories - categoryDao.bulkFromClasspathFile(CATEGORIES_BULK_CLASSPATH_FILE, - // Add order attribute - new AddSequenceAttributeHandler("order", "\\{.*\"name\".*\\}", 1)); - } - - - protected IndexTypeDao<?> createCategoryDao(final PluginSettings settings) { - return new AbstractIndexTypeDao(INDEX, MarketIndexDao.CATEGORY_TYPE) { - @Override - protected void createIndex() throws JsonProcessingException { - throw new TechnicalException("not implemented"); - } - - @Override - public XContentBuilder createTypeMapping() { - try { - XContentBuilder mapping = XContentFactory.jsonBuilder().startObject() - .startObject(getType()) - .startObject("properties") - - // name - .startObject("name") - .field("type", "string") - .field("analyzer", settings.getDefaultStringAnalyzer()) - .endObject() - - // parent - .startObject("parent") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - .endObject() - .endObject().endObject(); - - return mapping; - } - catch(IOException ioe) { - throw new TechnicalException(String.format("Error while getting mapping for index [%s/%s]: %s", getIndex(), getType(), ioe.getMessage()), ioe); - } - } - }; - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketRecordDao.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketRecordDao.java deleted file mode 100644 index 7b4238a9..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketRecordDao.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.market; - -import org.duniter.elasticsearch.gchange.dao.RecordDao; - -/** - * Created by blavenie on 03/04/17. - */ -public interface MarketRecordDao extends RecordDao { -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketRecordDaoImpl.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketRecordDaoImpl.java deleted file mode 100644 index f5f855d7..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/market/MarketRecordDaoImpl.java +++ /dev/null @@ -1,182 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.market; - -import org.duniter.core.exception.TechnicalException; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.AbstractRecordDaoImpl; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; - -import java.io.IOException; - -/** - * Created by blavenie on 03/04/17. - */ -public class MarketRecordDaoImpl extends AbstractRecordDaoImpl implements MarketRecordDao { - - @Inject - public MarketRecordDaoImpl(PluginSettings pluginSettings) { - super(MarketIndexDao.INDEX, pluginSettings); - } - - @Override - public XContentBuilder createTypeMapping() { - String stringAnalyzer = pluginSettings.getDefaultStringAnalyzer(); - - try { - XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject(getType()) - .startObject("properties") - - // title - .startObject("title") - .field("type", "string") - .field("analyzer", stringAnalyzer) - .endObject() - - // description - .startObject("description") - .field("type", "string") - .field("analyzer", stringAnalyzer) - .endObject() - - // creationTime - .startObject("creationTime") - .field("type", "integer") - .endObject() - - // time - .startObject("time") - .field("type", "integer") - .endObject() - - // price - .startObject("price") - .field("type", "double") - .endObject() - - // price Unit - .startObject("unit") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - // currency - .startObject("currency") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - // issuer - .startObject("issuer") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - // type (offer, need, ...) - .startObject("type") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - // location - .startObject("location") - .field("type", "string") - .field("analyzer", stringAnalyzer) - .endObject() - - // geoPoint - .startObject("geoPoint") - .field("type", "geo_point") - .endObject() - - // thumbnail - .startObject("thumbnail") - .field("type", "attachment") - .startObject("fields") // src - .startObject("content") // title - .field("index", "no") - .endObject() - .startObject("title") // title - .field("type", "string") - .field("store", "no") - .endObject() - .startObject("author") // title - .field("store", "no") - .endObject() - .startObject("content_type") // title - .field("store", "yes") - .endObject() - .endObject() - .endObject() - - // pictures - .startObject("pictures") - .field("type", "nested") - .field("dynamic", "false") - .startObject("properties") - .startObject("file") // file - .field("type", "attachment") - .startObject("fields") - .startObject("content") // content - .field("index", "no") - .endObject() - .startObject("title") // title - .field("type", "string") - .field("store", "yes") - .field("analyzer", stringAnalyzer) - .endObject() - .startObject("author") // author - .field("type", "string") - .field("store", "no") - .endObject() - .startObject("content_type") // content_type - .field("store", "yes") - .endObject() - .endObject() - .endObject() - .endObject() - .endObject() - - // picturesCount - .startObject("picturesCount") - .field("type", "integer") - .endObject() - - // category - .startObject("category") - .field("type", "nested") - .field("dynamic", "false") - .startObject("properties") - .startObject("id") // id - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - .startObject("parent") // parent - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - .startObject("name") // name - .field("type", "string") - .field("analyzer", stringAnalyzer) - .endObject() - .endObject() - .endObject() - - // tags - .startObject("tags") - .field("type", "completion") - .field("search_analyzer", "simple") - .field("analyzer", "simple") - .field("preserve_separators", "false") - .endObject() - - .endObject() - .endObject().endObject(); - - return mapping; - } - catch(IOException ioe) { - throw new TechnicalException(String.format("Error while getting mapping for index [%s/%s]: %s", getIndex(), getType(), ioe.getMessage()), ioe); - } - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryCommentDao.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryCommentDao.java deleted file mode 100644 index e70be6d0..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryCommentDao.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.registry; - -import org.duniter.elasticsearch.gchange.dao.CommentDao; - -/** - * Created by blavenie on 03/04/17. - */ -public interface RegistryCommentDao extends CommentDao { -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryCommentDaoImpl.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryCommentDaoImpl.java deleted file mode 100644 index c9d4b28a..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryCommentDaoImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.registry; - -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.AbstractCommentDaoImpl; -import org.elasticsearch.common.inject.Inject; - -/** - * Created by blavenie on 03/04/17. - */ -public class RegistryCommentDaoImpl extends AbstractCommentDaoImpl implements RegistryCommentDao { - - - @Inject - public RegistryCommentDaoImpl(PluginSettings pluginSettings) { - super(RegistryIndexDao.INDEX, pluginSettings); - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryIndexDao.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryIndexDao.java deleted file mode 100644 index f803d173..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryIndexDao.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.registry; - -import org.duniter.elasticsearch.dao.IndexDao; - -/** - * Created by blavenie on 03/04/17. - */ -public interface RegistryIndexDao extends IndexDao<RegistryIndexDao> { - String INDEX = "registry"; - String CATEGORY_TYPE = "category"; -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryIndexDaoImpl.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryIndexDaoImpl.java deleted file mode 100644 index c62ded09..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryIndexDaoImpl.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.registry; - -import com.fasterxml.jackson.core.JsonProcessingException; -import org.duniter.core.exception.TechnicalException; -import org.duniter.elasticsearch.dao.AbstractIndexDao; -import org.duniter.elasticsearch.dao.AbstractIndexTypeDao; -import org.duniter.elasticsearch.dao.IndexDao; -import org.duniter.elasticsearch.dao.IndexTypeDao; -import org.duniter.elasticsearch.dao.handler.AddSequenceAttributeHandler; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.AbstractCommentDaoImpl; -import org.duniter.elasticsearch.gchange.dao.AbstractRecordDaoImpl; -import org.duniter.elasticsearch.gchange.dao.CommentDao; -import org.duniter.elasticsearch.gchange.dao.RecordDao; -import org.duniter.elasticsearch.gchange.service.RegistryService; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.inject.Injector; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; - -import java.io.IOException; - -/** - * Created by blavenie on 03/04/17. - */ -public class RegistryIndexDaoImpl extends AbstractIndexDao<RegistryIndexDao> implements RegistryIndexDao { - - - private static final String CATEGORIES_BULK_CLASSPATH_FILE = "registry-categories-bulk-insert.json"; - - private PluginSettings pluginSettings; - private IndexTypeDao<?> categoryDao; - private RecordDao recordDao; - private CommentDao commentDao; - - @Inject - public RegistryIndexDaoImpl(PluginSettings pluginSettings, RegistryRecordDao recordDao, RegistryCommentDao commentDao) { - super(RegistryIndexDao.INDEX); - - this.pluginSettings = pluginSettings; - this.commentDao = commentDao; - this.recordDao = recordDao; - this.categoryDao = createCategoryDao(pluginSettings); - } - - - @Override - protected void createIndex() throws JsonProcessingException { - logger.info(String.format("Creating index [%s]", INDEX)); - - CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(INDEX); - org.elasticsearch.common.settings.Settings indexSettings = org.elasticsearch.common.settings.Settings.settingsBuilder() - .put("number_of_shards", 3) - .put("number_of_replicas", 1) - //.put("analyzer", createDefaultAnalyzer()) - .build(); - createIndexRequestBuilder.setSettings(indexSettings); - createIndexRequestBuilder.addMapping(recordDao.getType(), recordDao.createTypeMapping()); - createIndexRequestBuilder.addMapping(commentDao.getType(), commentDao.createTypeMapping()); - createIndexRequestBuilder.addMapping(categoryDao.getType(), categoryDao.createTypeMapping()); - createIndexRequestBuilder.execute().actionGet(); - - // Fill categories - fillRecordCategories(); - } - - public void fillRecordCategories() { - if (logger.isDebugEnabled()) { - logger.debug(String.format("[%s/%s] Fill data", INDEX, RegistryIndexDao.CATEGORY_TYPE)); - } - - // Insert categories - categoryDao.bulkFromClasspathFile(CATEGORIES_BULK_CLASSPATH_FILE, - // Add order attribute - new AddSequenceAttributeHandler("order", "\\{.*\"name\".*\\}", 1)); - } - - - protected IndexTypeDao<?> createCategoryDao(final PluginSettings settings) { - return new AbstractIndexTypeDao(INDEX, RegistryIndexDao.CATEGORY_TYPE) { - @Override - protected void createIndex() throws JsonProcessingException { - throw new TechnicalException("not implemented"); - } - - @Override - public XContentBuilder createTypeMapping() { - try { - XContentBuilder mapping = XContentFactory.jsonBuilder().startObject() - .startObject(getType()) - .startObject("properties") - - // name - .startObject("name") - .field("type", "string") - .field("analyzer", settings.getDefaultStringAnalyzer()) - .endObject() - - // parent - .startObject("parent") - .field("type", "string") - .field("index", "not_analyzed") - .endObject() - - .endObject() - .endObject().endObject(); - - return mapping; - } - catch(IOException ioe) { - throw new TechnicalException(String.format("Error while getting mapping for index [%s/%s]: %s", getIndex(), getType(), ioe.getMessage()), ioe); - } - } - }; - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryRecordDao.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryRecordDao.java deleted file mode 100644 index 163ebea8..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryRecordDao.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.registry; - -import org.duniter.elasticsearch.gchange.dao.RecordDao; - -/** - * Created by blavenie on 03/04/17. - */ -public interface RegistryRecordDao extends RecordDao { -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryRecordDaoImpl.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryRecordDaoImpl.java deleted file mode 100644 index b9ae257b..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/registry/RegistryRecordDaoImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.duniter.elasticsearch.gchange.dao.registry; - -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.AbstractRecordDaoImpl; -import org.elasticsearch.common.inject.Inject; - -/** - * Created by blavenie on 03/04/17. - */ -public class RegistryRecordDaoImpl extends AbstractRecordDaoImpl implements RegistryRecordDao { - - @Inject - public RegistryRecordDaoImpl(PluginSettings pluginSettings) { - super(RegistryIndexDao.INDEX, pluginSettings); - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/event/GchangeEventCodes.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/event/GchangeEventCodes.java deleted file mode 100644 index 3ab5a401..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/event/GchangeEventCodes.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.duniter.elasticsearch.gchange.model.event; - -/* - * #%L - * Duniter4j :: ElasticSearch GChange plugin - * %% - * Copyright (C) 2014 - 2017 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -/** - * Created by blavenie on 01/12/16. - */ -public enum GchangeEventCodes { - - NEW_COMMENT, - UPDATE_COMMENT, - NEW_REPLY_COMMENT, - UPDATE_REPLY_COMMENT, -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/market/MarketRecord.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/market/MarketRecord.java deleted file mode 100644 index 33ab5654..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/market/MarketRecord.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.duniter.elasticsearch.gchange.model.market; - -/* - * #%L - * Duniter4j :: ElasticSearch GChange plugin - * %% - * Copyright (C) 2014 - 2017 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.core.client.model.elasticsearch.Record; - -import java.util.HashMap; -import java.util.Map; - -/** - * Created by blavenie on 01/12/16. - */ -public class MarketRecord extends Record{ - - public static final String PROPERTY_TITLE="title"; - public static final String PROPERTY_DESCRIPTION="description"; - public static final String PROPERTY_PRICE="price"; - public static final String PROPERTY_UNIT="unit"; - public static final String PROPERTY_CURRENCY="currency"; - public static final String PROPERTY_THUMBNAIL="thumbnail"; - - private String title; - private String description; - private Map<String, String> thumbnail = new HashMap<>(); - private Double price; - private String unit; - private String currency; - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public Double getPrice() { - return price; - } - - public void setPrice(Double price) { - this.price = price; - } - - public String getUnit() { - return unit; - } - - public void setUnit(String unit) { - this.unit = unit; - } - - public String getCurrency() { - return currency; - } - - public void setCurrency(String currency) { - this.currency = currency; - } - - public Map<String, String> getThumbnail() { - return thumbnail; - } - - public void setThumbnail(Map<String, String> thumbnail) { - this.thumbnail = thumbnail; - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/registry/RegistryRecord.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/registry/RegistryRecord.java deleted file mode 100644 index e04d3013..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/registry/RegistryRecord.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.duniter.elasticsearch.gchange.model.registry; - -/* - * #%L - * Duniter4j :: ElasticSearch GChange plugin - * %% - * Copyright (C) 2014 - 2017 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.core.client.model.elasticsearch.Record; - -import java.util.HashMap; -import java.util.Map; - -/** - * Created by blavenie on 01/12/16. - */ -public class RegistryRecord extends Record{ - - public static final String PROPERTY_TITLE="title"; - public static final String PROPERTY_DESCRIPTION="description"; - public static final String PROPERTY_THUMBNAIL="thumbnail"; - - private String title; - private String description; - private Map<String, String> thumbnail = new HashMap<>(); - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public Map<String, String> getThumbnail() { - return thumbnail; - } - - public void setThumbnail(Map<String, String> thumbnail) { - this.thumbnail = thumbnail; - } - -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/RestModule.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/RestModule.java deleted file mode 100644 index d7ee15f7..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/RestModule.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.duniter.elasticsearch.gchange.rest; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.gchange.rest.market.*; -import org.duniter.elasticsearch.gchange.rest.registry.*; -import org.elasticsearch.common.inject.AbstractModule; -import org.elasticsearch.common.inject.Module; - -public class RestModule extends AbstractModule implements Module { - - @Override protected void configure() { - - // Market - bind(RestMarketRecordIndexAction.class).asEagerSingleton(); - bind(RestMarketRecordUpdateAction.class).asEagerSingleton(); - bind(RestMarketCommentIndexAction.class).asEagerSingleton(); - bind(RestMarketCommentUpdateAction.class).asEagerSingleton(); - bind(RestMarketCategoryAction.class).asEagerSingleton(); - bind(RestMarketImageAction.class).asEagerSingleton(); - - // Registry - bind(RestRegistryRecordIndexAction.class).asEagerSingleton(); - bind(RestRegistryRecordUpdateAction.class).asEagerSingleton(); - bind(RestRegistryCommentIndexAction.class).asEagerSingleton(); - bind(RestRegistryCommentUpdateAction.class).asEagerSingleton(); - bind(RestRegistryCategoryAction.class).asEagerSingleton(); - bind(RestRegistryImageAction.class).asEagerSingleton(); - } -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCommentIndexAction.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCommentIndexAction.java deleted file mode 100644 index e0a39533..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCommentIndexAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.duniter.elasticsearch.gchange.rest.market; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.gchange.dao.market.MarketCommentDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketIndexDao; -import org.duniter.elasticsearch.rest.AbstractRestPostIndexAction; -import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.duniter.elasticsearch.gchange.service.MarketService; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.RestController; - -public class RestMarketCommentIndexAction extends AbstractRestPostIndexAction { - - @Inject - public RestMarketCommentIndexAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, - MarketService service) { - super(settings, controller, client, securityController, - MarketIndexDao.INDEX, MarketCommentDao.TYPE, - json -> service.indexCommentFromJson(json)); - } - -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCommentUpdateAction.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCommentUpdateAction.java deleted file mode 100644 index 0052f6aa..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCommentUpdateAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.duniter.elasticsearch.gchange.rest.market; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.gchange.dao.market.MarketCommentDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketIndexDao; -import org.duniter.elasticsearch.rest.AbstractRestPostUpdateAction; -import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.duniter.elasticsearch.gchange.service.MarketService; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.RestController; - -public class RestMarketCommentUpdateAction extends AbstractRestPostUpdateAction { - - @Inject - public RestMarketCommentUpdateAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, - MarketService service) { - super(settings, controller, client, securityController, - MarketIndexDao.INDEX, MarketCommentDao.TYPE, - (id, json) -> service.updateCommentFromJson(id, json)); - } - -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketImageAction.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketImageAction.java deleted file mode 100644 index dbc054d5..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketImageAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.duniter.elasticsearch.gchange.rest.market; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.gchange.dao.market.MarketIndexDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketRecordDao; -import org.duniter.elasticsearch.gchange.model.market.MarketRecord; -import org.duniter.elasticsearch.gchange.model.registry.RegistryRecord; -import org.duniter.elasticsearch.gchange.service.MarketService; -import org.duniter.elasticsearch.gchange.service.RegistryService; -import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.rest.RestRequest; - -public class RestMarketImageAction { - - @Inject - public RestMarketImageAction(RestSecurityController securityController) { - - // Allow to get thumbnail - securityController.allowImageAttachment(MarketIndexDao.INDEX, MarketRecordDao.TYPE, MarketRecord.PROPERTY_THUMBNAIL); - - // TODO : allow to get pictures - } -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketRecordIndexAction.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketRecordIndexAction.java deleted file mode 100644 index 7af1deee..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketRecordIndexAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.duniter.elasticsearch.gchange.rest.market; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.gchange.dao.market.MarketIndexDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketRecordDao; -import org.duniter.elasticsearch.rest.AbstractRestPostIndexAction; -import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.duniter.elasticsearch.gchange.service.MarketService; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.RestController; - -public class RestMarketRecordIndexAction extends AbstractRestPostIndexAction { - - @Inject - public RestMarketRecordIndexAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, - MarketService service) { - super(settings, controller, client, securityController, - MarketIndexDao.INDEX, MarketRecordDao.TYPE, - json -> service.indexRecordFromJson(json)); - } - -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketRecordUpdateAction.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketRecordUpdateAction.java deleted file mode 100644 index 7fd0a76e..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketRecordUpdateAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.duniter.elasticsearch.gchange.rest.market; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.gchange.dao.market.MarketIndexDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketRecordDao; -import org.duniter.elasticsearch.gchange.service.MarketService; -import org.duniter.elasticsearch.rest.AbstractRestPostUpdateAction; -import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.RestController; - -public class RestMarketRecordUpdateAction extends AbstractRestPostUpdateAction { - - @Inject - public RestMarketRecordUpdateAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, - MarketService service) { - super(settings, controller, client, securityController, - MarketIndexDao.INDEX, MarketRecordDao.TYPE, - (id, json) -> service.updateRecordFromJson(id, json)); - } - -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCommentUpdateAction.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCommentUpdateAction.java deleted file mode 100644 index e724f60b..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCommentUpdateAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.duniter.elasticsearch.gchange.rest.registry; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.gchange.dao.registry.RegistryCommentDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryIndexDao; -import org.duniter.elasticsearch.gchange.service.RegistryService; -import org.duniter.elasticsearch.rest.AbstractRestPostUpdateAction; -import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.RestController; - -public class RestRegistryCommentUpdateAction extends AbstractRestPostUpdateAction { - - @Inject - public RestRegistryCommentUpdateAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, - RegistryService service) { - super(settings, controller, client, securityController, - RegistryIndexDao.INDEX, RegistryCommentDao.TYPE, - (id, json) -> service.updateCommentFromJson(id, json)); - } - -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryImageAction.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryImageAction.java deleted file mode 100644 index 197ba606..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryImageAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.duniter.elasticsearch.gchange.rest.registry; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.gchange.dao.registry.RegistryCommentDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryIndexDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryRecordDao; -import org.duniter.elasticsearch.gchange.model.registry.RegistryRecord; -import org.duniter.elasticsearch.gchange.service.RegistryService; -import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.duniter.elasticsearch.user.service.UserService; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.rest.RestRequest; - -public class RestRegistryImageAction { - - @Inject - public RestRegistryImageAction(RestSecurityController securityController) { - - // Allow to get thumbnail - securityController.allowImageAttachment(RegistryIndexDao.INDEX, RegistryRecordDao.TYPE, RegistryRecord.PROPERTY_THUMBNAIL); - - // TODO : allow to get pictures - } -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryRecordIndexAction.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryRecordIndexAction.java deleted file mode 100644 index 29756252..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryRecordIndexAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.duniter.elasticsearch.gchange.rest.registry; - -/* - * #%L - * duniter4j-elasticsearch-plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.gchange.dao.registry.RegistryIndexDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryRecordDao; -import org.duniter.elasticsearch.rest.AbstractRestPostIndexAction; -import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.duniter.elasticsearch.gchange.service.RegistryService; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.RestController; - -public class RestRegistryRecordIndexAction extends AbstractRestPostIndexAction { - - - @Inject - public RestRegistryRecordIndexAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, - RegistryService service) { - super(settings, controller, client, securityController, - RegistryIndexDao.INDEX, RegistryRecordDao.TYPE, - json -> service.indexRecordFromJson(json)); - } -} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/CommentUserEventService.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/CommentUserEventService.java deleted file mode 100644 index 76da0a6e..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/CommentUserEventService.java +++ /dev/null @@ -1,273 +0,0 @@ -package org.duniter.elasticsearch.gchange.service; - -/* - * #%L - * UCoin Java Client :: Core API - * %% - * Copyright (C) 2014 - 2015 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.google.common.collect.ImmutableList; -import org.apache.commons.collections4.MapUtils; -import org.duniter.core.client.model.ModelUtils; -import org.duniter.core.client.model.elasticsearch.RecordComment; -import org.duniter.core.exception.TechnicalException; -import org.duniter.core.service.CryptoService; -import org.duniter.core.util.StringUtils; -import org.duniter.elasticsearch.client.Duniter4jClient; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.RecordDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketCommentDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketIndexDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryCommentDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryIndexDao; -import org.duniter.elasticsearch.gchange.model.event.GchangeEventCodes; -import org.duniter.elasticsearch.gchange.model.market.MarketRecord; -import org.duniter.elasticsearch.service.changes.ChangeEvent; -import org.duniter.elasticsearch.service.changes.ChangeService; -import org.duniter.elasticsearch.service.changes.ChangeSource; -import org.duniter.elasticsearch.user.model.UserEvent; -import org.duniter.elasticsearch.user.service.UserEventService; -import org.duniter.elasticsearch.user.service.UserService; -import org.elasticsearch.common.inject.Inject; -import org.nuiton.i18n.I18n; - -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -/** - * Created by Benoit on 30/03/2015. - */ -public class CommentUserEventService extends AbstractService implements ChangeService.ChangeListener { - - static { - I18n.n("duniter.market.error.comment.recordNotFound"); - I18n.n("duniter.market.event.newComment"); - I18n.n("duniter.market.event.updateComment"); - I18n.n("duniter.market.event.newReplyComment"); - I18n.n("duniter.market.event.updateReplyComment"); - - I18n.n("duniter.registry.error.comment.recordNotFound"); - I18n.n("duniter.registry.event.newComment"); - I18n.n("duniter.registry.event.updateComment"); - I18n.n("duniter.registry.event.newReplyComment"); - I18n.n("duniter.registry.event.updateReplyComment"); - } - - private final UserService userService; - private final UserEventService userEventService; - private final List<ChangeSource> changeListenSources; - private final String recordType; - private final boolean trace; - - @Inject - public CommentUserEventService(Duniter4jClient client, - PluginSettings settings, - CryptoService cryptoService, - UserService userService, - UserEventService userEventService) { - super("duniter.user.event.comment", client, settings, cryptoService); - this.userService = userService; - this.userEventService = userEventService; - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - this.changeListenSources = ImmutableList.of( - new ChangeSource(MarketIndexDao.INDEX, MarketCommentDao.TYPE), - new ChangeSource(RegistryIndexDao.INDEX, RegistryCommentDao.TYPE)); - ChangeService.registerListener(this); - - this.trace = logger.isTraceEnabled(); - - this.recordType = RecordDao.TYPE; - } - - @Override - public String getId() { - return "duniter.user.event.comment"; - } - - @Override - public void onChange(ChangeEvent change) { - - RecordComment comment; - - switch (change.getOperation()) { - case CREATE: - comment = readComment(change); - if (comment != null) { - processCreateComment(change.getIndex(), change.getType(), change.getId(), comment); - } - break; - case INDEX: - comment = readComment(change); - if (comment != null) { - processUpdateComment(change.getIndex(), change.getType(), change.getId(), comment); - } - break; - - // on DELETE : remove user event on block (using link - case DELETE: - processCommentDelete(change); - break; - } - - } - - @Override - public Collection<ChangeSource> getChangeSources() { - return changeListenSources; - } - - /* -- internal method -- */ - - /** - * Send notification from a new comment - * - * @param index - * @param type - * @param commentId - * @param comment - */ - private void processCreateComment(String index, String type, String commentId, RecordComment comment) { - - processUpdateOrCreateComment(index, type, commentId, comment, - GchangeEventCodes.NEW_COMMENT, String.format("duniter.%s.event.newComment", index.toLowerCase()), - GchangeEventCodes.NEW_REPLY_COMMENT, String.format("duniter.%s.event.newReplyComment", index.toLowerCase())); - } - - /** - * Same as processCreateComment(), but with other code and message. - * - * @param index - * @param type - * @param commentId - * @param comment - */ - private void processUpdateComment(String index, String type, String commentId, RecordComment comment) { - - processUpdateOrCreateComment(index, type, commentId, comment, - GchangeEventCodes.UPDATE_COMMENT, String.format("duniter.%s.event.updateComment", index.toLowerCase()), - GchangeEventCodes.UPDATE_REPLY_COMMENT, String.format("duniter.%s.event.updateReplyComment", index.toLowerCase())); - } - - - /** - * Same as processCreateComment(), but with other code and message. - * - * @param index - * @param type - * @param commentId - * @param comment - */ - private void processUpdateOrCreateComment(String index, String type, String commentId, RecordComment comment, - GchangeEventCodes eventCodeForRecordIssuer, String messageKeyForRecordIssuer, - GchangeEventCodes eventCodeForParentCommentIssuer, String messageKeyForParentCommentIssuer) { - // Get record issuer - String recordId = comment.getRecord(); - Map<String, Object> record = client.getFieldsById(index, this.recordType, recordId, - MarketRecord.PROPERTY_TITLE, MarketRecord.PROPERTY_ISSUER); - - // Record not found : nothing to emit - if (MapUtils.isEmpty(record)) { - logger.warn(I18n.t(String.format("duniter.%s.error.comment.recordNotFound", index.toLowerCase()), recordId)); - return; - } - - // Fetch record info - String recordIssuer = record.get(MarketRecord.PROPERTY_ISSUER).toString(); - String recordTitle = record.get(MarketRecord.PROPERTY_TITLE).toString(); - - // Get comment issuer title - String issuer = comment.getIssuer(); - String issuerTitle = userService.getProfileTitle(issuer); - - // Notify issuer of record (is not same as comment writer) - if (!issuer.equals(recordIssuer)) { - userEventService.notifyUser( - UserEvent.newBuilder(UserEvent.EventType.INFO, eventCodeForRecordIssuer.name()) - .setMessage( - messageKeyForRecordIssuer, - issuer, - issuerTitle != null ? issuerTitle : ModelUtils.minifyPubkey(issuer), - recordTitle - ) - .setRecipient(recordIssuer) - .setReference(index, recordType, recordId) - .setReferenceAnchor(commentId) - .setTime(comment.getTime()) - .build()); - } - - // Notify comment is a reply to another comment - if (StringUtils.isNotBlank(comment.getReplyTo())) { - - String parentCommentIssuer = client.getTypedFieldById(index, type, comment.getReplyTo(), RecordComment.PROPERTY_ISSUER); - - if (StringUtils.isNotBlank(parentCommentIssuer) && - !issuer.equals(parentCommentIssuer) && - !recordIssuer.equals(parentCommentIssuer)) { - - userEventService.notifyUser( - UserEvent.newBuilder(UserEvent.EventType.INFO, eventCodeForParentCommentIssuer.name()) - .setMessage( - messageKeyForParentCommentIssuer, - issuer, - issuerTitle != null ? issuerTitle : ModelUtils.minifyPubkey(issuer), - recordTitle - ) - .setRecipient(parentCommentIssuer) - .setReference(index, recordType, recordId) - .setReferenceAnchor(commentId) - /*.setTime(comment.getTime()) - DO NOT set time, has the comment time is NOT the update time*/ - .build()); - } - } - - } - - private void processCommentDelete(ChangeEvent change) { - if (change.getId() == null) return; - - // Delete events that reference this block - userEventService.deleteEventsByReference(new UserEvent.Reference(change.getIndex(), change.getType(), change.getId())); - } - - private RecordComment readComment(ChangeEvent change) { - try { - if (change.getSource() != null) { - return objectMapper.readValue(change.getSource().streamInput(), RecordComment.class); - } - return null; - } catch (JsonProcessingException e) { - if (trace) { - logger.warn(String.format("Bad format for comment [%s]: %s. Skip this comment", change.getId(), e.getMessage()), e); - } - else { - logger.warn(String.format("Bad format for comment [%s]: %s. Skip this comment", change.getId(), e.getMessage())); - } - return null; - } - catch (IOException e) { - throw new TechnicalException(String.format("Unable to parse received comment %s", change.getId()), e); - } - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/MarketService.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/MarketService.java deleted file mode 100644 index 78581d99..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/MarketService.java +++ /dev/null @@ -1,150 +0,0 @@ -package org.duniter.elasticsearch.gchange.service; - -/* - * #%L - * UCoin Java Client :: Core API - * %% - * Copyright (C) 2014 - 2015 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - - -import com.fasterxml.jackson.databind.JsonNode; -import org.duniter.core.client.model.elasticsearch.RecordComment; -import org.duniter.core.service.CryptoService; -import org.duniter.elasticsearch.client.Duniter4jClient; -import org.duniter.elasticsearch.exception.NotFoundException; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.market.MarketCommentDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketIndexDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketRecordDao; -import org.duniter.elasticsearch.user.service.HistoryService; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.inject.Inject; - -/** - * Created by Benoit on 30/03/2015. - */ -public class MarketService extends AbstractService { - - private MarketIndexDao indexDao; - private MarketRecordDao recordDao; - private MarketCommentDao commentDao; - private HistoryService historyService; - - @Inject - public MarketService(Duniter4jClient client, PluginSettings settings, - CryptoService cryptoService, - HistoryService historyService, - MarketIndexDao indexDao, - MarketCommentDao commentDao, - MarketRecordDao recordDao - ) { - super("gchange.service.market", client, settings, cryptoService); - this.indexDao = indexDao; - this.commentDao = commentDao; - this.recordDao = recordDao; - - this.historyService = historyService; - } - - - /** - * Create index need for blockchain registry, if need - */ - public MarketService createIndexIfNotExists() { - indexDao.createIndexIfNotExists(); - return this; - } - - public MarketService deleteIndex() { - indexDao.deleteIndex(); - return this; - } - - - public String indexRecordFromJson(String json) { - JsonNode actualObj = readAndVerifyIssuerSignature(json); - String issuer = getIssuer(actualObj); - - if (logger.isDebugEnabled()) { - logger.debug(String.format("Indexing a %s from issuer [%s]", recordDao.getType(), issuer.substring(0, 8))); - } - - return recordDao.create(json); - } - - public void updateRecordFromJson(String id, String json) { - JsonNode actualObj = readAndVerifyIssuerSignature(json); - String issuer = getIssuer(actualObj); - - // Check same document issuer - recordDao.checkSameDocumentIssuer(id, issuer); - - if (logger.isDebugEnabled()) { - logger.debug(String.format("Updating %s [%s] from issuer [%s]", recordDao.getType(), id, issuer.substring(0, 8))); - } - - recordDao.update(id, json); - } - - public String indexCommentFromJson(String json) { - JsonNode commentObj = readAndVerifyIssuerSignature(json); - String issuer = getMandatoryField(commentObj, RecordComment.PROPERTY_ISSUER).asText(); - - // Check the record document exists - String recordId = getMandatoryField(commentObj, RecordComment.PROPERTY_RECORD).asText(); - checkRecordExistsOrDeleted(recordId); - - if (logger.isDebugEnabled()) { - logger.debug(String.format("Indexing a %s from issuer [%s]", commentDao.getType(), issuer.substring(0, 8))); - } - return commentDao.create(json); - } - - public void updateCommentFromJson(String id, String json) { - JsonNode commentObj = readAndVerifyIssuerSignature(json); - - // Check the record document exists - String recordId = getMandatoryField(commentObj, RecordComment.PROPERTY_RECORD).asText(); - checkRecordExistsOrDeleted(recordId); - - if (logger.isDebugEnabled()) { - String issuer = getMandatoryField(commentObj, RecordComment.PROPERTY_ISSUER).asText(); - logger.debug(String.format("[%s] Indexing a %s from issuer [%s] on [%s]", commentDao.getType(), commentDao.getType(), issuer.substring(0, 8))); - } - - commentDao.update(id, json); - } - - - /* -- Internal methods -- */ - - // Check the record document exists (or has been deleted) - private void checkRecordExistsOrDeleted(String id) { - boolean recordExists; - try { - recordExists = recordDao.isExists(id); - } catch (NotFoundException e) { - // Check if exists in delete history - recordExists = historyService.existsInDeleteHistory(recordDao.getIndex(), recordDao.getType(), id); - } - if (!recordExists) { - throw new NotFoundException(String.format("Comment refers a non-existent document [%s/%s/%s].", recordDao.getIndex(), recordDao.getType(), id)); - } - } -} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/RegistryService.java b/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/RegistryService.java deleted file mode 100644 index ca51cb87..00000000 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/RegistryService.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.duniter.elasticsearch.gchange.service; - -/* - * #%L - * UCoin Java Client :: Core API - * %% - * Copyright (C) 2014 - 2015 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - - -import com.fasterxml.jackson.databind.JsonNode; -import org.duniter.core.client.model.elasticsearch.RecordComment; -import org.duniter.core.service.CryptoService; -import org.duniter.elasticsearch.client.Duniter4jClient; -import org.duniter.elasticsearch.exception.NotFoundException; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryCommentDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryIndexDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryRecordDao; -import org.duniter.elasticsearch.user.service.HistoryService; -import org.elasticsearch.common.inject.Inject; - -/** - * Created by Benoit on 30/03/2015. - */ -public class RegistryService extends AbstractService { - - private RegistryIndexDao indexDao; - private RegistryRecordDao recordDao; - private RegistryCommentDao commentDao; - private HistoryService historyService; - - @Inject - public RegistryService(Duniter4jClient client, - PluginSettings settings, - CryptoService cryptoService, - HistoryService historyService, - RegistryIndexDao registryIndexDao, - RegistryCommentDao commentDao, - RegistryRecordDao recordDao) { - super("gchange.service.registry", client, settings, cryptoService); - this.indexDao = registryIndexDao; - this.commentDao = commentDao; - this.recordDao = recordDao; - this.historyService = historyService; - } - - /** - * Create index need for blockchain registry, if need - */ - public RegistryService createIndexIfNotExists() { - indexDao.createIndexIfNotExists(); - return this; - } - - public RegistryService deleteIndex() { - indexDao.deleteIndex(); - return this; - } - - public String indexRecordFromJson(String json) { - JsonNode actualObj = readAndVerifyIssuerSignature(json); - String issuer = getIssuer(actualObj); - - if (logger.isDebugEnabled()) { - logger.debug(String.format("Indexing a %s from issuer [%s]", recordDao.getType(), issuer.substring(0, 8))); - } - - return recordDao.create(json); - } - - public void updateRecordFromJson(String id, String json) { - JsonNode actualObj = readAndVerifyIssuerSignature(json); - String issuer = getIssuer(actualObj); - - // Check same document issuer - recordDao.checkSameDocumentIssuer(id, issuer); - - if (logger.isDebugEnabled()) { - logger.debug(String.format("Updating %s [%s] from issuer [%s]", recordDao.getType(), id, issuer.substring(0, 8))); - } - - recordDao.update(id, json); - } - - public String indexCommentFromJson(String json) { - JsonNode commentObj = readAndVerifyIssuerSignature(json); - String issuer = getMandatoryField(commentObj, RecordComment.PROPERTY_ISSUER).asText(); - - // Check the record document exists - String recordId = getMandatoryField(commentObj, RecordComment.PROPERTY_RECORD).asText(); - checkRecordExistsOrDeleted(recordId); - - if (logger.isDebugEnabled()) { - logger.debug(String.format("Indexing a %s from issuer [%s]", commentDao.getType(), issuer.substring(0, 8))); - } - return commentDao.create(json); - } - - public void updateCommentFromJson(String id, String json) { - JsonNode commentObj = readAndVerifyIssuerSignature(json); - - // Check the record document exists - String recordId = getMandatoryField(commentObj, RecordComment.PROPERTY_RECORD).asText(); - checkRecordExistsOrDeleted(recordId); - - if (logger.isDebugEnabled()) { - String issuer = getMandatoryField(commentObj, RecordComment.PROPERTY_ISSUER).asText(); - logger.debug(String.format("[%s] Indexing a %s from issuer [%s] on [%s]", commentDao.getType(), commentDao.getType(), issuer.substring(0, 8))); - } - - commentDao.update(id, json); - } - - - /* -- Internal methods -- */ - - // Check the record document exists (or has been deleted) - private void checkRecordExistsOrDeleted(String id) { - boolean recordExists; - try { - recordExists = recordDao.isExists(id); - } catch (NotFoundException e) { - // Check if exists in delete history - recordExists = historyService.existsInDeleteHistory(recordDao.getIndex(), recordDao.getType(), id); - } - if (!recordExists) { - throw new NotFoundException(String.format("Comment refers a non-existent document [%s/%s/%s].", recordDao.getIndex(), recordDao.getType(), id)); - } - } - -} diff --git a/duniter4j-es-gchange/src/main/misc/cities-fr.geoJson.txt b/duniter4j-es-gchange/src/main/misc/cities-fr.geoJson.txt deleted file mode 100644 index bb4b1bd4..00000000 --- a/duniter4j-es-gchange/src/main/misc/cities-fr.geoJson.txt +++ /dev/null @@ -1,8 +0,0 @@ -Les données Francaise des communes provient de ce fichier : -http://public.opendatasoft.com/explore/dataset/geoflar-communes-2015/export/ - ->> Cliquer sur Export > GeoJSON - - -Ou directement via : - http://public.opendatasoft.com/explore/dataset/geoflar-communes-2015/download/?format=geojson&timezone=Europe/Berlin \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/misc/registry-categories-naf2008_liste_n5.ods b/duniter4j-es-gchange/src/main/misc/registry-categories-naf2008_liste_n5.ods deleted file mode 100644 index acc6ea091339d82dacf7533c99e3cf9876599984..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70946 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 VgO-&IBr6Dn1wi}e2mmc+0052v`#k^v diff --git a/duniter4j-es-gchange/src/main/resources/i18n/duniter4j-es-gchange_en_GB.properties b/duniter4j-es-gchange/src/main/resources/i18n/duniter4j-es-gchange_en_GB.properties deleted file mode 100644 index dd29729a..00000000 --- a/duniter4j-es-gchange/src/main/resources/i18n/duniter4j-es-gchange_en_GB.properties +++ /dev/null @@ -1,12 +0,0 @@ -duniter.event.NODE_BMA_DOWN= -duniter.event.NODE_BMA_UP= -duniter.market.error.comment.recordNotFound=Ad [%s] referenced by comment not found -duniter.market.event.newComment= -duniter.market.event.newReplyComment= -duniter.market.event.updateComment= -duniter.market.event.updateReplyComment= -duniter.registry.error.comment.recordNotFound=Record [%s] referenced by comment not found -duniter.registry.event.newComment= -duniter.registry.event.newReplyComment= -duniter.registry.event.updateComment= -duniter.registry.event.updateReplyComment= diff --git a/duniter4j-es-gchange/src/main/resources/i18n/duniter4j-es-gchange_fr_FR.properties b/duniter4j-es-gchange/src/main/resources/i18n/duniter4j-es-gchange_fr_FR.properties deleted file mode 100644 index 40d7fb34..00000000 --- a/duniter4j-es-gchange/src/main/resources/i18n/duniter4j-es-gchange_fr_FR.properties +++ /dev/null @@ -1,12 +0,0 @@ -duniter.event.NODE_BMA_DOWN= -duniter.event.NODE_BMA_UP= -duniter.market.error.comment.recordNotFound=L'annonce [%s] référencée par le commentaire n'existe pas. -duniter.market.event.newComment=%2$s a commenté votre annonce '%3$s' -duniter.market.event.newReplyComment=%2$s a répondu à votre commentaire sur l'annonce '%3$s' -duniter.market.event.updateComment=%2$s a mise à jour son commentaire sur votre annonce '%3$s' -duniter.market.event.updateReplyComment=%2$s a modifié sa réponse à votre commentaire, sur l'annonce '%3$s' -duniter.registry.error.comment.recordNotFound=Le référencement [%s] référencée par le commentaire n'existe pas. -duniter.registry.event.newComment=%2$s a commenté votre référencement '%3$s' -duniter.registry.event.newReplyComment=%2$s a répondu à votre commentaire sur le référencement '%3$s' -duniter.registry.event.updateComment=%2$s a modifié son commentaire sur votre référencement '%3$s' -duniter.registry.event.updateReplyComment=%2$s a modifié sa réponse à votre commentaire, sur le référencement '%3$s' diff --git a/duniter4j-es-gchange/src/main/resources/market-categories-bulk-insert.json b/duniter4j-es-gchange/src/main/resources/market-categories-bulk-insert.json deleted file mode 100644 index c9527a96..00000000 --- a/duniter4j-es-gchange/src/main/resources/market-categories-bulk-insert.json +++ /dev/null @@ -1,151 +0,0 @@ -{ "index": { "_id": "cat71"}} -{ "name": "Emploi" , "parent": null} -{ "index": { "_id": "cat33"}} -{ "name": "Offres d'emploi", "parent": "cat71" } - -{ "index": { "_id": "cat1" }} -{ "name": "Véhicules" , "parent": null} -{ "index": { "_id": "cat2" }} -{ "name": "Voitures" , "parent": "cat2" } -{ "index": { "_id": "cat3" }} -{ "name": "Motos" , "parent": "cat3" } -{ "index": { "_id": "cat4" }} -{ "name": "Caravaning" , "parent": "cat3" } -{ "index": { "_id": "cat5" }} -{ "name": "Utilitaires" , "parent": "cat3" } -{ "index": { "_id": "cat6" }} -{ "name": "Equipement Auto" , "parent": "cat3" } -{ "index": { "_id": "cat44" }} -{ "name": "Equipement Moto" , "parent": "cat3" } -{ "index": { "_id": "cat50" }} -{ "name": "Equipement Caravaning" , "parent": "cat3" } -{ "index": { "_id": "cat7" }} -{ "name": "Nautisme" , "parent": "cat3" } -{ "index": { "_id": "cat51" }} -{ "name": "Equipement Nautisme" , "parent": "cat3" } - -{ "index": { "_id": "cat8" }} -{ "name": "Immobilier" , "parent": null} -{ "index": { "_id": "cat9" }} -{ "name": "Ventes immobilières" , "parent": "cat8" } -{ "index": { "_id": "cat10" }} -{ "name": "Locations" , "parent": "cat8" } -{ "index": { "_id": "cat11" }} -{ "name": "Colocations" , "parent": "cat8" } -{ "index": { "_id": "cat13" }} -{ "name": "Bureaux & Commerces" , "parent": "cat8" } - -{ "index": { "_id": "cat66" }} -{ "name": "Vacances" , "parent": null} -{ "index": { "_id": "cat12" }} -{ "name": "Locations & Gîtes" , "parent": "cat66" } -{ "index": { "_id": "cat67" }} -{ "name": "Chambres d'hôtes" , "parent": "cat66" } -{ "index": { "_id": "cat68" }} -{ "name": "Campings" , "parent": "cat66" } -{ "index": { "_id": "cat69" }} -{ "name": "Hôtels" , "parent": "cat66" } -{ "index": { "_id": "cat70" }} -{ "name": "Hébergements insolites" , "parent": "cat66" } - -{ "index": { "_id": "cat14" }} -{ "name": "Multimédia" , "parent": null} -{ "index": { "_id": "cat15" }} -{ "name": "Informatique" , "parent": "cat14" } -{ "index": { "_id": "cat43" }} -{ "name": "Consoles & Jeux vidéo" , "parent": "cat14" } -{ "index": { "_id": "cat16" }} -{ "name": "Image & Son" , "parent": "cat14" } -{ "index": { "_id": "cat17" }} -{ "name": "Téléphonie" , "parent": "cat14" } - -{ "index": { "_id": "cat18" }} -{ "name": "Maison" , "parent": null} -{ "index": { "_id": "cat19" }} -{ "name": "Ameublement" , "parent": "cat18" } -{ "index": { "_id": "cat20" }} -{ "name": "Electroménager" , "parent": "cat18" } -{ "index": { "_id": "cat45" }} -{ "name": "Arts de la table" , "parent": "cat18" } -{ "index": { "_id": "cat39" }} -{ "name": "Décoration" , "parent": "cat18" } -{ "index": { "_id": "cat46" }} -{ "name": "Linge de maison" , "parent": "cat18" } -{ "index": { "_id": "cat21" }} -{ "name": "Bricolage" , "parent": "cat18" } -{ "index": { "_id": "cat52" }} -{ "name": "Jardinage" , "parent": "cat18" } -{ "index": { "_id": "cat22" }} -{ "name": "Vêtements" , "parent": "cat18" } -{ "index": { "_id": "cat53" }} -{ "name": "Chaussures" , "parent": "cat18" } -{ "index": { "_id": "cat47" }} -{ "name": "Accessoires & Bagagerie" , "parent": "cat18" } -{ "index": { "_id": "cat42" }} -{ "name": "Montres & Bijoux" , "parent": "cat18" } -{ "index": { "_id": "cat23" }} -{ "name": "Equipement bébé" , "parent": "cat18" } -{ "index": { "_id": "cat54" }} -{ "name": "Vêtements bébé" , "parent": "cat18" } - -{ "index": { "_id": "cat24" }} -{ "name": "Loisirs" , "parent": null} -{ "index": { "_id": "cat25" }} -{ "name": "DVD / Films" , "parent": "cat24" } -{ "index": { "_id": "cat26" }} -{ "name": "CD / Musique" , "parent": "cat24" } -{ "index": { "_id": "cat27" }} -{ "name": "Livres" , "parent": "cat24" } -{ "index": { "_id": "cat28" }} -{ "name": "Animaux" , "parent": "cat24" } -{ "index": { "_id": "cat55" }} -{ "name": "Vélos" , "parent": "cat24" } -{ "index": { "_id": "cat29" }} -{ "name": "Sports & Hobbies" } -{ "index": { "_id": "cat30" }} -{ "name": "Instruments de musique" , "parent": "cat24" } -{ "index": { "_id": "cat40" }} -{ "name": "Collection" , "parent": "cat24" } -{ "index": { "_id": "cat41" }} -{ "name": "Jeux & Jouets" , "parent": "cat24" } -{ "index": { "_id": "cat48" }} -{ "name": "Vins & Gastronomie" , "parent": "cat24" } - -{ "index": { "_id": "cat56" }} -{ "name": "Matériel professionnel" , "parent": null} -{ "index": { "_id": "cat57" }} -{ "name": "Matériel Agricole" , "parent": "cat56" } -{ "index": { "_id": "cat58" }} -{ "name": "Transport - Manutention" , "parent": "cat56" } -{ "index": { "_id": "cat59" }} -{ "name": "BTP - Chantier Gros-oeuvre" , "parent": "cat56" } -{ "index": { "_id": "cat60" }} -{ "name": "Outillage - Matériaux 2nd-oeuvre" , "parent": "cat56" } -{ "index": { "_id": "cat32" }} -{ "name": "Équipements Industriels" , "parent": "cat56" } -{ "index": { "_id": "cat61" }} -{ "name": "Restauration - Hôtellerie" , "parent": "cat56" } -{ "index": { "_id": "cat62" }} -{ "name": "Fournitures de Bureau" , "parent": "cat56" } -{ "index": { "_id": "cat63" }} -{ "name": "Commerces & Marchés" , "parent": "cat56" } -{ "index": { "_id": "cat64" }} -{ "name": "Matériel Médical" , "parent": "cat56" } - -{ "index": { "_id": "cat31" }} -{ "name": "Services" , "parent": null} -{ "index": { "_id": "cat34" }} -{ "name": "Prestations de services" , "parent": "cat31" } -{ "index": { "_id": "cat35" }} -{ "name": "Billetterie" , "parent": "cat31" } -{ "index": { "_id": "cat49" }} -{ "name": "Evénements" , "parent": "cat31" } -{ "index": { "_id": "cat36" }} -{ "name": "Cours particuliers" , "parent": "cat31" } -{ "index": { "_id": "cat65" }} -{ "name": "Covoiturage" , "parent": "cat31" } -{ "index": { "_id": "cat37" }} - -{ "name": "Divers" , "parent": null} -{ "index": { "_id": "cat38" }} -{ "name": "Autres" , "parent": "cat37" } diff --git a/duniter4j-es-gchange/src/main/resources/registry-categories-bulk-insert.json b/duniter4j-es-gchange/src/main/resources/registry-categories-bulk-insert.json deleted file mode 100644 index 3ee70de3..00000000 --- a/duniter4j-es-gchange/src/main/resources/registry-categories-bulk-insert.json +++ /dev/null @@ -1,1506 +0,0 @@ -{"index": {"_id": "A"}} -{"name": "Agriculture, sylviculture et pêche", "parent": null} -{"index": {"_id": "01.11Z"}} -{"name": "Culture de céréales (à l'exception du riz), de légumineuses et de graines oléagineuses", "parent": "A"} -{"index": {"_id": "01.12Z"}} -{"name": "Culture du riz", "parent": "A"} -{"index": {"_id": "01.13Z"}} -{"name": "Culture de légumes, de melons, de racines et de tubercules", "parent": "A"} -{"index": {"_id": "01.14Z"}} -{"name": "Culture de la canne à sucre", "parent": "A"} -{"index": {"_id": "01.15Z"}} -{"name": "Culture du tabac", "parent": "A"} -{"index": {"_id": "01.16Z"}} -{"name": "Culture de plantes à fibres", "parent": "A"} -{"index": {"_id": "01.19Z"}} -{"name": "Autres cultures non permanentes", "parent": "A"} -{"index": {"_id": "01.21Z"}} -{"name": "Culture de la vigne", "parent": "A"} -{"index": {"_id": "01.22Z"}} -{"name": "Culture de fruits tropicaux et subtropicaux", "parent": "A"} -{"index": {"_id": "01.23Z"}} -{"name": "Culture d'agrumes", "parent": "A"} -{"index": {"_id": "01.24Z"}} -{"name": "Culture de fruits à pépins et à noyau", "parent": "A"} -{"index": {"_id": "01.25Z"}} -{"name": "Culture d'autres fruits d'arbres ou d'arbustes et de fruits à coque", "parent": "A"} -{"index": {"_id": "01.26Z"}} -{"name": "Culture de fruits oléagineux", "parent": "A"} -{"index": {"_id": "01.27Z"}} -{"name": "Culture de plantes à boissons", "parent": "A"} -{"index": {"_id": "01.28Z"}} -{"name": "Culture de plantes à épices, aromatiques, médicinales et pharmaceutiques", "parent": "A"} -{"index": {"_id": "01.29Z"}} -{"name": "Autres cultures permanentes", "parent": "A"} -{"index": {"_id": "01.30Z"}} -{"name": "Reproduction de plantes", "parent": "A"} -{"index": {"_id": "01.41Z"}} -{"name": "Élevage de vaches laitières", "parent": "A"} -{"index": {"_id": "01.42Z"}} -{"name": "Élevage d'autres bovins et de buffles", "parent": "A"} -{"index": {"_id": "01.43Z"}} -{"name": "Élevage de chevaux et d'autres équidés", "parent": "A"} -{"index": {"_id": "01.44Z"}} -{"name": "Élevage de chameaux et d'autres camélidés", "parent": "A"} -{"index": {"_id": "01.45Z"}} -{"name": "Élevage d'ovins et de caprins", "parent": "A"} -{"index": {"_id": "01.46Z"}} -{"name": "Élevage de porcins", "parent": "A"} -{"index": {"_id": "01.47Z"}} -{"name": "Élevage de volailles", "parent": "A"} -{"index": {"_id": "01.49Z"}} -{"name": "Élevage d'autres animaux", "parent": "A"} -{"index": {"_id": "01.50Z"}} -{"name": "Culture et élevage associés", "parent": "A"} -{"index": {"_id": "01.61Z"}} -{"name": "Activités de soutien aux cultures", "parent": "A"} -{"index": {"_id": "01.62Z"}} -{"name": "Activités de soutien à la production animale", "parent": "A"} -{"index": {"_id": "01.63Z"}} -{"name": "Traitement primaire des récoltes", "parent": "A"} -{"index": {"_id": "01.64Z"}} -{"name": "Traitement des semences", "parent": "A"} -{"index": {"_id": "01.70Z"}} -{"name": "Chasse, piégeage et services annexes", "parent": "A"} -{"index": {"_id": "02.10Z"}} -{"name": "Sylviculture et autres activités forestières", "parent": "A"} -{"index": {"_id": "02.20Z"}} -{"name": "Exploitation forestière", "parent": "A"} -{"index": {"_id": "02.30Z"}} -{"name": "Récolte de produits forestiers non ligneux poussant à l'état sauvage", "parent": "A"} -{"index": {"_id": "02.40Z"}} -{"name": "Services de soutien à l'exploitation forestière", "parent": "A"} -{"index": {"_id": "03.11Z"}} -{"name": "Pêche en mer", "parent": "A"} -{"index": {"_id": "03.12Z"}} -{"name": "Pêche en eau douce", "parent": "A"} -{"index": {"_id": "03.21Z"}} -{"name": "Aquaculture en mer", "parent": "A"} -{"index": {"_id": "03.22Z"}} -{"name": "Aquaculture en eau douce", "parent": "A"} -{"index": {"_id": "B"}} -{"name": "Industries extractives", "parent": null} -{"index": {"_id": "05.10Z"}} -{"name": "Extraction de houille", "parent": "B"} -{"index": {"_id": "05.20Z"}} -{"name": "Extraction de lignite", "parent": "B"} -{"index": {"_id": "06.10Z"}} -{"name": "Extraction de pétrole brut", "parent": "B"} -{"index": {"_id": "06.20Z"}} -{"name": "Extraction de gaz naturel", "parent": "B"} -{"index": {"_id": "07.10Z"}} -{"name": "Extraction de minerais de fer", "parent": "B"} -{"index": {"_id": "07.21Z"}} -{"name": "Extraction de minerais d'uranium et de thorium", "parent": "B"} -{"index": {"_id": "07.29Z"}} -{"name": "Extraction d'autres minerais de métaux non ferreux", "parent": "B"} -{"index": {"_id": "08.11Z"}} -{"name": "Extraction de pierres ornementales et de construction, de calcaire industriel, de gypse, de craie et d'ardoise", "parent": "B"} -{"index": {"_id": "08.12Z"}} -{"name": "Exploitation de gravières et sablières, extraction d'argiles et de kaolin", "parent": "B"} -{"index": {"_id": "08.91Z"}} -{"name": "Extraction des minéraux chimiques et d'engrais minéraux", "parent": "B"} -{"index": {"_id": "08.92Z"}} -{"name": "Extraction de tourbe", "parent": "B"} -{"index": {"_id": "08.93Z"}} -{"name": "Production de sel", "parent": "B"} -{"index": {"_id": "08.99Z"}} -{"name": "Autres activités extractives n.c.a.", "parent": "B"} -{"index": {"_id": "09.10Z"}} -{"name": "Activités de soutien à l'extraction d'hydrocarbures", "parent": "B"} -{"index": {"_id": "09.90Z"}} -{"name": "Activités de soutien aux autres industries extractives", "parent": "B"} -{"index": {"_id": "C"}} -{"name": "Industrie manufacturière", "parent": null} -{"index": {"_id": "10.11Z"}} -{"name": "Transformation et conservation de la viande de boucherie", "parent": "C"} -{"index": {"_id": "10.12Z"}} -{"name": "Transformation et conservation de la viande de volaille", "parent": "C"} -{"index": {"_id": "10.13A"}} -{"name": "Préparation industrielle de produits à base de viande", "parent": "C"} -{"index": {"_id": "10.13B"}} -{"name": "Charcuterie", "parent": "C"} -{"index": {"_id": "10.20Z"}} -{"name": "Transformation et conservation de poisson, de crustacés et de mollusques", "parent": "C"} -{"index": {"_id": "10.31Z"}} -{"name": "Transformation et conservation de pommes de terre", "parent": "C"} -{"index": {"_id": "10.32Z"}} -{"name": "Préparation de jus de fruits et légumes", "parent": "C"} -{"index": {"_id": "10.39A"}} -{"name": "Autre transformation et conservation de légumes", "parent": "C"} -{"index": {"_id": "10.39B"}} -{"name": "Transformation et conservation de fruits", "parent": "C"} -{"index": {"_id": "10.41A"}} -{"name": "Fabrication d'huiles et graisses brutes", "parent": "C"} -{"index": {"_id": "10.41B"}} -{"name": "Fabrication d'huiles et graisses raffinées", "parent": "C"} -{"index": {"_id": "10.42Z"}} -{"name": "Fabrication de margarine et graisses comestibles similaires", "parent": "C"} -{"index": {"_id": "10.51A"}} -{"name": "Fabrication de lait liquide et de produits frais", "parent": "C"} -{"index": {"_id": "10.51B"}} -{"name": "Fabrication de beurre", "parent": "C"} -{"index": {"_id": "10.51C"}} -{"name": "Fabrication de fromage", "parent": "C"} -{"index": {"_id": "10.51D"}} -{"name": "Fabrication d'autres produits laitiers", "parent": "C"} -{"index": {"_id": "10.52Z"}} -{"name": "Fabrication de glaces et sorbets", "parent": "C"} -{"index": {"_id": "10.61A"}} -{"name": "Meunerie", "parent": "C"} -{"index": {"_id": "10.61B"}} -{"name": "Autres activités du travail des grains", "parent": "C"} -{"index": {"_id": "10.62Z"}} -{"name": "Fabrication de produits amylacés", "parent": "C"} -{"index": {"_id": "10.71A"}} -{"name": "Fabrication industrielle de pain et de pâtisserie fraîche", "parent": "C"} -{"index": {"_id": "10.71B"}} -{"name": "Cuisson de produits de boulangerie", "parent": "C"} -{"index": {"_id": "10.71C"}} -{"name": "Boulangerie et boulangerie-pâtisserie", "parent": "C"} -{"index": {"_id": "10.71D"}} -{"name": "Pâtisserie", "parent": "C"} -{"index": {"_id": "10.72Z"}} -{"name": "Fabrication de biscuits, biscottes et pâtisseries de conservation", "parent": "C"} -{"index": {"_id": "10.73Z"}} -{"name": "Fabrication de pâtes alimentaires", "parent": "C"} -{"index": {"_id": "10.81Z"}} -{"name": "Fabrication de sucre", "parent": "C"} -{"index": {"_id": "10.82Z"}} -{"name": "Fabrication de cacao, chocolat et de produits de confiserie", "parent": "C"} -{"index": {"_id": "10.83Z"}} -{"name": "Transformation du thé et du café", "parent": "C"} -{"index": {"_id": "10.84Z"}} -{"name": "Fabrication de condiments et assaisonnements", "parent": "C"} -{"index": {"_id": "10.85Z"}} -{"name": "Fabrication de plats préparés", "parent": "C"} -{"index": {"_id": "10.86Z"}} -{"name": "Fabrication d'aliments homogénéisés et diététiques", "parent": "C"} -{"index": {"_id": "10.89Z"}} -{"name": "Fabrication d'autres produits alimentaires n.c.a.", "parent": "C"} -{"index": {"_id": "10.91Z"}} -{"name": "Fabrication d'aliments pour animaux de ferme", "parent": "C"} -{"index": {"_id": "10.92Z"}} -{"name": "Fabrication d'aliments pour animaux de compagnie", "parent": "C"} -{"index": {"_id": "11.01Z"}} -{"name": "Production de boissons alcooliques distillées", "parent": "C"} -{"index": {"_id": "11.02A"}} -{"name": "Fabrication de vins effervescents", "parent": "C"} -{"index": {"_id": "11.02B"}} -{"name": "Vinification", "parent": "C"} -{"index": {"_id": "11.03Z"}} -{"name": "Fabrication de cidre et de vins de fruits", "parent": "C"} -{"index": {"_id": "11.04Z"}} -{"name": "Production d'autres boissons fermentées non distillées", "parent": "C"} -{"index": {"_id": "11.05Z"}} -{"name": "Fabrication de bière", "parent": "C"} -{"index": {"_id": "11.06Z"}} -{"name": "Fabrication de malt", "parent": "C"} -{"index": {"_id": "11.07A"}} -{"name": "Industrie des eaux de table", "parent": "C"} -{"index": {"_id": "11.07B"}} -{"name": "Production de boissons rafraîchissantes", "parent": "C"} -{"index": {"_id": "12.00Z"}} -{"name": "Fabrication de produits à base de tabac", "parent": "C"} -{"index": {"_id": "13.10Z"}} -{"name": "Préparation de fibres textiles et filature", "parent": "C"} -{"index": {"_id": "13.20Z"}} -{"name": "Tissage", "parent": "C"} -{"index": {"_id": "13.30Z"}} -{"name": "Ennoblissement textile", "parent": "C"} -{"index": {"_id": "13.91Z"}} -{"name": "Fabrication d'étoffes à mailles", "parent": "C"} -{"index": {"_id": "13.92Z"}} -{"name": "Fabrication d'articles textiles, sauf habillement", "parent": "C"} -{"index": {"_id": "13.93Z"}} -{"name": "Fabrication de tapis et moquettes", "parent": "C"} -{"index": {"_id": "13.94Z"}} -{"name": "Fabrication de ficelles, cordes et filets", "parent": "C"} -{"index": {"_id": "13.95Z"}} -{"name": "Fabrication de non-tissés, sauf habillement", "parent": "C"} -{"index": {"_id": "13.96Z"}} -{"name": "Fabrication d'autres textiles techniques et industriels", "parent": "C"} -{"index": {"_id": "13.99Z"}} -{"name": "Fabrication d'autres textiles n.c.a.", "parent": "C"} -{"index": {"_id": "14.11Z"}} -{"name": "Fabrication de vêtements en cuir", "parent": "C"} -{"index": {"_id": "14.12Z"}} -{"name": "Fabrication de vêtements de travail", "parent": "C"} -{"index": {"_id": "14.13Z"}} -{"name": "Fabrication de vêtements de dessus", "parent": "C"} -{"index": {"_id": "14.14Z"}} -{"name": "Fabrication de vêtements de dessous", "parent": "C"} -{"index": {"_id": "14.19Z"}} -{"name": "Fabrication d'autres vêtements et accessoires", "parent": "C"} -{"index": {"_id": "14.20Z"}} -{"name": "Fabrication d'articles en fourrure", "parent": "C"} -{"index": {"_id": "14.31Z"}} -{"name": "Fabrication d'articles chaussants à mailles", "parent": "C"} -{"index": {"_id": "14.39Z"}} -{"name": "Fabrication d'autres articles à mailles", "parent": "C"} -{"index": {"_id": "15.11Z"}} -{"name": "Apprêt et tannage des cuirs ; préparation et teinture des fourrures", "parent": "C"} -{"index": {"_id": "15.12Z"}} -{"name": "Fabrication d'articles de voyage, de maroquinerie et de sellerie", "parent": "C"} -{"index": {"_id": "15.20Z"}} -{"name": "Fabrication de chaussures", "parent": "C"} -{"index": {"_id": "16.10A"}} -{"name": "Sciage et rabotage du bois, hors imprégnation", "parent": "C"} -{"index": {"_id": "16.10B"}} -{"name": "Imprégnation du bois", "parent": "C"} -{"index": {"_id": "16.21Z"}} -{"name": "Fabrication de placage et de panneaux de bois", "parent": "C"} -{"index": {"_id": "16.22Z"}} -{"name": "Fabrication de parquets assemblés", "parent": "C"} -{"index": {"_id": "16.23Z"}} -{"name": "Fabrication de charpentes et d'autres menuiseries", "parent": "C"} -{"index": {"_id": "16.24Z"}} -{"name": "Fabrication d'emballages en bois", "parent": "C"} -{"index": {"_id": "16.29Z"}} -{"name": "Fabrication d'objets divers en bois ; fabrication d'objets en liège, vannerie et sparterie", "parent": "C"} -{"index": {"_id": "17.11Z"}} -{"name": "Fabrication de pâte à papier", "parent": "C"} -{"index": {"_id": "17.12Z"}} -{"name": "Fabrication de papier et de carton", "parent": "C"} -{"index": {"_id": "17.21A"}} -{"name": "Fabrication de carton ondulé", "parent": "C"} -{"index": {"_id": "17.21B"}} -{"name": "Fabrication de cartonnages", "parent": "C"} -{"index": {"_id": "17.21C"}} -{"name": "Fabrication d'emballages en papier", "parent": "C"} -{"index": {"_id": "17.22Z"}} -{"name": "Fabrication d'articles en papier à usage sanitaire ou domestique", "parent": "C"} -{"index": {"_id": "17.23Z"}} -{"name": "Fabrication d'articles de papeterie", "parent": "C"} -{"index": {"_id": "17.24Z"}} -{"name": "Fabrication de papiers peints", "parent": "C"} -{"index": {"_id": "17.29Z"}} -{"name": "Fabrication d'autres articles en papier ou en carton", "parent": "C"} -{"index": {"_id": "18.11Z"}} -{"name": "Imprimerie de journaux", "parent": "C"} -{"index": {"_id": "18.12Z"}} -{"name": "Autre imprimerie (labeur)", "parent": "C"} -{"index": {"_id": "18.13Z"}} -{"name": "Activités de pré-presse", "parent": "C"} -{"index": {"_id": "18.14Z"}} -{"name": "Reliure et activités connexes", "parent": "C"} -{"index": {"_id": "18.20Z"}} -{"name": "Reproduction d'enregistrements", "parent": "C"} -{"index": {"_id": "19.10Z"}} -{"name": "Cokéfaction", "parent": "C"} -{"index": {"_id": "19.20Z"}} -{"name": "Raffinage du pétrole", "parent": "C"} -{"index": {"_id": "20.11Z"}} -{"name": "Fabrication de gaz industriels", "parent": "C"} -{"index": {"_id": "20.12Z"}} -{"name": "Fabrication de colorants et de pigments", "parent": "C"} -{"index": {"_id": "20.13A"}} -{"name": "Enrichissement et retraitement de matières nucléaires", "parent": "C"} -{"index": {"_id": "20.13B"}} -{"name": "Fabrication d'autres produits chimiques inorganiques de base n.c.a.", "parent": "C"} -{"index": {"_id": "20.14Z"}} -{"name": "Fabrication d'autres produits chimiques organiques de base", "parent": "C"} -{"index": {"_id": "20.15Z"}} -{"name": "Fabrication de produits azotés et d'engrais", "parent": "C"} -{"index": {"_id": "20.16Z"}} -{"name": "Fabrication de matières plastiques de base", "parent": "C"} -{"index": {"_id": "20.17Z"}} -{"name": "Fabrication de caoutchouc synthétique", "parent": "C"} -{"index": {"_id": "20.20Z"}} -{"name": "Fabrication de pesticides et d'autres produits agrochimiques", "parent": "C"} -{"index": {"_id": "20.30Z"}} -{"name": "Fabrication de peintures, vernis, encres et mastics", "parent": "C"} -{"index": {"_id": "20.41Z"}} -{"name": "Fabrication de savons, détergents et produits d'entretien", "parent": "C"} -{"index": {"_id": "20.42Z"}} -{"name": "Fabrication de parfums et de produits pour la toilette", "parent": "C"} -{"index": {"_id": "20.51Z"}} -{"name": "Fabrication de produits explosifs", "parent": "C"} -{"index": {"_id": "20.52Z"}} -{"name": "Fabrication de colles", "parent": "C"} -{"index": {"_id": "20.53Z"}} -{"name": "Fabrication d'huiles essentielles", "parent": "C"} -{"index": {"_id": "20.59Z"}} -{"name": "Fabrication d'autres produits chimiques n.c.a.", "parent": "C"} -{"index": {"_id": "20.60Z"}} -{"name": "Fabrication de fibres artificielles ou synthétiques", "parent": "C"} -{"index": {"_id": "21.10Z"}} -{"name": "Fabrication de produits pharmaceutiques de base", "parent": "C"} -{"index": {"_id": "21.20Z"}} -{"name": "Fabrication de préparations pharmaceutiques", "parent": "C"} -{"index": {"_id": "22.11Z"}} -{"name": "Fabrication et rechapage de pneumatiques", "parent": "C"} -{"index": {"_id": "22.19Z"}} -{"name": "Fabrication d'autres articles en caoutchouc", "parent": "C"} -{"index": {"_id": "22.21Z"}} -{"name": "Fabrication de plaques, feuilles, tubes et profilés en matières plastiques", "parent": "C"} -{"index": {"_id": "22.22Z"}} -{"name": "Fabrication d'emballages en matières plastiques", "parent": "C"} -{"index": {"_id": "22.23Z"}} -{"name": "Fabrication d'éléments en matières plastiques pour la construction", "parent": "C"} -{"index": {"_id": "22.29A"}} -{"name": "Fabrication de pièces techniques à base de matières plastiques", "parent": "C"} -{"index": {"_id": "22.29B"}} -{"name": "Fabrication de produits de consommation courante en matières plastiques", "parent": "C"} -{"index": {"_id": "23.11Z"}} -{"name": "Fabrication de verre plat", "parent": "C"} -{"index": {"_id": "23.12Z"}} -{"name": "Façonnage et transformation du verre plat", "parent": "C"} -{"index": {"_id": "23.13Z"}} -{"name": "Fabrication de verre creux", "parent": "C"} -{"index": {"_id": "23.14Z"}} -{"name": "Fabrication de fibres de verre", "parent": "C"} -{"index": {"_id": "23.19Z"}} -{"name": "Fabrication et façonnage d'autres articles en verre, y compris verre technique", "parent": "C"} -{"index": {"_id": "23.20Z"}} -{"name": "Fabrication de produits réfractaires", "parent": "C"} -{"index": {"_id": "23.31Z"}} -{"name": "Fabrication de carreaux en céramique", "parent": "C"} -{"index": {"_id": "23.32Z"}} -{"name": "Fabrication de briques, tuiles et produits de construction, en terre cuite", "parent": "C"} -{"index": {"_id": "23.41Z"}} -{"name": "Fabrication d'articles céramiques à usage domestique ou ornemental", "parent": "C"} -{"index": {"_id": "23.42Z"}} -{"name": "Fabrication d'appareils sanitaires en céramique", "parent": "C"} -{"index": {"_id": "23.43Z"}} -{"name": "Fabrication d'isolateurs et pièces isolantes en céramique", "parent": "C"} -{"index": {"_id": "23.44Z"}} -{"name": "Fabrication d'autres produits céramiques à usage technique", "parent": "C"} -{"index": {"_id": "23.49Z"}} -{"name": "Fabrication d'autres produits céramiques", "parent": "C"} -{"index": {"_id": "23.51Z"}} -{"name": "Fabrication de ciment", "parent": "C"} -{"index": {"_id": "23.52Z"}} -{"name": "Fabrication de chaux et plâtre", "parent": "C"} -{"index": {"_id": "23.61Z"}} -{"name": "Fabrication d'éléments en béton pour la construction", "parent": "C"} -{"index": {"_id": "23.62Z"}} -{"name": "Fabrication d'éléments en plâtre pour la construction", "parent": "C"} -{"index": {"_id": "23.63Z"}} -{"name": "Fabrication de béton prêt à l'emploi", "parent": "C"} -{"index": {"_id": "23.64Z"}} -{"name": "Fabrication de mortiers et bétons secs", "parent": "C"} -{"index": {"_id": "23.65Z"}} -{"name": "Fabrication d'ouvrages en fibre-ciment", "parent": "C"} -{"index": {"_id": "23.69Z"}} -{"name": "Fabrication d'autres ouvrages en béton, en ciment ou en plâtre", "parent": "C"} -{"index": {"_id": "23.70Z"}} -{"name": "Taille, façonnage et finissage de pierres", "parent": "C"} -{"index": {"_id": "23.91Z"}} -{"name": "Fabrication de produits abrasifs", "parent": "C"} -{"index": {"_id": "23.99Z"}} -{"name": "Fabrication d'autres produits minéraux non métalliques n.c.a.", "parent": "C"} -{"index": {"_id": "24.10Z"}} -{"name": "Sidérurgie", "parent": "C"} -{"index": {"_id": "24.20Z"}} -{"name": "Fabrication de tubes, tuyaux, profilés creux et accessoires correspondants en acier", "parent": "C"} -{"index": {"_id": "24.31Z"}} -{"name": "Étirage à froid de barres", "parent": "C"} -{"index": {"_id": "24.32Z"}} -{"name": "Laminage à froid de feuillards", "parent": "C"} -{"index": {"_id": "24.33Z"}} -{"name": "Profilage à froid par formage ou pliage", "parent": "C"} -{"index": {"_id": "24.34Z"}} -{"name": "Tréfilage à froid", "parent": "C"} -{"index": {"_id": "24.41Z"}} -{"name": "Production de métaux précieux", "parent": "C"} -{"index": {"_id": "24.42Z"}} -{"name": "Métallurgie de l'aluminium", "parent": "C"} -{"index": {"_id": "24.43Z"}} -{"name": "Métallurgie du plomb, du zinc ou de l'étain", "parent": "C"} -{"index": {"_id": "24.44Z"}} -{"name": "Métallurgie du cuivre", "parent": "C"} -{"index": {"_id": "24.45Z"}} -{"name": "Métallurgie des autres métaux non ferreux", "parent": "C"} -{"index": {"_id": "24.46Z"}} -{"name": "Élaboration et transformation de matières nucléaires", "parent": "C"} -{"index": {"_id": "24.51Z"}} -{"name": "Fonderie de fonte", "parent": "C"} -{"index": {"_id": "24.52Z"}} -{"name": "Fonderie d'acier", "parent": "C"} -{"index": {"_id": "24.53Z"}} -{"name": "Fonderie de métaux légers", "parent": "C"} -{"index": {"_id": "24.54Z"}} -{"name": "Fonderie d'autres métaux non ferreux", "parent": "C"} -{"index": {"_id": "25.11Z"}} -{"name": "Fabrication de structures métalliques et de parties de structures", "parent": "C"} -{"index": {"_id": "25.12Z"}} -{"name": "Fabrication de portes et fenêtres en métal", "parent": "C"} -{"index": {"_id": "25.21Z"}} -{"name": "Fabrication de radiateurs et de chaudières pour le chauffage central", "parent": "C"} -{"index": {"_id": "25.29Z"}} -{"name": "Fabrication d'autres réservoirs, citernes et conteneurs métalliques", "parent": "C"} -{"index": {"_id": "25.30Z"}} -{"name": "Fabrication de générateurs de vapeur, à l'exception des chaudières pour le chauffage central", "parent": "C"} -{"index": {"_id": "25.40Z"}} -{"name": "Fabrication d'armes et de munitions", "parent": "C"} -{"index": {"_id": "25.50A"}} -{"name": "Forge, estampage, matriçage ; métallurgie des poudres", "parent": "C"} -{"index": {"_id": "25.50B"}} -{"name": "Découpage, emboutissage", "parent": "C"} -{"index": {"_id": "25.61Z"}} -{"name": "Traitement et revêtement des métaux", "parent": "C"} -{"index": {"_id": "25.62A"}} -{"name": "Décolletage", "parent": "C"} -{"index": {"_id": "25.62B"}} -{"name": "Mécanique industrielle", "parent": "C"} -{"index": {"_id": "25.71Z"}} -{"name": "Fabrication de coutellerie", "parent": "C"} -{"index": {"_id": "25.72Z"}} -{"name": "Fabrication de serrures et de ferrures", "parent": "C"} -{"index": {"_id": "25.73A"}} -{"name": "Fabrication de moules et modèles", "parent": "C"} -{"index": {"_id": "25.73B"}} -{"name": "Fabrication d'autres outillages", "parent": "C"} -{"index": {"_id": "25.91Z"}} -{"name": "Fabrication de fûts et emballages métalliques similaires", "parent": "C"} -{"index": {"_id": "25.92Z"}} -{"name": "Fabrication d'emballages métalliques légers", "parent": "C"} -{"index": {"_id": "25.93Z"}} -{"name": "Fabrication d'articles en fils métalliques, de chaînes et de ressorts", "parent": "C"} -{"index": {"_id": "25.94Z"}} -{"name": "Fabrication de vis et de boulons", "parent": "C"} -{"index": {"_id": "25.99A"}} -{"name": "Fabrication d'articles métalliques ménagers", "parent": "C"} -{"index": {"_id": "25.99B"}} -{"name": "Fabrication d'autres articles métalliques", "parent": "C"} -{"index": {"_id": "26.11Z"}} -{"name": "Fabrication de composants électroniques", "parent": "C"} -{"index": {"_id": "26.12Z"}} -{"name": "Fabrication de cartes électroniques assemblées", "parent": "C"} -{"index": {"_id": "26.20Z"}} -{"name": "Fabrication d'ordinateurs et d'équipements périphériques", "parent": "C"} -{"index": {"_id": "26.30Z"}} -{"name": "Fabrication d'équipements de communication", "parent": "C"} -{"index": {"_id": "26.40Z"}} -{"name": "Fabrication de produits électroniques grand public", "parent": "C"} -{"index": {"_id": "26.51A"}} -{"name": "Fabrication d'équipements d'aide à la navigation", "parent": "C"} -{"index": {"_id": "26.51B"}} -{"name": "Fabrication d'instrumentation scientifique et technique", "parent": "C"} -{"index": {"_id": "26.52Z"}} -{"name": "Horlogerie", "parent": "C"} -{"index": {"_id": "26.60Z"}} -{"name": "Fabrication d'équipements d'irradiation médicale, d'équipements électromédicaux et électrothérapeutiques", "parent": "C"} -{"index": {"_id": "26.70Z"}} -{"name": "Fabrication de matériels optique et photographique", "parent": "C"} -{"index": {"_id": "26.80Z"}} -{"name": "Fabrication de supports magnétiques et optiques", "parent": "C"} -{"index": {"_id": "27.11Z"}} -{"name": "Fabrication de moteurs, génératrices et transformateurs électriques", "parent": "C"} -{"index": {"_id": "27.12Z"}} -{"name": "Fabrication de matériel de distribution et de commande électrique", "parent": "C"} -{"index": {"_id": "27.20Z"}} -{"name": "Fabrication de piles et d'accumulateurs électriques", "parent": "C"} -{"index": {"_id": "27.31Z"}} -{"name": "Fabrication de câbles de fibres optiques", "parent": "C"} -{"index": {"_id": "27.32Z"}} -{"name": "Fabrication d'autres fils et câbles électroniques ou électriques", "parent": "C"} -{"index": {"_id": "27.33Z"}} -{"name": "Fabrication de matériel d'installation électrique", "parent": "C"} -{"index": {"_id": "27.40Z"}} -{"name": "Fabrication d'appareils d'éclairage électrique", "parent": "C"} -{"index": {"_id": "27.51Z"}} -{"name": "Fabrication d'appareils électroménagers", "parent": "C"} -{"index": {"_id": "27.52Z"}} -{"name": "Fabrication d'appareils ménagers non électriques", "parent": "C"} -{"index": {"_id": "27.90Z"}} -{"name": "Fabrication d'autres matériels électriques", "parent": "C"} -{"index": {"_id": "28.11Z"}} -{"name": "Fabrication de moteurs et turbines, à l'exception des moteurs d'avions et de véhicules", "parent": "C"} -{"index": {"_id": "28.12Z"}} -{"name": "Fabrication d'équipements hydrauliques et pneumatiques", "parent": "C"} -{"index": {"_id": "28.13Z"}} -{"name": "Fabrication d'autres pompes et compresseurs", "parent": "C"} -{"index": {"_id": "28.14Z"}} -{"name": "Fabrication d'autres articles de robinetterie", "parent": "C"} -{"index": {"_id": "28.15Z"}} -{"name": "Fabrication d'engrenages et d'organes mécaniques de transmission", "parent": "C"} -{"index": {"_id": "28.21Z"}} -{"name": "Fabrication de fours et brûleurs", "parent": "C"} -{"index": {"_id": "28.22Z"}} -{"name": "Fabrication de matériel de levage et de manutention", "parent": "C"} -{"index": {"_id": "28.23Z"}} -{"name": "Fabrication de machines et d'équipements de bureau (à l'exception des ordinateurs et équipements périphériques)", "parent": "C"} -{"index": {"_id": "28.24Z"}} -{"name": "Fabrication d'outillage portatif à moteur incorporé", "parent": "C"} -{"index": {"_id": "28.25Z"}} -{"name": "Fabrication d'équipements aérauliques et frigorifiques industriels", "parent": "C"} -{"index": {"_id": "28.29A"}} -{"name": "Fabrication d'équipements d'emballage, de conditionnement et de pesage", "parent": "C"} -{"index": {"_id": "28.29B"}} -{"name": "Fabrication d'autres machines d'usage général", "parent": "C"} -{"index": {"_id": "28.30Z"}} -{"name": "Fabrication de machines agricoles et forestières", "parent": "C"} -{"index": {"_id": "28.41Z"}} -{"name": "Fabrication de machines-outils pour le travail des métaux", "parent": "C"} -{"index": {"_id": "28.49Z"}} -{"name": "Fabrication d'autres machines-outils", "parent": "C"} -{"index": {"_id": "28.91Z"}} -{"name": "Fabrication de machines pour la métallurgie", "parent": "C"} -{"index": {"_id": "28.92Z"}} -{"name": "Fabrication de machines pour l'extraction ou la construction", "parent": "C"} -{"index": {"_id": "28.93Z"}} -{"name": "Fabrication de machines pour l'industrie agro-alimentaire", "parent": "C"} -{"index": {"_id": "28.94Z"}} -{"name": "Fabrication de machines pour les industries textiles", "parent": "C"} -{"index": {"_id": "28.95Z"}} -{"name": "Fabrication de machines pour les industries du papier et du carton", "parent": "C"} -{"index": {"_id": "28.96Z"}} -{"name": "Fabrication de machines pour le travail du caoutchouc ou des plastiques", "parent": "C"} -{"index": {"_id": "28.99A"}} -{"name": "Fabrication de machines d'imprimerie", "parent": "C"} -{"index": {"_id": "28.99B"}} -{"name": "Fabrication d'autres machines spécialisées", "parent": "C"} -{"index": {"_id": "29.10Z"}} -{"name": "Construction de véhicules automobiles", "parent": "C"} -{"index": {"_id": "29.20Z"}} -{"name": "Fabrication de carrosseries et remorques", "parent": "C"} -{"index": {"_id": "29.31Z"}} -{"name": "Fabrication d'équipements électriques et électroniques automobiles", "parent": "C"} -{"index": {"_id": "29.32Z"}} -{"name": "Fabrication d'autres équipements automobiles", "parent": "C"} -{"index": {"_id": "30.11Z"}} -{"name": "Construction de navires et de structures flottantes", "parent": "C"} -{"index": {"_id": "30.12Z"}} -{"name": "Construction de bateaux de plaisance", "parent": "C"} -{"index": {"_id": "30.20Z"}} -{"name": "Construction de locomotives et d'autre matériel ferroviaire roulant", "parent": "C"} -{"index": {"_id": "30.30Z"}} -{"name": "Construction aéronautique et spatiale", "parent": "C"} -{"index": {"_id": "30.40Z"}} -{"name": "Construction de véhicules militaires de combat", "parent": "C"} -{"index": {"_id": "30.91Z"}} -{"name": "Fabrication de motocycles", "parent": "C"} -{"index": {"_id": "30.92Z"}} -{"name": "Fabrication de bicyclettes et de véhicules pour invalides", "parent": "C"} -{"index": {"_id": "30.99Z"}} -{"name": "Fabrication d'autres équipements de transport n.c.a.", "parent": "C"} -{"index": {"_id": "31.01Z"}} -{"name": "Fabrication de meubles de bureau et de magasin", "parent": "C"} -{"index": {"_id": "31.02Z"}} -{"name": "Fabrication de meubles de cuisine", "parent": "C"} -{"index": {"_id": "31.03Z"}} -{"name": "Fabrication de matelas", "parent": "C"} -{"index": {"_id": "31.09A"}} -{"name": "Fabrication de sièges d'ameublement d'intérieur", "parent": "C"} -{"index": {"_id": "31.09B"}} -{"name": "Fabrication d'autres meubles et industries connexes de l'ameublement", "parent": "C"} -{"index": {"_id": "32.11Z"}} -{"name": "Frappe de monnaie", "parent": "C"} -{"index": {"_id": "32.12Z"}} -{"name": "Fabrication d'articles de joaillerie et bijouterie", "parent": "C"} -{"index": {"_id": "32.13Z"}} -{"name": "Fabrication d'articles de bijouterie fantaisie et articles similaires", "parent": "C"} -{"index": {"_id": "32.20Z"}} -{"name": "Fabrication d'instruments de musique", "parent": "C"} -{"index": {"_id": "32.30Z"}} -{"name": "Fabrication d'articles de sport", "parent": "C"} -{"index": {"_id": "32.40Z"}} -{"name": "Fabrication de jeux et jouets", "parent": "C"} -{"index": {"_id": "32.50A"}} -{"name": "Fabrication de matériel médico-chirurgical et dentaire", "parent": "C"} -{"index": {"_id": "32.50B"}} -{"name": "Fabrication de lunettes", "parent": "C"} -{"index": {"_id": "32.91Z"}} -{"name": "Fabrication d'articles de brosserie", "parent": "C"} -{"index": {"_id": "32.99Z"}} -{"name": "Autres activités manufacturières n.c.a.", "parent": "C"} -{"index": {"_id": "33.11Z"}} -{"name": "Réparation d'ouvrages en métaux", "parent": "C"} -{"index": {"_id": "33.12Z"}} -{"name": "Réparation de machines et équipements mécaniques", "parent": "C"} -{"index": {"_id": "33.13Z"}} -{"name": "Réparation de matériels électroniques et optiques", "parent": "C"} -{"index": {"_id": "33.14Z"}} -{"name": "Réparation d'équipements électriques", "parent": "C"} -{"index": {"_id": "33.15Z"}} -{"name": "Réparation et maintenance navale", "parent": "C"} -{"index": {"_id": "33.16Z"}} -{"name": "Réparation et maintenance d'aéronefs et d'engins spatiaux", "parent": "C"} -{"index": {"_id": "33.17Z"}} -{"name": "Réparation et maintenance d'autres équipements de transport", "parent": "C"} -{"index": {"_id": "33.19Z"}} -{"name": "Réparation d'autres équipements", "parent": "C"} -{"index": {"_id": "33.20A"}} -{"name": "Installation de structures métalliques, chaudronnées et de tuyauterie", "parent": "C"} -{"index": {"_id": "33.20B"}} -{"name": "Installation de machines et équipements mécaniques", "parent": "C"} -{"index": {"_id": "33.20C"}} -{"name": "Conception d'ensemble et assemblage sur site industriel d'équipements de contrôle des processus industriels", "parent": "C"} -{"index": {"_id": "33.20D"}} -{"name": "Installation d'équipements électriques, de matériels électroniques et optiques ou d'autres matériels", "parent": "C"} -{"index": {"_id": "D"}} -{"name": "Production et distribution d'électricité, de gaz, de vapeur et d'air conditionné", "parent": null} -{"index": {"_id": "35.11Z"}} -{"name": "Production d'électricité", "parent": "D"} -{"index": {"_id": "35.12Z"}} -{"name": "Transport d'électricité", "parent": "D"} -{"index": {"_id": "35.13Z"}} -{"name": "Distribution d'électricité", "parent": "D"} -{"index": {"_id": "35.14Z"}} -{"name": "Commerce d'électricité", "parent": "D"} -{"index": {"_id": "35.21Z"}} -{"name": "Production de combustibles gazeux", "parent": "D"} -{"index": {"_id": "35.22Z"}} -{"name": "Distribution de combustibles gazeux par conduites", "parent": "D"} -{"index": {"_id": "35.23Z"}} -{"name": "Commerce de combustibles gazeux par conduites", "parent": "D"} -{"index": {"_id": "35.30Z"}} -{"name": "Production et distribution de vapeur et d'air conditionné", "parent": "D"} -{"index": {"_id": "E"}} -{"name": "Production et distribution d'eau ; assainissement, gestion des déchets et dépollution", "parent": null} -{"index": {"_id": "36.00Z"}} -{"name": "Captage, traitement et distribution d'eau", "parent": "E"} -{"index": {"_id": "37.00Z"}} -{"name": "Collecte et traitement des eaux usées", "parent": "E"} -{"index": {"_id": "38.11Z"}} -{"name": "Collecte des déchets non dangereux", "parent": "E"} -{"index": {"_id": "38.12Z"}} -{"name": "Collecte des déchets dangereux", "parent": "E"} -{"index": {"_id": "38.21Z"}} -{"name": "Traitement et élimination des déchets non dangereux", "parent": "E"} -{"index": {"_id": "38.22Z"}} -{"name": "Traitement et élimination des déchets dangereux", "parent": "E"} -{"index": {"_id": "38.31Z"}} -{"name": "Démantèlement d'épaves", "parent": "E"} -{"index": {"_id": "38.32Z"}} -{"name": "Récupération de déchets triés", "parent": "E"} -{"index": {"_id": "39.00Z"}} -{"name": "Dépollution et autres services de gestion des déchets", "parent": "E"} -{"index": {"_id": "F"}} -{"name": "Construction", "parent": null} -{"index": {"_id": "41.10A"}} -{"name": "Promotion immobilière de logements", "parent": "F"} -{"index": {"_id": "41.10B"}} -{"name": "Promotion immobilière de bureaux", "parent": "F"} -{"index": {"_id": "41.10C"}} -{"name": "Promotion immobilière d'autres bâtiments", "parent": "F"} -{"index": {"_id": "41.10D"}} -{"name": "Supports juridiques de programmes", "parent": "F"} -{"index": {"_id": "41.20A"}} -{"name": "Construction de maisons individuelles", "parent": "F"} -{"index": {"_id": "41.20B"}} -{"name": "Construction d'autres bâtiments", "parent": "F"} -{"index": {"_id": "42.11Z"}} -{"name": "Construction de routes et autoroutes", "parent": "F"} -{"index": {"_id": "42.12Z"}} -{"name": "Construction de voies ferrées de surface et souterraines", "parent": "F"} -{"index": {"_id": "42.13A"}} -{"name": "Construction d'ouvrages d'art", "parent": "F"} -{"index": {"_id": "42.13B"}} -{"name": "Construction et entretien de tunnels", "parent": "F"} -{"index": {"_id": "42.21Z"}} -{"name": "Construction de réseaux pour fluides", "parent": "F"} -{"index": {"_id": "42.22Z"}} -{"name": "Construction de réseaux électriques et de télécommunications", "parent": "F"} -{"index": {"_id": "42.91Z"}} -{"name": "Construction d'ouvrages maritimes et fluviaux", "parent": "F"} -{"index": {"_id": "42.99Z"}} -{"name": "Construction d'autres ouvrages de génie civil n.c.a.", "parent": "F"} -{"index": {"_id": "43.11Z"}} -{"name": "Travaux de démolition", "parent": "F"} -{"index": {"_id": "43.12A"}} -{"name": "Travaux de terrassement courants et travaux préparatoires", "parent": "F"} -{"index": {"_id": "43.12B"}} -{"name": "Travaux de terrassement spécialisés ou de grande masse", "parent": "F"} -{"index": {"_id": "43.13Z"}} -{"name": "Forages et sondages", "parent": "F"} -{"index": {"_id": "43.21A"}} -{"name": "Travaux d'installation électrique dans tous locaux", "parent": "F"} -{"index": {"_id": "43.21B"}} -{"name": "Travaux d'installation électrique sur la voie publique", "parent": "F"} -{"index": {"_id": "43.22A"}} -{"name": "Travaux d'installation d'eau et de gaz en tous locaux", "parent": "F"} -{"index": {"_id": "43.22B"}} -{"name": "Travaux d'installation d'équipements thermiques et de climatisation", "parent": "F"} -{"index": {"_id": "43.29A"}} -{"name": "Travaux d'isolation", "parent": "F"} -{"index": {"_id": "43.29B"}} -{"name": "Autres travaux d'installation n.c.a.", "parent": "F"} -{"index": {"_id": "43.31Z"}} -{"name": "Travaux de plâtrerie", "parent": "F"} -{"index": {"_id": "43.32A"}} -{"name": "Travaux de menuiserie bois et PVC", "parent": "F"} -{"index": {"_id": "43.32B"}} -{"name": "Travaux de menuiserie métallique et serrurerie", "parent": "F"} -{"index": {"_id": "43.32C"}} -{"name": "Agencement de lieux de vente", "parent": "F"} -{"index": {"_id": "43.33Z"}} -{"name": "Travaux de revêtement des sols et des murs", "parent": "F"} -{"index": {"_id": "43.34Z"}} -{"name": "Travaux de peinture et vitrerie", "parent": "F"} -{"index": {"_id": "43.39Z"}} -{"name": "Autres travaux de finition", "parent": "F"} -{"index": {"_id": "43.91A"}} -{"name": "Travaux de charpente", "parent": "F"} -{"index": {"_id": "43.91B"}} -{"name": "Travaux de couverture par éléments", "parent": "F"} -{"index": {"_id": "43.99A"}} -{"name": "Travaux d'étanchéification", "parent": "F"} -{"index": {"_id": "43.99B"}} -{"name": "Travaux de montage de structures métalliques", "parent": "F"} -{"index": {"_id": "43.99C"}} -{"name": "Travaux de maçonnerie générale et gros œuvre de bâtiment", "parent": "F"} -{"index": {"_id": "43.99D"}} -{"name": "Autres travaux spécialisés de construction", "parent": "F"} -{"index": {"_id": "43.99E"}} -{"name": "Location avec opérateur de matériel de construction", "parent": "F"} -{"index": {"_id": "G"}} -{"name": "Commerce ; réparation d'automobiles et de motocycles", "parent": null} -{"index": {"_id": "45.11Z"}} -{"name": "Commerce de voitures et de véhicules automobiles légers", "parent": "G"} -{"index": {"_id": "45.19Z"}} -{"name": "Commerce d'autres véhicules automobiles", "parent": "G"} -{"index": {"_id": "45.20A"}} -{"name": "Entretien et réparation de véhicules automobiles légers", "parent": "G"} -{"index": {"_id": "45.20B"}} -{"name": "Entretien et réparation d'autres véhicules automobiles", "parent": "G"} -{"index": {"_id": "45.31Z"}} -{"name": "Commerce de gros d'équipements automobiles", "parent": "G"} -{"index": {"_id": "45.32Z"}} -{"name": "Commerce de détail d'équipements automobiles", "parent": "G"} -{"index": {"_id": "45.40Z"}} -{"name": "Commerce et réparation de motocycles", "parent": "G"} -{"index": {"_id": "46.11Z"}} -{"name": "Intermédiaires du commerce en matières premières agricoles, animaux vivants, matières premières textiles et produits semi-finis", "parent": "G"} -{"index": {"_id": "46.12A"}} -{"name": "Centrales d'achat de carburant", "parent": "G"} -{"index": {"_id": "46.12B"}} -{"name": "Autres intermédiaires du commerce en combustibles, métaux, minéraux et produits chimiques", "parent": "G"} -{"index": {"_id": "46.13Z"}} -{"name": "Intermédiaires du commerce en bois et matériaux de construction", "parent": "G"} -{"index": {"_id": "46.14Z"}} -{"name": "Intermédiaires du commerce en machines, équipements industriels, navires et avions", "parent": "G"} -{"index": {"_id": "46.15Z"}} -{"name": "Intermédiaires du commerce en meubles, articles de ménage et quincaillerie", "parent": "G"} -{"index": {"_id": "46.16Z"}} -{"name": "Intermédiaires du commerce en textiles, habillement, fourrures, chaussures et articles en cuir", "parent": "G"} -{"index": {"_id": "46.17A"}} -{"name": "Centrales d'achat alimentaires", "parent": "G"} -{"index": {"_id": "46.17B"}} -{"name": "Autres intermédiaires du commerce en denrées, boissons et tabac", "parent": "G"} -{"index": {"_id": "46.18Z"}} -{"name": "Intermédiaires spécialisés dans le commerce d'autres produits spécifiques", "parent": "G"} -{"index": {"_id": "46.19A"}} -{"name": "Centrales d'achat non alimentaires", "parent": "G"} -{"index": {"_id": "46.19B"}} -{"name": "Autres intermédiaires du commerce en produits divers", "parent": "G"} -{"index": {"_id": "46.21Z"}} -{"name": "Commerce de gros (commerce interentreprises) de céréales, de tabac non manufacturé, de semences et d'aliments pour le bétail", "parent": "G"} -{"index": {"_id": "46.22Z"}} -{"name": "Commerce de gros (commerce interentreprises) de fleurs et plantes", "parent": "G"} -{"index": {"_id": "46.23Z"}} -{"name": "Commerce de gros (commerce interentreprises) d'animaux vivants", "parent": "G"} -{"index": {"_id": "46.24Z"}} -{"name": "Commerce de gros (commerce interentreprises) de cuirs et peaux", "parent": "G"} -{"index": {"_id": "46.31Z"}} -{"name": "Commerce de gros (commerce interentreprises) de fruits et légumes", "parent": "G"} -{"index": {"_id": "46.32A"}} -{"name": "Commerce de gros (commerce interentreprises) de viandes de boucherie", "parent": "G"} -{"index": {"_id": "46.32B"}} -{"name": "Commerce de gros (commerce interentreprises) de produits à base de viande", "parent": "G"} -{"index": {"_id": "46.32C"}} -{"name": "Commerce de gros (commerce interentreprises) de volailles et gibier", "parent": "G"} -{"index": {"_id": "46.33Z"}} -{"name": "Commerce de gros (commerce interentreprises) de produits laitiers, œufs, huiles et matières grasses comestibles", "parent": "G"} -{"index": {"_id": "46.34Z"}} -{"name": "Commerce de gros (commerce interentreprises) de boissons", "parent": "G"} -{"index": {"_id": "46.35Z"}} -{"name": "Commerce de gros (commerce interentreprises) de produits à base de tabac", "parent": "G"} -{"index": {"_id": "46.36Z"}} -{"name": "Commerce de gros (commerce interentreprises) de sucre, chocolat et confiserie", "parent": "G"} -{"index": {"_id": "46.37Z"}} -{"name": "Commerce de gros (commerce interentreprises) de café, thé, cacao et épices", "parent": "G"} -{"index": {"_id": "46.38A"}} -{"name": "Commerce de gros (commerce interentreprises) de poissons, crustacés et mollusques", "parent": "G"} -{"index": {"_id": "46.38B"}} -{"name": "Commerce de gros (commerce interentreprises) alimentaire spécialisé divers", "parent": "G"} -{"index": {"_id": "46.39A"}} -{"name": "Commerce de gros (commerce interentreprises) de produits surgelés", "parent": "G"} -{"index": {"_id": "46.39B"}} -{"name": "Commerce de gros (commerce interentreprises) alimentaire non spécialisé", "parent": "G"} -{"index": {"_id": "46.41Z"}} -{"name": "Commerce de gros (commerce interentreprises) de textiles", "parent": "G"} -{"index": {"_id": "46.42Z"}} -{"name": "Commerce de gros (commerce interentreprises) d'habillement et de chaussures", "parent": "G"} -{"index": {"_id": "46.43Z"}} -{"name": "Commerce de gros (commerce interentreprises) d'appareils électroménagers", "parent": "G"} -{"index": {"_id": "46.44Z"}} -{"name": "Commerce de gros (commerce interentreprises) de vaisselle, verrerie et produits d'entretien", "parent": "G"} -{"index": {"_id": "46.45Z"}} -{"name": "Commerce de gros (commerce interentreprises) de parfumerie et de produits de beauté", "parent": "G"} -{"index": {"_id": "46.46Z"}} -{"name": "Commerce de gros (commerce interentreprises) de produits pharmaceutiques", "parent": "G"} -{"index": {"_id": "46.47Z"}} -{"name": "Commerce de gros (commerce interentreprises) de meubles, de tapis et d'appareils d'éclairage", "parent": "G"} -{"index": {"_id": "46.48Z"}} -{"name": "Commerce de gros (commerce interentreprises) d'articles d'horlogerie et de bijouterie", "parent": "G"} -{"index": {"_id": "46.49Z"}} -{"name": "Commerce de gros (commerce interentreprises) d'autres biens domestiques", "parent": "G"} -{"index": {"_id": "46.51Z"}} -{"name": "Commerce de gros (commerce interentreprises) d'ordinateurs, d'équipements informatiques périphériques et de logiciels", "parent": "G"} -{"index": {"_id": "46.52Z"}} -{"name": "Commerce de gros (commerce interentreprises) de composants et d'équipements électroniques et de télécommunication", "parent": "G"} -{"index": {"_id": "46.61Z"}} -{"name": "Commerce de gros (commerce interentreprises) de matériel agricole", "parent": "G"} -{"index": {"_id": "46.62Z"}} -{"name": "Commerce de gros (commerce interentreprises) de machines-outils", "parent": "G"} -{"index": {"_id": "46.63Z"}} -{"name": "Commerce de gros (commerce interentreprises) de machines pour l'extraction, la construction et le génie civil", "parent": "G"} -{"index": {"_id": "46.64Z"}} -{"name": "Commerce de gros (commerce interentreprises) de machines pour l'industrie textile et l'habillement", "parent": "G"} -{"index": {"_id": "46.65Z"}} -{"name": "Commerce de gros (commerce interentreprises) de mobilier de bureau", "parent": "G"} -{"index": {"_id": "46.66Z"}} -{"name": "Commerce de gros (commerce interentreprises) d'autres machines et équipements de bureau", "parent": "G"} -{"index": {"_id": "46.69A"}} -{"name": "Commerce de gros (commerce interentreprises) de matériel électrique", "parent": "G"} -{"index": {"_id": "46.69B"}} -{"name": "Commerce de gros (commerce interentreprises) de fournitures et équipements industriels divers", "parent": "G"} -{"index": {"_id": "46.69C"}} -{"name": "Commerce de gros (commerce interentreprises) de fournitures et équipements divers pour le commerce et les services", "parent": "G"} -{"index": {"_id": "46.71Z"}} -{"name": "Commerce de gros (commerce interentreprises) de combustibles et de produits annexes", "parent": "G"} -{"index": {"_id": "46.72Z"}} -{"name": "Commerce de gros (commerce interentreprises) de minerais et métaux", "parent": "G"} -{"index": {"_id": "46.73A"}} -{"name": "Commerce de gros (commerce interentreprises) de bois et de matériaux de construction", "parent": "G"} -{"index": {"_id": "46.73B"}} -{"name": "Commerce de gros (commerce interentreprises) d'appareils sanitaires et de produits de décoration", "parent": "G"} -{"index": {"_id": "46.74A"}} -{"name": "Commerce de gros (commerce interentreprises) de quincaillerie", "parent": "G"} -{"index": {"_id": "46.74B"}} -{"name": "Commerce de gros (commerce interentreprises) de fournitures pour la plomberie et le chauffage", "parent": "G"} -{"index": {"_id": "46.75Z"}} -{"name": "Commerce de gros (commerce interentreprises) de produits chimiques", "parent": "G"} -{"index": {"_id": "46.76Z"}} -{"name": "Commerce de gros (commerce interentreprises) d'autres produits intermédiaires", "parent": "G"} -{"index": {"_id": "46.77Z"}} -{"name": "Commerce de gros (commerce interentreprises) de déchets et débris", "parent": "G"} -{"index": {"_id": "46.90Z"}} -{"name": "Commerce de gros (commerce interentreprises) non spécialisé", "parent": "G"} -{"index": {"_id": "47.11A"}} -{"name": "Commerce de détail de produits surgelés", "parent": "G"} -{"index": {"_id": "47.11B"}} -{"name": "Commerce d'alimentation générale", "parent": "G"} -{"index": {"_id": "47.11C"}} -{"name": "Supérettes", "parent": "G"} -{"index": {"_id": "47.11D"}} -{"name": "Supermarchés", "parent": "G"} -{"index": {"_id": "47.11E"}} -{"name": "Magasins multi-commerces", "parent": "G"} -{"index": {"_id": "47.11F"}} -{"name": "Hypermarchés", "parent": "G"} -{"index": {"_id": "47.19A"}} -{"name": "Grands magasins", "parent": "G"} -{"index": {"_id": "47.19B"}} -{"name": "Autres commerces de détail en magasin non spécialisé", "parent": "G"} -{"index": {"_id": "47.21Z"}} -{"name": "Commerce de détail de fruits et légumes en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.22Z"}} -{"name": "Commerce de détail de viandes et de produits à base de viande en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.23Z"}} -{"name": "Commerce de détail de poissons, crustacés et mollusques en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.24Z"}} -{"name": "Commerce de détail de pain, pâtisserie et confiserie en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.25Z"}} -{"name": "Commerce de détail de boissons en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.26Z"}} -{"name": "Commerce de détail de produits à base de tabac en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.29Z"}} -{"name": "Autres commerces de détail alimentaires en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.30Z"}} -{"name": "Commerce de détail de carburants en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.41Z"}} -{"name": "Commerce de détail d'ordinateurs, d'unités périphériques et de logiciels en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.42Z"}} -{"name": "Commerce de détail de matériels de télécommunication en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.43Z"}} -{"name": "Commerce de détail de matériels audio et vidéo en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.51Z"}} -{"name": "Commerce de détail de textiles en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.52A"}} -{"name": "Commerce de détail de quincaillerie, peintures et verres en petites surfaces (moins de 400 m²)", "parent": "G"} -{"index": {"_id": "47.52B"}} -{"name": "Commerce de détail de quincaillerie, peintures et verres en grandes surfaces (400 m² et plus)", "parent": "G"} -{"index": {"_id": "47.53Z"}} -{"name": "Commerce de détail de tapis, moquettes et revêtements de murs et de sols en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.54Z"}} -{"name": "Commerce de détail d'appareils électroménagers en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.59A"}} -{"name": "Commerce de détail de meubles", "parent": "G"} -{"index": {"_id": "47.59B"}} -{"name": "Commerce de détail d'autres équipements du foyer", "parent": "G"} -{"index": {"_id": "47.61Z"}} -{"name": "Commerce de détail de livres en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.62Z"}} -{"name": "Commerce de détail de journaux et papeterie en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.63Z"}} -{"name": "Commerce de détail d'enregistrements musicaux et vidéo en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.64Z"}} -{"name": "Commerce de détail d'articles de sport en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.65Z"}} -{"name": "Commerce de détail de jeux et jouets en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.71Z"}} -{"name": "Commerce de détail d'habillement en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.72A"}} -{"name": "Commerce de détail de la chaussure", "parent": "G"} -{"index": {"_id": "47.72B"}} -{"name": "Commerce de détail de maroquinerie et d'articles de voyage", "parent": "G"} -{"index": {"_id": "47.73Z"}} -{"name": "Commerce de détail de produits pharmaceutiques en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.74Z"}} -{"name": "Commerce de détail d'articles médicaux et orthopédiques en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.75Z"}} -{"name": "Commerce de détail de parfumerie et de produits de beauté en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.76Z"}} -{"name": "Commerce de détail de fleurs, plantes, graines, engrais, animaux de compagnie et aliments pour ces animaux en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.77Z"}} -{"name": "Commerce de détail d'articles d'horlogerie et de bijouterie en magasin spécialisé", "parent": "G"} -{"index": {"_id": "47.78A"}} -{"name": "Commerces de détail d'optique", "parent": "G"} -{"index": {"_id": "47.78B"}} -{"name": "Commerces de détail de charbons et combustibles", "parent": "G"} -{"index": {"_id": "47.78C"}} -{"name": "Autres commerces de détail spécialisés divers", "parent": "G"} -{"index": {"_id": "47.79Z"}} -{"name": "Commerce de détail de biens d'occasion en magasin", "parent": "G"} -{"index": {"_id": "47.81Z"}} -{"name": "Commerce de détail alimentaire sur éventaires et marchés", "parent": "G"} -{"index": {"_id": "47.82Z"}} -{"name": "Commerce de détail de textiles, d'habillement et de chaussures sur éventaires et marchés", "parent": "G"} -{"index": {"_id": "47.89Z"}} -{"name": "Autres commerces de détail sur éventaires et marchés", "parent": "G"} -{"index": {"_id": "47.91A"}} -{"name": "Vente à distance sur catalogue général", "parent": "G"} -{"index": {"_id": "47.91B"}} -{"name": "Vente à distance sur catalogue spécialisé", "parent": "G"} -{"index": {"_id": "47.99A"}} -{"name": "Vente à domicile", "parent": "G"} -{"index": {"_id": "47.99B"}} -{"name": "Vente par automates et autres commerces de détail hors magasin, éventaires ou marchés n.c.a.", "parent": "G"} -{"index": {"_id": "H"}} -{"name": "Transports et entreposage", "parent": null} -{"index": {"_id": "49.10Z"}} -{"name": "Transport ferroviaire interurbain de voyageurs", "parent": "H"} -{"index": {"_id": "49.20Z"}} -{"name": "Transports ferroviaires de fret", "parent": "H"} -{"index": {"_id": "49.31Z"}} -{"name": "Transports urbains et suburbains de voyageurs", "parent": "H"} -{"index": {"_id": "49.32Z"}} -{"name": "Transports de voyageurs par taxis", "parent": "H"} -{"index": {"_id": "49.39A"}} -{"name": "Transports routiers réguliers de voyageurs", "parent": "H"} -{"index": {"_id": "49.39B"}} -{"name": "Autres transports routiers de voyageurs", "parent": "H"} -{"index": {"_id": "49.39C"}} -{"name": "Téléphériques et remontées mécaniques", "parent": "H"} -{"index": {"_id": "49.41A"}} -{"name": "Transports routiers de fret interurbains", "parent": "H"} -{"index": {"_id": "49.41B"}} -{"name": "Transports routiers de fret de proximité", "parent": "H"} -{"index": {"_id": "49.41C"}} -{"name": "Location de camions avec chauffeur", "parent": "H"} -{"index": {"_id": "49.42Z"}} -{"name": "Services de déménagement", "parent": "H"} -{"index": {"_id": "49.50Z"}} -{"name": "Transports par conduites", "parent": "H"} -{"index": {"_id": "50.10Z"}} -{"name": "Transports maritimes et côtiers de passagers", "parent": "H"} -{"index": {"_id": "50.20Z"}} -{"name": "Transports maritimes et côtiers de fret", "parent": "H"} -{"index": {"_id": "50.30Z"}} -{"name": "Transports fluviaux de passagers", "parent": "H"} -{"index": {"_id": "50.40Z"}} -{"name": "Transports fluviaux de fret", "parent": "H"} -{"index": {"_id": "51.10Z"}} -{"name": "Transports aériens de passagers", "parent": "H"} -{"index": {"_id": "51.21Z"}} -{"name": "Transports aériens de fret", "parent": "H"} -{"index": {"_id": "51.22Z"}} -{"name": "Transports spatiaux", "parent": "H"} -{"index": {"_id": "52.10A"}} -{"name": "Entreposage et stockage frigorifique", "parent": "H"} -{"index": {"_id": "52.10B"}} -{"name": "Entreposage et stockage non frigorifique", "parent": "H"} -{"index": {"_id": "52.21Z"}} -{"name": "Services auxiliaires des transports terrestres", "parent": "H"} -{"index": {"_id": "52.22Z"}} -{"name": "Services auxiliaires des transports par eau", "parent": "H"} -{"index": {"_id": "52.23Z"}} -{"name": "Services auxiliaires des transports aériens", "parent": "H"} -{"index": {"_id": "52.24A"}} -{"name": "Manutention portuaire", "parent": "H"} -{"index": {"_id": "52.24B"}} -{"name": "Manutention non portuaire", "parent": "H"} -{"index": {"_id": "52.29A"}} -{"name": "Messagerie, fret express", "parent": "H"} -{"index": {"_id": "52.29B"}} -{"name": "Affrètement et organisation des transports", "parent": "H"} -{"index": {"_id": "53.10Z"}} -{"name": "Activités de poste dans le cadre d'une obligation de service universel", "parent": "H"} -{"index": {"_id": "53.20Z"}} -{"name": "Autres activités de poste et de courrier", "parent": "H"} -{"index": {"_id": "I"}} -{"name": "Hébergement et restauration", "parent": null} -{"index": {"_id": "55.10Z"}} -{"name": "Hôtels et hébergement similaire", "parent": "I"} -{"index": {"_id": "55.20Z"}} -{"name": "Hébergement touristique et autre hébergement de courte durée", "parent": "I"} -{"index": {"_id": "55.30Z"}} -{"name": "Terrains de camping et parcs pour caravanes ou véhicules de loisirs", "parent": "I"} -{"index": {"_id": "55.90Z"}} -{"name": "Autres hébergements", "parent": "I"} -{"index": {"_id": "56.10A"}} -{"name": "Restauration traditionnelle", "parent": "I"} -{"index": {"_id": "56.10B"}} -{"name": "Cafétérias et autres libres-services", "parent": "I"} -{"index": {"_id": "56.10C"}} -{"name": "Restauration de type rapide", "parent": "I"} -{"index": {"_id": "56.21Z"}} -{"name": "Services des traiteurs", "parent": "I"} -{"index": {"_id": "56.29A"}} -{"name": "Restauration collective sous contrat", "parent": "I"} -{"index": {"_id": "56.29B"}} -{"name": "Autres services de restauration n.c.a.", "parent": "I"} -{"index": {"_id": "56.30Z"}} -{"name": "Débits de boissons", "parent": "I"} -{"index": {"_id": "J"}} -{"name": "Information et communication", "parent": null} -{"index": {"_id": "58.11Z"}} -{"name": "Édition de livres", "parent": "J"} -{"index": {"_id": "58.12Z"}} -{"name": "Édition de répertoires et de fichiers d'adresses", "parent": "J"} -{"index": {"_id": "58.13Z"}} -{"name": "Édition de journaux", "parent": "J"} -{"index": {"_id": "58.14Z"}} -{"name": "Édition de revues et périodiques", "parent": "J"} -{"index": {"_id": "58.19Z"}} -{"name": "Autres activités d'édition", "parent": "J"} -{"index": {"_id": "58.21Z"}} -{"name": "Édition de jeux électroniques", "parent": "J"} -{"index": {"_id": "58.29A"}} -{"name": "Édition de logiciels système et de réseau", "parent": "J"} -{"index": {"_id": "58.29B"}} -{"name": "Édition de logiciels outils de développement et de langages", "parent": "J"} -{"index": {"_id": "58.29C"}} -{"name": "Édition de logiciels applicatifs", "parent": "J"} -{"index": {"_id": "59.11A"}} -{"name": "Production de films et de programmes pour la télévision", "parent": "J"} -{"index": {"_id": "59.11B"}} -{"name": "Production de films institutionnels et publicitaires", "parent": "J"} -{"index": {"_id": "59.11C"}} -{"name": "Production de films pour le cinéma", "parent": "J"} -{"index": {"_id": "59.12Z"}} -{"name": "Post-production de films cinématographiques, de vidéo et de programmes de télévision", "parent": "J"} -{"index": {"_id": "59.13A"}} -{"name": "Distribution de films cinématographiques", "parent": "J"} -{"index": {"_id": "59.13B"}} -{"name": "Édition et distribution vidéo", "parent": "J"} -{"index": {"_id": "59.14Z"}} -{"name": "Projection de films cinématographiques", "parent": "J"} -{"index": {"_id": "59.20Z"}} -{"name": "Enregistrement sonore et édition musicale", "parent": "J"} -{"index": {"_id": "60.10Z"}} -{"name": "Édition et diffusion de programmes radio", "parent": "J"} -{"index": {"_id": "60.20A"}} -{"name": "Édition de chaînes généralistes", "parent": "J"} -{"index": {"_id": "60.20B"}} -{"name": "Édition de chaînes thématiques", "parent": "J"} -{"index": {"_id": "61.10Z"}} -{"name": "Télécommunications filaires", "parent": "J"} -{"index": {"_id": "61.20Z"}} -{"name": "Télécommunications sans fil", "parent": "J"} -{"index": {"_id": "61.30Z"}} -{"name": "Télécommunications par satellite", "parent": "J"} -{"index": {"_id": "61.90Z"}} -{"name": "Autres activités de télécommunication", "parent": "J"} -{"index": {"_id": "62.01Z"}} -{"name": "Programmation informatique", "parent": "J"} -{"index": {"_id": "62.02A"}} -{"name": "Conseil en systèmes et logiciels informatiques", "parent": "J"} -{"index": {"_id": "62.02B"}} -{"name": "Tierce maintenance de systèmes et d'applications informatiques", "parent": "J"} -{"index": {"_id": "62.03Z"}} -{"name": "Gestion d'installations informatiques", "parent": "J"} -{"index": {"_id": "62.09Z"}} -{"name": "Autres activités informatiques", "parent": "J"} -{"index": {"_id": "63.11Z"}} -{"name": "Traitement de données, hébergement et activités connexes", "parent": "J"} -{"index": {"_id": "63.12Z"}} -{"name": "Portails Internet", "parent": "J"} -{"index": {"_id": "63.91Z"}} -{"name": "Activités des agences de presse", "parent": "J"} -{"index": {"_id": "63.99Z"}} -{"name": "Autres services d'information n.c.a.", "parent": "J"} -{"index": {"_id": "K"}} -{"name": "Activités financières et d'assurance", "parent": null} -{"index": {"_id": "64.11Z"}} -{"name": "Activités de banque centrale", "parent": "K"} -{"index": {"_id": "64.19Z"}} -{"name": "Autres intermédiations monétaires", "parent": "K"} -{"index": {"_id": "64.20Z"}} -{"name": "Activités des sociétés holding", "parent": "K"} -{"index": {"_id": "64.30Z"}} -{"name": "Fonds de placement et entités financières similaires", "parent": "K"} -{"index": {"_id": "64.91Z"}} -{"name": "Crédit-bail", "parent": "K"} -{"index": {"_id": "64.92Z"}} -{"name": "Autre distribution de crédit", "parent": "K"} -{"index": {"_id": "64.99Z"}} -{"name": "Autres activités des services financiers, hors assurance et caisses de retraite, n.c.a.", "parent": "K"} -{"index": {"_id": "65.11Z"}} -{"name": "Assurance vie", "parent": "K"} -{"index": {"_id": "65.12Z"}} -{"name": "Autres assurances", "parent": "K"} -{"index": {"_id": "65.20Z"}} -{"name": "Réassurance", "parent": "K"} -{"index": {"_id": "65.30Z"}} -{"name": "Caisses de retraite", "parent": "K"} -{"index": {"_id": "66.11Z"}} -{"name": "Administration de marchés financiers", "parent": "K"} -{"index": {"_id": "66.12Z"}} -{"name": "Courtage de valeurs mobilières et de marchandises", "parent": "K"} -{"index": {"_id": "66.19A"}} -{"name": "Supports juridiques de gestion de patrimoine mobilier", "parent": "K"} -{"index": {"_id": "66.19B"}} -{"name": "Autres activités auxiliaires de services financiers, hors assurance et caisses de retraite, n.c.a.", "parent": "K"} -{"index": {"_id": "66.21Z"}} -{"name": "Évaluation des risques et dommages", "parent": "K"} -{"index": {"_id": "66.22Z"}} -{"name": "Activités des agents et courtiers d'assurances", "parent": "K"} -{"index": {"_id": "66.29Z"}} -{"name": "Autres activités auxiliaires d'assurance et de caisses de retraite", "parent": "K"} -{"index": {"_id": "66.30Z"}} -{"name": "Gestion de fonds", "parent": "K"} -{"index": {"_id": "L"}} -{"name": "Activités immobilières", "parent": null} -{"index": {"_id": "68.10Z"}} -{"name": "Activités des marchands de biens immobiliers", "parent": "L"} -{"index": {"_id": "68.20A"}} -{"name": "Location de logements", "parent": "L"} -{"index": {"_id": "68.20B"}} -{"name": "Location de terrains et d'autres biens immobiliers", "parent": "L"} -{"index": {"_id": "68.31Z"}} -{"name": "Agences immobilières", "parent": "L"} -{"index": {"_id": "68.32A"}} -{"name": "Administration d'immeubles et autres biens immobiliers", "parent": "L"} -{"index": {"_id": "68.32B"}} -{"name": "Supports juridiques de gestion de patrimoine immobilier", "parent": "L"} -{"index": {"_id": "M"}} -{"name": "Activités spécialisées, scientifiques et techniques", "parent": null} -{"index": {"_id": "69.10Z"}} -{"name": "Activités juridiques", "parent": "M"} -{"index": {"_id": "69.20Z"}} -{"name": "Activités comptables", "parent": "M"} -{"index": {"_id": "70.10Z"}} -{"name": "Activités des sièges sociaux", "parent": "M"} -{"index": {"_id": "70.21Z"}} -{"name": "Conseil en relations publiques et communication", "parent": "M"} -{"index": {"_id": "70.22Z"}} -{"name": "Conseil pour les affaires et autres conseils de gestion", "parent": "M"} -{"index": {"_id": "71.11Z"}} -{"name": "Activités d'architecture", "parent": "M"} -{"index": {"_id": "71.12A"}} -{"name": "Activité des géomètres", "parent": "M"} -{"index": {"_id": "71.12B"}} -{"name": "Ingénierie, études techniques", "parent": "M"} -{"index": {"_id": "71.20A"}} -{"name": "Contrôle technique automobile", "parent": "M"} -{"index": {"_id": "71.20B"}} -{"name": "Analyses, essais et inspections techniques", "parent": "M"} -{"index": {"_id": "72.11Z"}} -{"name": "Recherche-développement en biotechnologie", "parent": "M"} -{"index": {"_id": "72.19Z"}} -{"name": "Recherche-développement en autres sciences physiques et naturelles", "parent": "M"} -{"index": {"_id": "72.20Z"}} -{"name": "Recherche-développement en sciences humaines et sociales", "parent": "M"} -{"index": {"_id": "73.11Z"}} -{"name": "Activités des agences de publicité", "parent": "M"} -{"index": {"_id": "73.12Z"}} -{"name": "Régie publicitaire de médias", "parent": "M"} -{"index": {"_id": "73.20Z"}} -{"name": "Études de marché et sondages", "parent": "M"} -{"index": {"_id": "74.10Z"}} -{"name": "Activités spécialisées de design", "parent": "M"} -{"index": {"_id": "74.20Z"}} -{"name": "Activités photographiques", "parent": "M"} -{"index": {"_id": "74.30Z"}} -{"name": "Traduction et interprétation", "parent": "M"} -{"index": {"_id": "74.90A"}} -{"name": "Activité des économistes de la construction", "parent": "M"} -{"index": {"_id": "74.90B"}} -{"name": "Activités spécialisées, scientifiques et techniques diverses", "parent": "M"} -{"index": {"_id": "N"}} -{"name": "Activités de services administratifs et de soutien", "parent": null} -{"index": {"_id": "75.00Z"}} -{"name": "Activités vétérinaires", "parent": "N"} -{"index": {"_id": "77.11A"}} -{"name": "Location de courte durée de voitures et de véhicules automobiles légers", "parent": "N"} -{"index": {"_id": "77.11B"}} -{"name": "Location de longue durée de voitures et de véhicules automobiles légers", "parent": "N"} -{"index": {"_id": "77.12Z"}} -{"name": "Location et location-bail de camions", "parent": "N"} -{"index": {"_id": "77.21Z"}} -{"name": "Location et location-bail d'articles de loisirs et de sport", "parent": "N"} -{"index": {"_id": "77.22Z"}} -{"name": "Location de vidéocassettes et disques vidéo", "parent": "N"} -{"index": {"_id": "77.29Z"}} -{"name": "Location et location-bail d'autres biens personnels et domestiques", "parent": "N"} -{"index": {"_id": "77.31Z"}} -{"name": "Location et location-bail de machines et équipements agricoles", "parent": "N"} -{"index": {"_id": "77.32Z"}} -{"name": "Location et location-bail de machines et équipements pour la construction", "parent": "N"} -{"index": {"_id": "77.33Z"}} -{"name": "Location et location-bail de machines de bureau et de matériel informatique", "parent": "N"} -{"index": {"_id": "77.34Z"}} -{"name": "Location et location-bail de matériels de transport par eau", "parent": "N"} -{"index": {"_id": "77.35Z"}} -{"name": "Location et location-bail de matériels de transport aérien", "parent": "N"} -{"index": {"_id": "77.39Z"}} -{"name": "Location et location-bail d'autres machines, équipements et biens matériels n.c.a.", "parent": "N"} -{"index": {"_id": "77.40Z"}} -{"name": "Location-bail de propriété intellectuelle et de produits similaires, à l'exception des œuvres soumises à copyright", "parent": "N"} -{"index": {"_id": "78.10Z"}} -{"name": "Activités des agences de placement de main-d'œuvre", "parent": "N"} -{"index": {"_id": "78.20Z"}} -{"name": "Activités des agences de travail temporaire", "parent": "N"} -{"index": {"_id": "78.30Z"}} -{"name": "Autre mise à disposition de ressources humaines", "parent": "N"} -{"index": {"_id": "79.11Z"}} -{"name": "Activités des agences de voyage", "parent": "N"} -{"index": {"_id": "79.12Z"}} -{"name": "Activités des voyagistes", "parent": "N"} -{"index": {"_id": "79.90Z"}} -{"name": "Autres services de réservation et activités connexes", "parent": "N"} -{"index": {"_id": "80.10Z"}} -{"name": "Activités de sécurité privée", "parent": "N"} -{"index": {"_id": "80.20Z"}} -{"name": "Activités liées aux systèmes de sécurité", "parent": "N"} -{"index": {"_id": "80.30Z"}} -{"name": "Activités d'enquête", "parent": "N"} -{"index": {"_id": "81.10Z"}} -{"name": "Activités combinées de soutien lié aux bâtiments", "parent": "N"} -{"index": {"_id": "81.21Z"}} -{"name": "Nettoyage courant des bâtiments", "parent": "N"} -{"index": {"_id": "81.22Z"}} -{"name": "Autres activités de nettoyage des bâtiments et nettoyage industriel", "parent": "N"} -{"index": {"_id": "81.29A"}} -{"name": "Désinfection, désinsectisation, dératisation", "parent": "N"} -{"index": {"_id": "81.29B"}} -{"name": "Autres activités de nettoyage n.c.a.", "parent": "N"} -{"index": {"_id": "81.30Z"}} -{"name": "Services d'aménagement paysager", "parent": "N"} -{"index": {"_id": "82.11Z"}} -{"name": "Services administratifs combinés de bureau", "parent": "N"} -{"index": {"_id": "82.19Z"}} -{"name": "Photocopie, préparation de documents et autres activités spécialisées de soutien de bureau", "parent": "N"} -{"index": {"_id": "82.20Z"}} -{"name": "Activités de centres d'appels", "parent": "N"} -{"index": {"_id": "82.30Z"}} -{"name": "Organisation de foires, salons professionnels et congrès", "parent": "N"} -{"index": {"_id": "82.91Z"}} -{"name": "Activités des agences de recouvrement de factures et des sociétés d'information financière sur la clientèle", "parent": "N"} -{"index": {"_id": "82.92Z"}} -{"name": "Activités de conditionnement", "parent": "N"} -{"index": {"_id": "82.99Z"}} -{"name": "Autres activités de soutien aux entreprises n.c.a.", "parent": "N"} -{"index": {"_id": "O"}} -{"name": "Administration publique", "parent": null} -{"index": {"_id": "84.11Z"}} -{"name": "Administration publique générale", "parent": "O"} -{"index": {"_id": "84.12Z"}} -{"name": "Administration publique (tutelle) de la santé, de la formation, de la culture et des services sociaux, autre que sécurité sociale", "parent": "O"} -{"index": {"_id": "84.13Z"}} -{"name": "Administration publique (tutelle) des activités économiques", "parent": "O"} -{"index": {"_id": "84.21Z"}} -{"name": "Affaires étrangères", "parent": "O"} -{"index": {"_id": "84.22Z"}} -{"name": "Défense", "parent": "O"} -{"index": {"_id": "84.23Z"}} -{"name": "Justice", "parent": "O"} -{"index": {"_id": "84.24Z"}} -{"name": "Activités d'ordre public et de sécurité", "parent": "O"} -{"index": {"_id": "84.25Z"}} -{"name": "Services du feu et de secours", "parent": "O"} -{"index": {"_id": "84.30A"}} -{"name": "Activités générales de sécurité sociale", "parent": "O"} -{"index": {"_id": "84.30B"}} -{"name": "Gestion des retraites complémentaires", "parent": "O"} -{"index": {"_id": "84.30C"}} -{"name": "Distribution sociale de revenus", "parent": "O"} -{"index": {"_id": "P"}} -{"name": "Enseignement", "parent": null} -{"index": {"_id": "85.10Z"}} -{"name": "Enseignement pré-primaire", "parent": "P"} -{"index": {"_id": "85.20Z"}} -{"name": "Enseignement primaire", "parent": "P"} -{"index": {"_id": "85.31Z"}} -{"name": "Enseignement secondaire général", "parent": "P"} -{"index": {"_id": "85.32Z"}} -{"name": "Enseignement secondaire technique ou professionnel", "parent": "P"} -{"index": {"_id": "85.41Z"}} -{"name": "Enseignement post-secondaire non supérieur", "parent": "P"} -{"index": {"_id": "85.42Z"}} -{"name": "Enseignement supérieur", "parent": "P"} -{"index": {"_id": "85.51Z"}} -{"name": "Enseignement de disciplines sportives et d'activités de loisirs", "parent": "P"} -{"index": {"_id": "85.52Z"}} -{"name": "Enseignement culturel", "parent": "P"} -{"index": {"_id": "85.53Z"}} -{"name": "Enseignement de la conduite", "parent": "P"} -{"index": {"_id": "85.59A"}} -{"name": "Formation continue d'adultes", "parent": "P"} -{"index": {"_id": "85.59B"}} -{"name": "Autres enseignements", "parent": "P"} -{"index": {"_id": "85.60Z"}} -{"name": "Activités de soutien à l'enseignement", "parent": "P"} -{"index": {"_id": "Q"}} -{"name": "Santé humaine et action sociale", "parent": null} -{"index": {"_id": "86.10Z"}} -{"name": "Activités hospitalières", "parent": "Q"} -{"index": {"_id": "86.21Z"}} -{"name": "Activité des médecins généralistes", "parent": "Q"} -{"index": {"_id": "86.22A"}} -{"name": "Activités de radiodiagnostic et de radiothérapie", "parent": "Q"} -{"index": {"_id": "86.22B"}} -{"name": "Activités chirurgicales", "parent": "Q"} -{"index": {"_id": "86.22C"}} -{"name": "Autres activités des médecins spécialistes", "parent": "Q"} -{"index": {"_id": "86.23Z"}} -{"name": "Pratique dentaire", "parent": "Q"} -{"index": {"_id": "86.90A"}} -{"name": "Ambulances", "parent": "Q"} -{"index": {"_id": "86.90B"}} -{"name": "Laboratoires d'analyses médicales", "parent": "Q"} -{"index": {"_id": "86.90C"}} -{"name": "Centres de collecte et banques d'organes", "parent": "Q"} -{"index": {"_id": "86.90D"}} -{"name": "Activités des infirmiers et des sages-femmes", "parent": "Q"} -{"index": {"_id": "86.90E"}} -{"name": "Activités des professionnels de la rééducation, de l'appareillage et des pédicures-podologues", "parent": "Q"} -{"index": {"_id": "86.90F"}} -{"name": "Activités de santé humaine non classées ailleurs", "parent": "Q"} -{"index": {"_id": "87.10A"}} -{"name": "Hébergement médicalisé pour personnes âgées", "parent": "Q"} -{"index": {"_id": "87.10B"}} -{"name": "Hébergement médicalisé pour enfants handicapés", "parent": "Q"} -{"index": {"_id": "87.10C"}} -{"name": "Hébergement médicalisé pour adultes handicapés et autre hébergement médicalisé", "parent": "Q"} -{"index": {"_id": "87.20A"}} -{"name": "Hébergement social pour handicapés mentaux et malades mentaux", "parent": "Q"} -{"index": {"_id": "87.20B"}} -{"name": "Hébergement social pour toxicomanes", "parent": "Q"} -{"index": {"_id": "87.30A"}} -{"name": "Hébergement social pour personnes âgées", "parent": "Q"} -{"index": {"_id": "87.30B"}} -{"name": "Hébergement social pour handicapés physiques", "parent": "Q"} -{"index": {"_id": "87.90A"}} -{"name": "Hébergement social pour enfants en difficultés", "parent": "Q"} -{"index": {"_id": "87.90B"}} -{"name": "Hébergement social pour adultes et familles en difficultés et autre hébergement social", "parent": "Q"} -{"index": {"_id": "88.10A"}} -{"name": "Aide à domicile", "parent": "Q"} -{"index": {"_id": "88.10B"}} -{"name": "Accueil ou accompagnement sans hébergement d'adultes handicapés ou de personnes âgées", "parent": "Q"} -{"index": {"_id": "88.10C"}} -{"name": "Aide par le travail", "parent": "Q"} -{"index": {"_id": "88.91A"}} -{"name": "Accueil de jeunes enfants", "parent": "Q"} -{"index": {"_id": "88.91B"}} -{"name": "Accueil ou accompagnement sans hébergement d'enfants handicapés", "parent": "Q"} -{"index": {"_id": "88.99A"}} -{"name": "Autre accueil ou accompagnement sans hébergement d'enfants et d'adolescents", "parent": "Q"} -{"index": {"_id": "88.99B"}} -{"name": "Action sociale sans hébergement n.c.a.", "parent": "Q"} -{"index": {"_id": "R"}} -{"name": "Arts, spectacles et activités récréatives", "parent": null} -{"index": {"_id": "90.01Z"}} -{"name": "Arts du spectacle vivant", "parent": "R"} -{"index": {"_id": "90.02Z"}} -{"name": "Activités de soutien au spectacle vivant", "parent": "R"} -{"index": {"_id": "90.03A"}} -{"name": "Création artistique relevant des arts plastiques", "parent": "R"} -{"index": {"_id": "90.03B"}} -{"name": "Autre création artistique", "parent": "R"} -{"index": {"_id": "90.04Z"}} -{"name": "Gestion de salles de spectacles", "parent": "R"} -{"index": {"_id": "91.01Z"}} -{"name": "Gestion des bibliothèques et des archives", "parent": "R"} -{"index": {"_id": "91.02Z"}} -{"name": "Gestion des musées", "parent": "R"} -{"index": {"_id": "91.03Z"}} -{"name": "Gestion des sites et monuments historiques et des attractions touristiques similaires", "parent": "R"} -{"index": {"_id": "91.04Z"}} -{"name": "Gestion des jardins botaniques et zoologiques et des réserves naturelles", "parent": "R"} -{"index": {"_id": "92.00Z"}} -{"name": "Organisation de jeux de hasard et d'argent", "parent": "R"} -{"index": {"_id": "93.11Z"}} -{"name": "Gestion d'installations sportives", "parent": "R"} -{"index": {"_id": "93.12Z"}} -{"name": "Activités de clubs de sports", "parent": "R"} -{"index": {"_id": "93.13Z"}} -{"name": "Activités des centres de culture physique", "parent": "R"} -{"index": {"_id": "93.19Z"}} -{"name": "Autres activités liées au sport", "parent": "R"} -{"index": {"_id": "93.21Z"}} -{"name": "Activités des parcs d'attractions et parcs à thèmes", "parent": "R"} -{"index": {"_id": "93.29Z"}} -{"name": "Autres activités récréatives et de loisirs", "parent": "R"} -{"index": {"_id": "S"}} -{"name": "Autres activités de services", "parent": null} -{"index": {"_id": "94.11Z"}} -{"name": "Activités des organisations patronales et consulaires", "parent": "S"} -{"index": {"_id": "94.12Z"}} -{"name": "Activités des organisations professionnelles", "parent": "S"} -{"index": {"_id": "94.20Z"}} -{"name": "Activités des syndicats de salariés", "parent": "S"} -{"index": {"_id": "94.91Z"}} -{"name": "Activités des organisations religieuses", "parent": "S"} -{"index": {"_id": "94.92Z"}} -{"name": "Activités des organisations politiques", "parent": "S"} -{"index": {"_id": "94.99Z"}} -{"name": "Autres organisations fonctionnant par adhésion volontaire", "parent": "S"} -{"index": {"_id": "95.11Z"}} -{"name": "Réparation d'ordinateurs et d'équipements périphériques", "parent": "S"} -{"index": {"_id": "95.12Z"}} -{"name": "Réparation d'équipements de communication", "parent": "S"} -{"index": {"_id": "95.21Z"}} -{"name": "Réparation de produits électroniques grand public", "parent": "S"} -{"index": {"_id": "95.22Z"}} -{"name": "Réparation d'appareils électroménagers et d'équipements pour la maison et le jardin", "parent": "S"} -{"index": {"_id": "95.23Z"}} -{"name": "Réparation de chaussures et d'articles en cuir", "parent": "S"} -{"index": {"_id": "95.24Z"}} -{"name": "Réparation de meubles et d'équipements du foyer", "parent": "S"} -{"index": {"_id": "95.25Z"}} -{"name": "Réparation d'articles d'horlogerie et de bijouterie", "parent": "S"} -{"index": {"_id": "95.29Z"}} -{"name": "Réparation d'autres biens personnels et domestiques", "parent": "S"} -{"index": {"_id": "96.01A"}} -{"name": "Blanchisserie-teinturerie de gros", "parent": "S"} -{"index": {"_id": "96.01B"}} -{"name": "Blanchisserie-teinturerie de détail", "parent": "S"} -{"index": {"_id": "96.02A"}} -{"name": "Coiffure", "parent": "S"} -{"index": {"_id": "96.02B"}} -{"name": "Soins de beauté", "parent": "S"} -{"index": {"_id": "96.03Z"}} -{"name": "Services funéraires", "parent": "S"} -{"index": {"_id": "96.04Z"}} -{"name": "Entretien corporel", "parent": "S"} -{"index": {"_id": "96.09Z"}} -{"name": "Autres services personnels n.c.a.", "parent": "S"} -{"index": {"_id": "T"}} -{"name": "Activités des ménages en tant qu'employeurs ; activités indifférenciées des ménages en tant que producteurs de biens et services pour usage propre", "parent": null} -{"index": {"_id": "97.00Z"}} -{"name": "Activités des ménages en tant qu'employeurs de personnel domestique", "parent": "T"} -{"index": {"_id": "98.10Z"}} -{"name": "Activités indifférenciées des ménages en tant que producteurs de biens pour usage propre", "parent": "T"} -{"index": {"_id": "98.20Z"}} -{"name": "Activités indifférenciées des ménages en tant que producteurs de services pour usage propre", "parent": "T"} -{"index": {"_id": "U"}} -{"name": "Activités extra-territoriales", "parent": null} -{"index": {"_id": "99.00Z"}} -{"name": "Activités des organisations et organismes extraterritoriaux", "parent": "U"} diff --git a/duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/TestResource.java b/duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/TestResource.java deleted file mode 100644 index 2b27a3e5..00000000 --- a/duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/TestResource.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.duniter.elasticsearch; - -/* - * #%L - * UCoin Java Client :: Core API - * %% - * Copyright (C) 2014 - 2015 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - - -import com.google.common.collect.Lists; -import org.duniter.core.client.config.ConfigurationOption; -import org.duniter.core.client.service.ServiceLocator; -import org.apache.commons.io.FileUtils; -import org.junit.runner.Description; -import org.nuiton.i18n.I18n; -import org.nuiton.i18n.init.DefaultI18nInitializer; -import org.nuiton.i18n.init.UserI18nInitializer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Locale; - -public class TestResource extends org.duniter.core.test.TestResource { - - private static final Logger log = LoggerFactory.getLogger(TestResource.class); - - public static TestResource create() { - return new TestResource(null); - } - - public static TestResource create(String configName) { - return new TestResource(configName); - } - - private TestFixtures fixtures = new TestFixtures(); - - protected TestResource(String configName) { - super(configName); - } - - public TestFixtures getFixtures() { - return fixtures; - } - - protected void before(Description description) throws Throwable { - super.before(description); - - // Initialize configuration - initConfiguration(getConfigFileName()); - - // Init i18n - initI18n(); - - // Initialize service locator - ServiceLocator.instance().init(); - } - - /** - * Return configuration files prefix (i.e. 'allegro-test') - * Could be override by external project - * - * @return the prefix to use to retrieve configuration files - */ - protected String getConfigFilesPrefix() { - return "duniter4j-elasticsearch-test"; - } - - protected String getI18nBundleName() { - return "duniter4j-elasticsearch-i18n"; - } - - /* -- -- */ - - /** - * Convenience methods that could be override to initialize other configuration - * - * @param configFilename - * @param configArgs - */ - protected void initConfiguration(String configFilename) { - String[] configArgs = getConfigArgs(); - //PluginSettings config = new PluginSettings(configFilename, configArgs); - //PluginSettings.setInstance(config); - } - - protected void initI18n() throws IOException { - /*PluginSettings config ;//= PluginSettings.instance(); - - // --------------------------------------------------------------------// - // init i18n - // --------------------------------------------------------------------// - File i18nDirectory = new File(config.getDataDirectory(), "i18n"); - if (i18nDirectory.exists()) { - // clean i18n cache - FileUtils.cleanDirectory(i18nDirectory); - } - - FileUtils.forceMkdir(i18nDirectory); - - if (log.isDebugEnabled()) { - log.debug("I18N directory: " + i18nDirectory); - } - - Locale i18nLocale = config.getI18nLocale(); - - if (log.isInfoEnabled()) { - log.info(String.format("Starts i18n with locale [%s] at [%s]", - i18nLocale, i18nDirectory)); - } - I18n.init(new UserI18nInitializer( - i18nDirectory, new DefaultI18nInitializer(getI18nBundleName())), - i18nLocale);*/ - } - - protected String[] getConfigArgs() { - List<String> configArgs = Lists.newArrayList(); - configArgs.addAll(Lists.newArrayList( - "--option", ConfigurationOption.BASEDIR.getKey(), getResourceDirectory().getAbsolutePath())); - return configArgs.toArray(new String[configArgs.size()]); - } - -} diff --git a/duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/service/RegistryRecordIndexerServiceTest.java b/duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/service/RegistryRecordIndexerServiceTest.java deleted file mode 100644 index 4987281d..00000000 --- a/duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/service/RegistryRecordIndexerServiceTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.duniter.elasticsearch.service; - -/* - * #%L - * UCoin Java Client :: ElasticSearch Indexer - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.elasticsearch.TestResource; -import org.duniter.elasticsearch.gchange.service.RegistryService; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Created by Benoit on 06/05/2015. - */ -@Ignore -public class RegistryRecordIndexerServiceTest { - private static final Logger log = LoggerFactory.getLogger(RegistryRecordIndexerServiceTest.class); - - @ClassRule - public static final TestResource resource = TestResource.create(); - - private RegistryService service; - - @Before - public void setUp() throws Exception { - // FIXME use google guice ? - //service = ServiceLocator.instance().getRegistryRecordIndexerService(); - } - - @Test - public void insertTestData() { - //service.insertRecordFromBulkFile(new File("src/test/resources/registry-test-records.json")); - } - -} diff --git a/duniter4j-es-gchange/src/test/resources/META-INF/services/org.duniter.core.beans.Bean b/duniter4j-es-gchange/src/test/resources/META-INF/services/org.duniter.core.beans.Bean deleted file mode 100644 index 1d327a74..00000000 --- a/duniter4j-es-gchange/src/test/resources/META-INF/services/org.duniter.core.beans.Bean +++ /dev/null @@ -1,14 +0,0 @@ -org.duniter.core.client.service.bma.BlockchainRemoteServiceImpl -org.duniter.core.client.service.bma.NetworkRemoteServiceImpl -org.duniter.core.client.service.bma.WotRemoteServiceImpl -org.duniter.core.client.service.bma.TransactionRemoteServiceImpl -org.duniter.core.service.Ed25519CryptoServiceImpl -org.duniter.core.service.MailServiceImpl -org.duniter.core.client.service.HttpServiceImpl -org.duniter.core.client.service.DataContext -org.duniter.core.client.service.local.PeerServiceImpl -org.duniter.core.client.service.local.CurrencyServiceImpl -org.duniter.core.client.dao.mem.MemoryCurrencyDaoImpl -org.duniter.core.client.dao.mem.MemoryPeerDaoImpl -org.duniter.elasticsearch.service.ElasticSearchService -org.duniter.elasticsearch.service.registry.CurrencyRegistryService \ No newline at end of file diff --git a/duniter4j-es-gchange/src/test/resources/duniter4j-elasticsearch-localhost-node.properties b/duniter4j-es-gchange/src/test/resources/duniter4j-elasticsearch-localhost-node.properties deleted file mode 100644 index 38d7a5d9..00000000 --- a/duniter4j-es-gchange/src/test/resources/duniter4j-elasticsearch-localhost-node.properties +++ /dev/null @@ -1,12 +0,0 @@ -duniter4j.node.host=metab.ucoin.fr -duniter4j.node.port=9201 - -duniter4j.elasticsearch.embedded.enable=false -duniter4j.elasticsearch.local=fals -duniter4j.elasticsearch.http.enable=false -duniter4j.elasticsearch.cluster.name=duniter4j-elacticsearch-test - -#duniter4j.elasticsearch.cluster.name=duniter4j-elacticsearch - -duniter4j.elasticsearch.host=localhost -duniter4j.elasticsearch.port=9300 diff --git a/duniter4j-es-gchange/src/test/resources/duniter4j-elasticsearch-test.properties b/duniter4j-es-gchange/src/test/resources/duniter4j-elasticsearch-test.properties deleted file mode 100644 index 27e326f1..00000000 --- a/duniter4j-es-gchange/src/test/resources/duniter4j-elasticsearch-test.properties +++ /dev/null @@ -1,16 +0,0 @@ -duniter4j.node.host=metab.ucoin.fr -duniter4j.node.port=9201 - -duniter4j.basedir=target/es-home - -#duniter4j.elasticsearch.data -#duniter4j.elasticsearch.embedded.enable=true -duniter4j.elasticsearch.local=false -duniter4j.elasticsearch.http.enable=true -duniter4j.elasticsearch.cluster.name=duniter4j-elasticsearch - -#duniter4j.elasticsearch.cluster.name=duniter4j-elacticsearch - -duniter4j.elasticsearch.embedded.enable=false -duniter4j.elasticsearch.host=192.168.0.5 -duniter4j.elasticsearch.port=9300 diff --git a/duniter4j-es-gchange/src/test/resources/registry-test-records.json b/duniter4j-es-gchange/src/test/resources/registry-test-records.json deleted file mode 100644 index c9c11c01..00000000 --- a/duniter4j-es-gchange/src/test/resources/registry-test-records.json +++ /dev/null @@ -1,23 +0,0 @@ -/* - * #%L - * Duniter4j :: ElasticSearch Plugin - * %% - * Copyright (C) 2014 - 2016 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ -{"index": {"_id": "AVOt3cmVo7-63byx1Jow"}} -{"title": "Benoit Lavenier (kimamila)", "description": "Pasionné de plein de trucs...", "category": "particulier", "location":"Martigné-sur-Mayenne", "pictures": [{"src": "data:image/jpeg;base64,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"}], "issuer": "G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU", "hash": "7zPfFwyXGZKYMmLTzVynFGVEwLDfj48a5E3EA2RWtifq", "signature": "CP4p0+Nby/Fs7exp/mlLnOAu8iMJwyLRW6UHkZXZX8q8WbqxHYBRo2uzpcFAT0zEYSig7j3HqYdeoA3MpU1BCQ=="} diff --git a/duniter4j-es-gchange/pom.xml b/duniter4j-es-subscription/pom.xml similarity index 68% rename from duniter4j-es-gchange/pom.xml rename to duniter4j-es-subscription/pom.xml index ab8ce385..219fb1e6 100644 --- a/duniter4j-es-gchange/pom.xml +++ b/duniter4j-es-subscription/pom.xml @@ -7,14 +7,14 @@ <version>0.9.2-SNAPSHOT</version> </parent> - <artifactId>duniter4j-es-gchange</artifactId> + <artifactId>duniter4j-es-subscription</artifactId> <packaging>jar</packaging> - <name>Duniter4j :: ElasticSearch GChange plugin</name> + <name>Duniter4j :: ElasticSearch Subscription plugin</name> <properties> <!-- i18n configuration --> - <i18n.bundleOutputName>duniter4j-es-gchange-i18n</i18n.bundleOutputName> + <i18n.bundleOutputName>duniter4j-es-subscription-i18n</i18n.bundleOutputName> <i18n.generateCsvFile>true</i18n.generateCsvFile> <i18n.bundleCsvFile> ${maven.gen.dir}/resources/META-INF/${i18n.bundleOutputName}.csv @@ -41,12 +41,65 @@ <scope>provided</scope> </dependency> + <dependency> + <groupId>org.antlr</groupId> + <artifactId>stringtemplate</artifactId> + </dependency> + <!-- Unit test --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> + + <!-- LOGGING DEPENDENCIES - SLF4J --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <optional>true</optional> + <scope>test</scope> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <optional>true</optional> + <scope>test</scope> + </dependency> + + <!-- JNA (need for OS shutdown hook) --> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna-platform</artifactId> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.elasticsearch.plugin</groupId> + <artifactId>mapper-attachments</artifactId> + <version>${elasticsearch.version}</version> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/duniter4j-es-gchange/src/license/THIRD-PARTY.properties b/duniter4j-es-subscription/src/license/THIRD-PARTY.properties similarity index 100% rename from duniter4j-es-gchange/src/license/THIRD-PARTY.properties rename to duniter4j-es-subscription/src/license/THIRD-PARTY.properties diff --git a/duniter4j-es-gchange/src/main/assembly/plugin.xml b/duniter4j-es-subscription/src/main/assembly/plugin.xml similarity index 100% rename from duniter4j-es-gchange/src/main/assembly/plugin.xml rename to duniter4j-es-subscription/src/main/assembly/plugin.xml diff --git a/duniter4j-es-gchange/src/main/filtered-resources/log4j.properties b/duniter4j-es-subscription/src/main/filtered-resources/log4j.properties similarity index 100% rename from duniter4j-es-gchange/src/main/filtered-resources/log4j.properties rename to duniter4j-es-subscription/src/main/filtered-resources/log4j.properties diff --git a/duniter4j-es-gchange/src/main/filtered-resources/plugin-descriptor.properties b/duniter4j-es-subscription/src/main/filtered-resources/plugin-descriptor.properties similarity index 73% rename from duniter4j-es-gchange/src/main/filtered-resources/plugin-descriptor.properties rename to duniter4j-es-subscription/src/main/filtered-resources/plugin-descriptor.properties index 9e05cd42..78fb7eb1 100644 --- a/duniter4j-es-gchange/src/main/filtered-resources/plugin-descriptor.properties +++ b/duniter4j-es-subscription/src/main/filtered-resources/plugin-descriptor.properties @@ -3,7 +3,7 @@ description=Plugin for Gchange API version=${project.version} site=false jvm=true -classname=org.duniter.elasticsearch.gchange.Plugin +classname=org.duniter.elasticsearch.subscription.Plugin java.version=1.7 elasticsearch.version=2.3.3 isolated=false diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/Plugin.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/Plugin.java similarity index 87% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/Plugin.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/Plugin.java index f4db9959..48b5b967 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/Plugin.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/Plugin.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange; +package org.duniter.elasticsearch.subscription; /* * #%L @@ -23,9 +23,9 @@ package org.duniter.elasticsearch.gchange; */ import com.google.common.collect.Lists; -import org.duniter.elasticsearch.gchange.dao.DaoModule; -import org.duniter.elasticsearch.gchange.rest.RestModule; -import org.duniter.elasticsearch.gchange.service.ServiceModule; +import org.duniter.elasticsearch.subscription.dao.DaoModule; +import org.duniter.elasticsearch.subscription.rest.RestModule; +import org.duniter.elasticsearch.subscription.service.ServiceModule; import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Module; @@ -42,12 +42,12 @@ public class Plugin extends org.elasticsearch.plugins.Plugin { private boolean enable; @Inject public Plugin(Settings settings) { - this.enable = settings.getAsBoolean("gchange.enabled", true); + this.enable = settings.getAsBoolean("subscription.enabled", true); } @Override public String name() { - return "gchange"; + return "subscription"; } @Override diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/PluginInit.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginInit.java similarity index 73% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/PluginInit.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginInit.java index 5b781ea3..6dc6e5ad 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/PluginInit.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginInit.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange; +package org.duniter.elasticsearch.subscription; /* * #%L @@ -22,11 +22,10 @@ package org.duniter.elasticsearch.gchange; * #L% */ -import org.duniter.elasticsearch.gchange.service.MarketService; -import org.duniter.elasticsearch.gchange.service.RegistryService; -import org.duniter.elasticsearch.gchange.service.SynchroService; +import org.duniter.elasticsearch.subscription.dao.SubscriptionIndexDao; +import org.duniter.elasticsearch.subscription.service.SubscriptionService; +import org.duniter.elasticsearch.subscription.service.SynchroService; import org.duniter.elasticsearch.threadpool.ThreadPool; -import org.duniter.elasticsearch.user.PluginSettings; import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.inject.Inject; @@ -43,7 +42,7 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { private final PluginSettings pluginSettings; private final ThreadPool threadPool; private final Injector injector; - private final static ESLogger logger = Loggers.getLogger("gchange"); + private final static ESLogger logger = Loggers.getLogger("duniter.subscription"); @Inject public PluginInit(Settings settings, PluginSettings pluginSettings, ThreadPool threadPool, final Injector injector) { @@ -59,7 +58,7 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { createIndices(); // Waiting cluster back to GREEN or YELLOW state, before synchronize - threadPool.scheduleOnClusterHealthStatus(() -> synchronize(), + threadPool.scheduleOnClusterHealthStatus(this::synchronize, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); }, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); } @@ -80,28 +79,24 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { if (reloadIndices) { if (logger.isInfoEnabled()) { - logger.info("Reloading all Gchange indices..."); + logger.info("Reloading all subscription indices..."); } - injector.getInstance(RegistryService.class) - .deleteIndex() - .createIndexIfNotExists(); - injector.getInstance(MarketService.class) + injector.getInstance(SubscriptionIndexDao.class) .deleteIndex() .createIndexIfNotExists(); if (logger.isInfoEnabled()) { - logger.info("Reloading all Gchange indices... [OK]"); + logger.info("Reloading all subscription indices... [OK]"); } } else { if (logger.isInfoEnabled()) { - logger.info("Checking Gchange indices..."); + logger.info("Checking subscription indices..."); } - injector.getInstance(RegistryService.class).createIndexIfNotExists(); - injector.getInstance(MarketService.class).createIndexIfNotExists(); + injector.getInstance(SubscriptionIndexDao.class).createIndexIfNotExists(); if (logger.isInfoEnabled()) { - logger.info("Checking Gchange indices... [OK]"); + logger.info("Checking subscription indices... [OK]"); } } } @@ -112,5 +107,11 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { // Synchronize injector.getInstance(SynchroService.class).synchronize(); } + + // Start subscription services + if (pluginSettings.enableSubscription()) { + + injector.getInstance(SubscriptionService.class).startScheduling(); + } } } diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/PluginSettings.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginSettings.java similarity index 75% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/PluginSettings.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginSettings.java index 826e938d..4151475a 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/PluginSettings.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginSettings.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange; +package org.duniter.elasticsearch.subscription; /* * #%L @@ -23,31 +23,10 @@ package org.duniter.elasticsearch.gchange; */ -import com.google.common.collect.ImmutableSet; -import org.apache.commons.io.FileUtils; -import org.duniter.core.client.config.Configuration; -import org.duniter.core.client.config.ConfigurationOption; -import org.duniter.core.client.config.ConfigurationProvider; -import org.duniter.core.client.model.local.Peer; -import org.duniter.core.exception.TechnicalException; -import org.duniter.core.util.StringUtils; +import org.duniter.core.util.crypto.KeyPair; import org.elasticsearch.common.component.*; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.nuiton.config.ApplicationConfig; -import org.nuiton.config.ApplicationConfigHelper; -import org.nuiton.config.ApplicationConfigProvider; -import org.nuiton.config.ArgumentsParserException; -import org.nuiton.i18n.I18n; -import org.nuiton.i18n.init.DefaultI18nInitializer; -import org.nuiton.i18n.init.UserI18nInitializer; - -import java.io.File; -import java.io.IOException; -import java.util.Locale; -import java.util.Set; - -import static org.nuiton.i18n.I18n.t; +import org.elasticsearch.common.inject.Singleton; /** * Access to configuration options @@ -58,6 +37,12 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { private org.duniter.elasticsearch.user.PluginSettings delegate; + private static PluginSettings instance; + + public static final PluginSettings instance() { + return instance; + } + @Inject public PluginSettings(org.elasticsearch.common.settings.Settings settings, org.duniter.elasticsearch.user.PluginSettings delegate) { @@ -67,6 +52,7 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { // Add i18n bundle name delegate.addI18nBundleName(getI18nBundleName()); + instance = this; } @Override @@ -88,6 +74,23 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { return delegate; } + + public boolean enableSubscription() { + return settings.getAsBoolean("duniter.subscription.enable", Boolean.TRUE); + } + + public String getCesiumUrl() { + return this.settings.get("duniter.subscription.email.cesium.url", "https://g1.duniter.fr"); + } + + /** + * Time interval (millisecond) to send email ? (default: 3600000 = 1h) + * @return + */ + public long getExecuteEmailSubscriptionsInterval() { + return settings.getAsLong("duniter.subscription.email.interval", 36000000l) /*1hour*/; + } + /* -- delegate methods -- */ public boolean reloadIndices() { @@ -170,9 +173,21 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { return delegate.getDefaultStringAnalyzer(); } + public KeyPair getNodeKeypair() { + return delegate.getNodeKeypair(); + } + + public boolean isRandomNodeKeypair() { + return delegate.isRandomNodeKeypair(); + } + + public String getNodePubkey() { + return delegate.getNodePubkey(); + } + /* -- protected methods -- */ protected String getI18nBundleName() { - return "duniter4j-es-gchange-i18n"; + return "duniter4j-es-subscription-i18n"; } } diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/AbstractSubscriptionIndexTypeDao.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/AbstractSubscriptionIndexTypeDao.java new file mode 100644 index 00000000..693b04d9 --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/AbstractSubscriptionIndexTypeDao.java @@ -0,0 +1,63 @@ +package org.duniter.elasticsearch.subscription.dao; + +/* + * #%L + * UCoin Java Client :: Core API + * %% + * Copyright (C) 2014 - 2015 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.duniter.core.client.model.elasticsearch.Record; +import org.duniter.core.client.model.local.LocalEntity; +import org.duniter.core.exception.TechnicalException; +import org.duniter.core.util.ObjectUtils; +import org.duniter.elasticsearch.subscription.PluginSettings; +import org.elasticsearch.search.SearchHit; + +import java.io.IOException; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Created by Benoit on 30/03/2015. + */ +public abstract class AbstractSubscriptionIndexTypeDao<T extends AbstractSubscriptionIndexTypeDao> extends org.duniter.elasticsearch.dao.AbstractIndexTypeDao<T> implements SubscriptionIndexTypeDao<T> { + + protected PluginSettings pluginSettings; + + public AbstractSubscriptionIndexTypeDao(String index, String type, PluginSettings pluginSettings) { + super(index, type); + this.pluginSettings = pluginSettings; + } + + @Override + protected void createIndex() throws JsonProcessingException { + throw new TechnicalException("not implemented"); + } + + @Override + public void checkSameDocumentIssuer(String id, String expectedIssuer) { + String issuer = getMandatoryFieldsById(id, Record.PROPERTY_ISSUER).get(Record.PROPERTY_ISSUER).toString(); + if (!ObjectUtils.equals(expectedIssuer, issuer)) { + throw new TechnicalException("Not same issuer"); + } + } + +} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCategoryAction.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/DaoModule.java similarity index 53% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCategoryAction.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/DaoModule.java index ff58d64b..7851afbe 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCategoryAction.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/DaoModule.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange.rest.registry; +package org.duniter.elasticsearch.subscription.dao; /* * #%L @@ -22,18 +22,20 @@ package org.duniter.elasticsearch.gchange.rest.registry; * #L% */ -import org.duniter.elasticsearch.gchange.dao.registry.RegistryIndexDao; -import org.duniter.elasticsearch.gchange.service.RegistryService; -import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.rest.RestRequest; +import org.duniter.elasticsearch.subscription.dao.record.SubscriptionRecordDao; +import org.duniter.elasticsearch.subscription.dao.record.SubscriptionRecordDaoImpl; +import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.inject.Module; -public class RestRegistryCategoryAction { +public class DaoModule extends AbstractModule implements Module { - @Inject - public RestRegistryCategoryAction(RestSecurityController securityController) { - // Add security rule for category - securityController.allowIndexType(RestRequest.Method.GET, RegistryIndexDao.INDEX, RegistryIndexDao.CATEGORY_TYPE); + @Override protected void configure() { + + // Subscription index + bind(SubscriptionIndexDao.class).to(SubscriptionIndexDaoImpl.class).asEagerSingleton(); + + // Subscription types + bind(SubscriptionRecordDao.class).to(SubscriptionRecordDaoImpl.class).asEagerSingleton(); } } \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexDao.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexDao.java new file mode 100644 index 00000000..f252212c --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexDao.java @@ -0,0 +1,14 @@ +package org.duniter.elasticsearch.subscription.dao; + +import org.duniter.elasticsearch.dao.IndexDao; +import org.duniter.elasticsearch.dao.IndexTypeDao; + +/** + * Created by blavenie on 03/04/17. + */ +public interface SubscriptionIndexDao extends IndexDao<SubscriptionIndexDao> { + String INDEX = "subscription"; + String CATEGORY_TYPE = "category"; + + SubscriptionIndexDao register(IndexTypeDao<?> indexTypeDao); +} diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexDaoImpl.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexDaoImpl.java new file mode 100644 index 00000000..a3494113 --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexDaoImpl.java @@ -0,0 +1,100 @@ +package org.duniter.elasticsearch.subscription.dao; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.duniter.core.exception.TechnicalException; +import org.duniter.elasticsearch.dao.AbstractIndexDao; +import org.duniter.elasticsearch.dao.IndexTypeDao; +import org.duniter.elasticsearch.dao.handler.AddSequenceAttributeHandler; +import org.duniter.elasticsearch.subscription.PluginSettings; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by blavenie on 03/04/17. + */ +public class SubscriptionIndexDaoImpl extends AbstractIndexDao<SubscriptionIndexDao> implements SubscriptionIndexDao { + + + private static final String CATEGORIES_BULK_CLASSPATH_FILE = "subscription-categories-bulk-insert.json"; + + private PluginSettings pluginSettings; + private List<IndexTypeDao<?>> indexTypeDaos = new ArrayList<>(); + + @Inject + public SubscriptionIndexDaoImpl(PluginSettings pluginSettings) { + super(SubscriptionIndexDao.INDEX); + + this.pluginSettings = pluginSettings; + } + + public SubscriptionIndexDao register(IndexTypeDao<?> indexTypeDao) { + indexTypeDaos.add(indexTypeDao); + return this; + } + + @Override + protected void createIndex() throws JsonProcessingException { + logger.info(String.format("Creating index [%s]", INDEX)); + + CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(INDEX); + org.elasticsearch.common.settings.Settings indexSettings = org.elasticsearch.common.settings.Settings.settingsBuilder() + .put("number_of_shards", 3) + .put("number_of_replicas", 1) + //.put("analyzer", createDefaultAnalyzer()) + .build(); + createIndexRequestBuilder.setSettings(indexSettings); + indexTypeDaos.forEach(indexTypeDao -> createIndexRequestBuilder.addMapping(indexTypeDao.getType(), indexTypeDao.createTypeMapping())); + createIndexRequestBuilder.addMapping(CATEGORY_TYPE, createCategoryTypeMapping()); + createIndexRequestBuilder.execute().actionGet(); + + // Fill categories + fillCategories(); + } + + + + protected XContentBuilder createCategoryTypeMapping() { + try { + XContentBuilder mapping = XContentFactory.jsonBuilder().startObject() + .startObject(CATEGORY_TYPE) + .startObject("properties") + + // name + .startObject("name") + .field("type", "string") + .field("analyzer", pluginSettings.getDefaultStringAnalyzer()) + .endObject() + + // parent + .startObject("parent") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + + .endObject() + .endObject().endObject(); + + return mapping; + } + catch(IOException ioe) { + throw new TechnicalException(String.format("Error while getting mapping for index [%s/%s]: %s", getIndex(), CATEGORY_TYPE, ioe.getMessage()), ioe); + } + } + + protected void fillCategories() { + if (logger.isDebugEnabled()) { + logger.debug(String.format("[%s/%s] Fill data", getIndex(), CATEGORY_TYPE)); + } + + // Insert categories + client.bulkFromClasspathFile(CATEGORIES_BULK_CLASSPATH_FILE, getIndex(), CATEGORY_TYPE, + // Add order attribute + new AddSequenceAttributeHandler("order", "\\{.*\"name\".*\\}", 1)); + } +} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/RecordDao.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexTypeDao.java similarity index 86% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/RecordDao.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexTypeDao.java index 3313806a..1b3637b6 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/dao/RecordDao.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/SubscriptionIndexTypeDao.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange.dao; +package org.duniter.elasticsearch.subscription.dao; /* * #%L @@ -28,9 +28,7 @@ import org.duniter.elasticsearch.dao.IndexTypeDao; /** * Created by Benoit on 30/03/2015. */ -public interface RecordDao<T extends RecordDao> extends IndexTypeDao<T> { - - String TYPE = "record"; +public interface SubscriptionIndexTypeDao<T extends SubscriptionIndexTypeDao> extends IndexTypeDao<T> { String create(final String json); diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/record/SubscriptionRecordDao.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/record/SubscriptionRecordDao.java new file mode 100644 index 00000000..b8b2703c --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/record/SubscriptionRecordDao.java @@ -0,0 +1,16 @@ +package org.duniter.elasticsearch.subscription.dao.record; + +import org.duniter.elasticsearch.subscription.dao.SubscriptionIndexTypeDao; +import org.duniter.elasticsearch.subscription.model.Subscription; + +import java.util.List; + +/** + * Created by blavenie on 03/04/17. + */ +public interface SubscriptionRecordDao<T extends SubscriptionIndexTypeDao> extends SubscriptionIndexTypeDao<T> { + + String TYPE = "record"; + + List<Subscription> getSubscriptions(int from, int size, String recipient, String... types); +} diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/record/SubscriptionRecordDaoImpl.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/record/SubscriptionRecordDaoImpl.java new file mode 100644 index 00000000..983ae405 --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/dao/record/SubscriptionRecordDaoImpl.java @@ -0,0 +1,141 @@ +package org.duniter.elasticsearch.subscription.dao.record; + +import org.duniter.core.exception.TechnicalException; +import org.duniter.core.util.CollectionUtils; +import org.duniter.elasticsearch.subscription.PluginSettings; +import org.duniter.elasticsearch.subscription.dao.AbstractSubscriptionIndexTypeDao; +import org.duniter.elasticsearch.subscription.dao.SubscriptionIndexDao; +import org.duniter.elasticsearch.subscription.model.Subscription; +import org.duniter.elasticsearch.subscription.model.email.EmailSubscription; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.search.SearchType; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.SearchHit; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Created by blavenie on 03/04/17. + */ +public class SubscriptionRecordDaoImpl extends AbstractSubscriptionIndexTypeDao<SubscriptionRecordDaoImpl> implements SubscriptionRecordDao<SubscriptionRecordDaoImpl> { + + @Inject + public SubscriptionRecordDaoImpl(PluginSettings pluginSettings, SubscriptionIndexDao indexDao) { + super(SubscriptionIndexDao.INDEX, TYPE, pluginSettings); + + indexDao.register(this); + } + + @Override + public List<Subscription> getSubscriptions(int from, int size, String recipient, String... types) { + + BoolQueryBuilder query = QueryBuilders.boolQuery() + .must(QueryBuilders.termQuery(Subscription.PROPERTY_RECIPIENT, recipient)); + if (CollectionUtils.isNotEmpty(types)) { + query.must(QueryBuilders.termsQuery(Subscription.PROPERTY_TYPE, types)); + } + + SearchResponse response = client.prepareSearch(SubscriptionIndexDao.INDEX) + .setTypes(SubscriptionRecordDao.TYPE) + .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) + .setQuery(query) + .setFetchSource(true) + .setFrom(from).setSize(size) + .get(); + + return Arrays.asList(response.getHits().getHits()).stream() + .map(this::toSubscription) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + @Override + public XContentBuilder createTypeMapping() { + try { + XContentBuilder mapping = XContentFactory.jsonBuilder().startObject() + .startObject(getType()) + .startObject("properties") + + // issuer + .startObject("issuer") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + + // recipient + .startObject("recipient") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + + // time + .startObject("time") + .field("type", "integer") + .endObject() + + // nonce + .startObject("nonce") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + + // issuer content + .startObject("issuer_content") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + + // receiver content + .startObject("receiver_content") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + + // hash + .startObject("hash") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + + // signature + .startObject("signature") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + + + .endObject() + .endObject().endObject(); + + return mapping; + } + catch(IOException ioe) { + throw new TechnicalException(String.format("Error while getting mapping for index [%s/%s]: %s", getIndex(), getType(), ioe.getMessage()), ioe); + } + } + + protected Subscription toSubscription(SearchHit searchHit) { + + Subscription record = null; + + if (SubscriptionRecordDao.TYPE.equals(searchHit.getType())) { + record = client.readSourceOrNull(searchHit, EmailSubscription.class); + } + + if (record != null) { + record.setId(searchHit.getId()); + } + + return record; + } + +} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/Protocol.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/Protocol.java similarity index 90% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/Protocol.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/Protocol.java index 3d5539e6..ea9d484a 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/model/Protocol.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/Protocol.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange.model; +package org.duniter.elasticsearch.subscription.model; /* * #%L @@ -29,5 +29,5 @@ public interface Protocol { String VERSION = "1"; - String GCHANGE_API = "GCHANGE_API"; + String EMAIL_API = "EMAIL_API"; } diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/Subscription.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/Subscription.java new file mode 100644 index 00000000..2ffc884e --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/Subscription.java @@ -0,0 +1,101 @@ +package org.duniter.elasticsearch.subscription.model; + +/* + * #%L + * Duniter4j :: ElasticSearch GChange plugin + * %% + * Copyright (C) 2014 - 2017 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.duniter.core.client.model.elasticsearch.Record; + +/** + * Created by blavenie on 01/12/16. + */ +public class Subscription<T> extends Record{ + + public static final String PROPERTY_RECIPIENT = "recipient"; + + public static final String PROPERTY_NONCE = "nonce"; + + public static final String PROPERTY_RECIPIENT_CONTENT = "recipientContent"; + + public static final String PROPERTY_ISSUER_CONTENT = "issuerContent"; + + public static final String PROPERTY_CONTENT = "content"; + + public static final String PROPERTY_TYPE = "type"; + + private String recipient; + private String nonce; + private String recipientContent; + private String issuerContent; + private String type; + private T content; + + public String getRecipient() { + return recipient; + } + + public void setRecipient(String recipient) { + this.recipient = recipient; + } + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } + + public String getRecipientContent() { + return recipientContent; + } + + public void setRecipientContent(String recipientContent) { + this.recipientContent = recipientContent; + } + + public String getIssuerContent() { + return issuerContent; + } + + public void setIssuerContent(String issuerContent) { + this.issuerContent = issuerContent; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @JsonIgnore + public T getContent() { + return content; + } + + @JsonIgnore + public void setContent(T content) { + this.content = content; + } +} diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/email/EmailSubscription.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/email/EmailSubscription.java new file mode 100644 index 00000000..663297df --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/model/email/EmailSubscription.java @@ -0,0 +1,83 @@ +package org.duniter.elasticsearch.subscription.model.email; + +/* + * #%L + * Duniter4j :: ElasticSearch GChange plugin + * %% + * Copyright (C) 2014 - 2017 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import org.duniter.elasticsearch.subscription.model.Subscription; + +/** + * Created by blavenie on 01/12/16. + */ +public class EmailSubscription extends Subscription<EmailSubscription.Content> { + + public static final String TYPE = "email"; + + public static Content newContent() { + return new EmailSubscription.Content(); + } + + public static class Content { + + public static final String PROPERTY_EMAIL = "email"; + public static final String PROPERTY_LOCALE = "locale"; + public static final String PROPERTY_INCLUDES = "includes"; + public static final String PROPERTY_EXCLUDES = "excludes"; + + private String email; + private String[] includes; + private String[] excludes; + private String locale; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String[] getIncludes() { + return includes; + } + + public void setIncludes(String[] includes) { + this.includes = includes; + } + + public String[] getExcludes() { + return excludes; + } + + public void setExcludes(String[] excludes) { + this.excludes = excludes; + } + + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } + } + +} diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/RestModule.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/RestModule.java new file mode 100644 index 00000000..4552038a --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/RestModule.java @@ -0,0 +1,40 @@ +package org.duniter.elasticsearch.subscription.rest; + +/* + * #%L + * duniter4j-elasticsearch-plugin + * %% + * Copyright (C) 2014 - 2016 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import org.duniter.elasticsearch.subscription.rest.record.RestSubscriptionRecordIndexAction; +import org.duniter.elasticsearch.subscription.rest.record.RestSubscriptionRecordUpdateAction; +import org.duniter.elasticsearch.subscription.rest.record.RestSubscriptionCategoryGetAction; +import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.inject.Module; + +public class RestModule extends AbstractModule implements Module { + + @Override protected void configure() { + + // Mail + bind(RestSubscriptionRecordIndexAction.class).asEagerSingleton(); + bind(RestSubscriptionRecordUpdateAction.class).asEagerSingleton(); + bind(RestSubscriptionCategoryGetAction.class).asEagerSingleton(); + } +} \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCategoryAction.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionCategoryGetAction.java similarity index 75% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCategoryAction.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionCategoryGetAction.java index f82ce5a7..010c12ce 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/market/RestMarketCategoryAction.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionCategoryGetAction.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange.rest.market; +package org.duniter.elasticsearch.subscription.rest.record; /* * #%L @@ -22,17 +22,17 @@ package org.duniter.elasticsearch.gchange.rest.market; * #L% */ -import org.duniter.elasticsearch.gchange.dao.market.MarketIndexDao; +import org.duniter.elasticsearch.subscription.dao.SubscriptionIndexDao; import org.duniter.elasticsearch.rest.security.RestSecurityController; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.rest.RestRequest; -public class RestMarketCategoryAction { +public class RestSubscriptionCategoryGetAction { @Inject - public RestMarketCategoryAction(RestSecurityController securityController) { + public RestSubscriptionCategoryGetAction(RestSecurityController securityController) { // Add security rule for category - securityController.allowIndexType(RestRequest.Method.GET, MarketIndexDao.INDEX, MarketIndexDao.CATEGORY_TYPE); + securityController.allowIndexType(RestRequest.Method.GET, SubscriptionIndexDao.INDEX, SubscriptionIndexDao.CATEGORY_TYPE); } } \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCommentIndexAction.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionRecordIndexAction.java similarity index 62% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCommentIndexAction.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionRecordIndexAction.java index 7ee815c9..8a4bb1a6 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryCommentIndexAction.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionRecordIndexAction.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange.rest.registry; +package org.duniter.elasticsearch.subscription.rest.record; /* * #%L @@ -22,24 +22,24 @@ package org.duniter.elasticsearch.gchange.rest.registry; * #L% */ -import org.duniter.elasticsearch.gchange.dao.registry.RegistryCommentDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryIndexDao; +import org.duniter.elasticsearch.subscription.dao.SubscriptionIndexDao; +import org.duniter.elasticsearch.subscription.dao.record.SubscriptionRecordDao; import org.duniter.elasticsearch.rest.AbstractRestPostIndexAction; import org.duniter.elasticsearch.rest.security.RestSecurityController; -import org.duniter.elasticsearch.gchange.service.RegistryService; +import org.duniter.elasticsearch.subscription.service.SubscriptionService; import org.elasticsearch.client.Client; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.rest.RestController; -public class RestRegistryCommentIndexAction extends AbstractRestPostIndexAction { +public class RestSubscriptionRecordIndexAction extends AbstractRestPostIndexAction { + @Inject - public RestRegistryCommentIndexAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, - RegistryService service) { + public RestSubscriptionRecordIndexAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, + SubscriptionService service) { super(settings, controller, client, securityController, - RegistryIndexDao.INDEX, RegistryCommentDao.TYPE, - json -> service.indexCommentFromJson(json)); + SubscriptionIndexDao.INDEX, SubscriptionRecordDao.TYPE, + json -> service.create(json)); } - } \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryRecordUpdateAction.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionRecordUpdateAction.java similarity index 62% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryRecordUpdateAction.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionRecordUpdateAction.java index 4131c882..2a265957 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/rest/registry/RestRegistryRecordUpdateAction.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/rest/record/RestSubscriptionRecordUpdateAction.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange.rest.registry; +package org.duniter.elasticsearch.subscription.rest.record; /* * #%L @@ -22,9 +22,9 @@ package org.duniter.elasticsearch.gchange.rest.registry; * #L% */ -import org.duniter.elasticsearch.gchange.dao.registry.RegistryIndexDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryRecordDao; -import org.duniter.elasticsearch.gchange.service.RegistryService; +import org.duniter.elasticsearch.subscription.dao.SubscriptionIndexDao; +import org.duniter.elasticsearch.subscription.dao.record.SubscriptionRecordDao; +import org.duniter.elasticsearch.subscription.service.SubscriptionService; import org.duniter.elasticsearch.rest.AbstractRestPostUpdateAction; import org.duniter.elasticsearch.rest.security.RestSecurityController; import org.elasticsearch.client.Client; @@ -32,14 +32,14 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.rest.RestController; -public class RestRegistryRecordUpdateAction extends AbstractRestPostUpdateAction { +public class RestSubscriptionRecordUpdateAction extends AbstractRestPostUpdateAction { @Inject - public RestRegistryRecordUpdateAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, - RegistryService service) { + public RestSubscriptionRecordUpdateAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, + SubscriptionService service) { super(settings, controller, client, securityController, - RegistryIndexDao.INDEX, RegistryRecordDao.TYPE, - (id, json) -> service.updateRecordFromJson(id, json)); + SubscriptionIndexDao.INDEX, SubscriptionRecordDao.TYPE, + (id, json) -> service.update(id, json)); } } \ No newline at end of file diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/AbstractService.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/AbstractService.java similarity index 88% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/AbstractService.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/AbstractService.java index 9ac60691..a900a2b2 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/AbstractService.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/AbstractService.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange.service; +package org.duniter.elasticsearch.subscription.service; /* * #%L @@ -24,8 +24,7 @@ package org.duniter.elasticsearch.gchange.service; import org.duniter.core.service.CryptoService; import org.duniter.elasticsearch.client.Duniter4jClient; -import org.duniter.elasticsearch.gchange.PluginSettings; -import org.elasticsearch.client.Client; +import org.duniter.elasticsearch.subscription.PluginSettings; /** * Created by blavenie on 10/01/17. @@ -43,7 +42,7 @@ public abstract class AbstractService extends org.duniter.elasticsearch.user.ser } public AbstractService(Duniter4jClient client, PluginSettings pluginSettings, CryptoService cryptoService) { - this("duniter.gchange", client, pluginSettings, cryptoService); + this("duniter.subscription", client, pluginSettings, cryptoService); } public AbstractService(String loggerName, Duniter4jClient client, PluginSettings pluginSettings, CryptoService cryptoService) { diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/ServiceModule.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/ServiceModule.java similarity index 82% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/ServiceModule.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/ServiceModule.java index a3d5f3d3..2bb9c7b9 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/ServiceModule.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/ServiceModule.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange.service; +package org.duniter.elasticsearch.subscription.service; /* * #%L @@ -28,9 +28,10 @@ import org.elasticsearch.common.inject.Module; public class ServiceModule extends AbstractModule implements Module { @Override protected void configure() { - bind(RegistryService.class).asEagerSingleton(); - bind(CommentUserEventService.class).asEagerSingleton(); - bind(MarketService.class).asEagerSingleton(); + // Subscription services + bind(SubscriptionService.class).asEagerSingleton(); + + // Synchro service bind(SynchroService.class).asEagerSingleton(); } } \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SubscriptionService.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SubscriptionService.java new file mode 100644 index 00000000..7571a7f6 --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SubscriptionService.java @@ -0,0 +1,358 @@ +package org.duniter.elasticsearch.subscription.service; + +/* + * #%L + * UCoin Java Client :: Core API + * %% + * Copyright (C) 2014 - 2015 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.ImmutableSet; +import org.duniter.core.client.model.ModelUtils; +import org.duniter.core.client.model.bma.jackson.JacksonUtils; +import org.duniter.core.client.model.elasticsearch.Record; +import org.duniter.core.exception.TechnicalException; +import org.duniter.core.service.CryptoService; +import org.duniter.core.util.CollectionUtils; +import org.duniter.core.util.Preconditions; +import org.duniter.core.util.StringUtils; +import org.duniter.core.util.crypto.CryptoUtils; +import org.duniter.elasticsearch.client.Duniter4jClient; +import org.duniter.elasticsearch.subscription.PluginSettings; +import org.duniter.elasticsearch.subscription.dao.record.SubscriptionRecordDao; +import org.duniter.elasticsearch.subscription.model.Subscription; +import org.duniter.elasticsearch.subscription.model.email.EmailSubscription; +import org.duniter.elasticsearch.subscription.util.stringtemplate.DateRenderer; +import org.duniter.elasticsearch.subscription.util.stringtemplate.I18nRenderer; +import org.duniter.elasticsearch.threadpool.ThreadPool; +import org.duniter.elasticsearch.user.model.UserEvent; +import org.duniter.elasticsearch.user.service.AdminService; +import org.duniter.elasticsearch.user.service.MailService; +import org.duniter.elasticsearch.user.service.UserEventService; +import org.duniter.elasticsearch.user.service.UserService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.unit.TimeValue; +import org.nuiton.i18n.I18n; +import org.stringtemplate.v4.*; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Created by Benoit on 30/03/2015. + */ +public class SubscriptionService extends AbstractService { + + private SubscriptionRecordDao subscriptionRecordDao; + private ThreadPool threadPool; + private MailService mailService; + private AdminService adminService; + private UserEventService userEventService; + private UserService userService; + private String emailSubjectPrefix; + + @Inject + public SubscriptionService(Duniter4jClient client, + PluginSettings settings, + CryptoService cryptoService, + SubscriptionRecordDao subscriptionRecordDao, + ThreadPool threadPool, + MailService mailService, + AdminService adminService, + UserService userService, + UserEventService userEventService) { + super("subscription.service", client, settings, cryptoService); + this.subscriptionRecordDao = subscriptionRecordDao; + this.threadPool = threadPool; + this.mailService = mailService; + this.adminService = adminService; + this.userService = userService; + this.userEventService = userEventService; + this.emailSubjectPrefix = pluginSettings.getMailSubjectPrefix().trim(); + if (StringUtils.isNotBlank(emailSubjectPrefix)) { + emailSubjectPrefix += " "; // add one trailing space + } + } + + public String create(String json) { + JsonNode actualObj = readAndVerifyIssuerSignature(json); + String issuer = getIssuer(actualObj); + + if (logger.isDebugEnabled()) { + logger.debug(String.format("Indexing a subscription from issuer [%s]", issuer.substring(0, 8))); + } + + return subscriptionRecordDao.create(json); + } + + public void update(String id, String json) { + JsonNode actualObj = readAndVerifyIssuerSignature(json); + String issuer = getIssuer(actualObj); + + // Check same document issuer + subscriptionRecordDao.checkSameDocumentIssuer(id, issuer); + + if (logger.isDebugEnabled()) { + logger.debug(String.format("Updating subscription [%s] from issuer [%s]", id, issuer.substring(0, 8))); + } + + subscriptionRecordDao.update(id, json); + } + + public SubscriptionService startScheduling() { + if (!pluginSettings.getMailEnable()) { + logger.warn(I18n.t("duniter4j.es.subscription.error.mailDisabling")); + return this; + } + + threadPool.scheduleWithFixedDelay( + this::executeEmailSubscriptions, + new TimeValue(pluginSettings.getExecuteEmailSubscriptionsInterval())); + + return this; + } + + public void executeEmailSubscriptions() { + + final String senderPubkey = pluginSettings.getNodePubkey(); + + int from = 0; + int size = 10; + + boolean hasMore = true; + while (hasMore) { + List<Subscription> subscriptions = subscriptionRecordDao.getSubscriptions(from, size, senderPubkey, EmailSubscription.TYPE); + + // Get profiles titles, for issuers and the sender + Set<String> issuers = subscriptions.stream() + .map(Subscription::getIssuer) + .distinct() + .collect(Collectors.toSet()); + final Map<String, String> profileTitles = userService.getProfileTitles( + ImmutableSet.<String>builder().addAll(issuers).add(senderPubkey).build()); + final String senderName = (profileTitles != null && profileTitles.containsKey(senderPubkey)) ? profileTitles.get(senderPubkey) : + ModelUtils.minifyPubkey(senderPubkey); + + subscriptions.stream() + .map(record -> decryptEmailSubscription((EmailSubscription)record)) + .filter(Objects::nonNull) + .map(record -> processEmailSubscription(record, senderPubkey, senderName, profileTitles)) + .filter(Objects::nonNull) + .forEach(this::saveSubscription); + + hasMore = CollectionUtils.size(subscriptions) >= size; + from += size; + } + } + + /* -- protected methods -- */ + + + protected EmailSubscription decryptEmailSubscription(EmailSubscription subscription) { + Preconditions.checkNotNull(subscription); + Preconditions.checkNotNull(subscription.getId()); + + if (StringUtils.isBlank(subscription.getRecipientContent()) || StringUtils.isBlank(subscription.getNonce()) || + StringUtils.isBlank(subscription.getIssuer())) { + logger.error(String.format("Invalid subscription [%s]. Missing field 'recipientContent', 'nonce' or 'issuer'.", subscription.getId())); + return null; + } + + String jsonContent; + try { + jsonContent = cryptoService.openBox(subscription.getRecipientContent(), + CryptoUtils.decodeBase58(subscription.getNonce()), + CryptoUtils.decodeBase58(subscription.getIssuer()), + pluginSettings.getNodeKeypair().getSecKey() + ); + } catch(Exception e) { + logger.error(String.format("Could not decrypt email subscription content for subscription [%s]", subscription.getId())); + return null; + } + + try { + EmailSubscription.Content content = objectMapper.readValue(jsonContent, EmailSubscription.Content.class); + subscription.setContent(content); + } catch(Exception e) { + logger.error(String.format("Could not parse email subscription content [%s]: %s", jsonContent, e.getMessage())); + return null; + } + + return subscription; + } + + protected EmailSubscription processEmailSubscription(final EmailSubscription subscription, + final String senderPubkey, + final String senderName, + final Map<String, String> profileTitles) { + Preconditions.checkNotNull(subscription); + + logger.info(String.format("Processing email subscription [%s]", subscription.getId())); + + Long lastTime = 0l; // TODO get it from subscription ? + + // Get last user events + String[] includes = subscription.getContent() == null ? null : subscription.getContent().getIncludes(); + String[] excludes = subscription.getContent() == null ? null : subscription.getContent().getExcludes(); + List<UserEvent> userEvents = userEventService.getUserEvents(subscription.getIssuer(), lastTime, includes, excludes); + + + STGroup templates = new STGroupDir("templates", '$', '$'); + templates.registerRenderer(Date.class, new DateRenderer()); + //templates.registerRenderer(String.class, new StringRenderer()); + //templates.registerRenderer(Number.class, new NumberRenderer()); + templates.registerRenderer(String.class, new I18nRenderer()); + String[] localParts = subscription.getContent() != null && subscription.getContent().getLocale() != null ? + subscription.getContent().getLocale().split("-") : new String[]{"en", "GB"}; + + Locale issuerLocale = localParts.length >= 2 ? new Locale(localParts[0].toLowerCase(), localParts[1].toUpperCase()) : new Locale(localParts[0].toLowerCase()); + + // Compute text + String text = fillTemplate( + templates.getInstanceOf("text_email"), + subscription, + senderPubkey, + senderName, + profileTitles, + userEvents, + pluginSettings.getCesiumUrl()) + .render(issuerLocale); + + // Compute HTML content + String html = fillTemplate( + templates.getInstanceOf("html_email_content"), + subscription, + senderPubkey, + senderName, + profileTitles, + userEvents, + pluginSettings.getCesiumUrl()) + .render(issuerLocale); + + mailService.sendHtmlEmailWithText( + emailSubjectPrefix + I18n.t("duniter4j.es.subscription.email.subject", userEvents.size()), + text, + "<body>" + html + "</body>", + subscription.getContent().getEmail()); + return subscription; + } + + + public static ST fillTemplate(ST template, + EmailSubscription subscription, + String senderPubkey, + String senderName, + Map<String, String> issuerProfilNames, + List<UserEvent> userEvents, + String cesiumSiteUrl) { + String issuerName = issuerProfilNames != null && issuerProfilNames.containsKey(subscription.getIssuer()) ? + issuerProfilNames.get(subscription.getIssuer()) : + ModelUtils.minifyPubkey(subscription.getIssuer()); + + + try { + // Compute body + template.add("url", cesiumSiteUrl); + template.add("issuer", issuerName); + template.add("senderPubkey", senderPubkey); + template.add("senderName", senderName); + userEvents.forEach(userEvent -> { + String description = userEvent.getParams() != null ? + I18n.t("duniter.user.event." + userEvent.getCode().toUpperCase(), userEvent.getParams()) : + I18n.t("duniter.user.event." + userEvent.getCode().toUpperCase()); + template.addAggr("events.{description, time}", new Object[]{ + description, + new Date(userEvent.getTime() * 1000) + }); + + }); + + return template; + + } + catch (Exception e) { + throw new TechnicalException(e); + } + } + + + public static String computeTextEmail(STGroup templates, + Locale issuerLocale, + EmailSubscription subscription, + String senderPubkey, + String senderName, + Map<String, String> issuerProfilNames, + List<UserEvent> userEvents, + String cesiumSiteUrl) { + String issuerName = issuerProfilNames != null && issuerProfilNames.containsKey(subscription.getIssuer()) ? + issuerProfilNames.get(subscription.getIssuer()) : + ModelUtils.minifyPubkey(subscription.getIssuer()); + + try { + // Compute text content + ST tpl = templates.getInstanceOf("text_email"); + tpl.add("url", cesiumSiteUrl); + tpl.add("issuer", issuerName); + tpl.add("url", cesiumSiteUrl); + tpl.add("senderPubkey", senderPubkey); + tpl.add("senderName", senderName); + userEvents.forEach(userEvent -> { + String description = userEvent.getParams() != null ? + I18n.t("duniter.user.event." + userEvent.getCode().toUpperCase(), userEvent.getParams()) : + I18n.t("duniter.user.event." + userEvent.getCode().toUpperCase()); + tpl.addAggr("events.{description, time}", new Object[]{ + description, + new Date(userEvent.getTime() * 1000) + }); + + }); + + return tpl.render(); + } + catch (Exception e) { + throw new TechnicalException(e); + } + } + + protected EmailSubscription saveSubscription(EmailSubscription subscription) { + Preconditions.checkNotNull(subscription); + + //mailService.sendEmail(); + return subscription; + } + + private String toJson(EmailSubscription subscription) { + return toJson(subscription, false); + } + + private String toJson(EmailSubscription subscription, boolean cleanHashAndSignature) { + try { + String json = objectMapper.writeValueAsString(subscription); + if (cleanHashAndSignature) { + json = JacksonUtils.removeAttribute(json, Record.PROPERTY_SIGNATURE); + json = JacksonUtils.removeAttribute(json, Record.PROPERTY_HASH); + } + return json; + } catch(JsonProcessingException e) { + throw new TechnicalException("Unable to serialize UserEvent object", e); + } + } +} diff --git a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/SynchroService.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SynchroService.java similarity index 56% rename from duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/SynchroService.java rename to duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SynchroService.java index 977f2330..94421128 100644 --- a/duniter4j-es-gchange/src/main/java/org/duniter/elasticsearch/gchange/service/SynchroService.java +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SynchroService.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch.gchange.service; +package org.duniter.elasticsearch.subscription.service; /* * #%L @@ -25,19 +25,14 @@ package org.duniter.elasticsearch.gchange.service; import org.duniter.core.client.model.local.Peer; import org.duniter.core.service.CryptoService; import org.duniter.elasticsearch.client.Duniter4jClient; -import org.duniter.elasticsearch.gchange.dao.market.MarketCommentDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketIndexDao; -import org.duniter.elasticsearch.gchange.dao.market.MarketRecordDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryCommentDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryIndexDao; -import org.duniter.elasticsearch.gchange.dao.registry.RegistryRecordDao; -import org.duniter.elasticsearch.gchange.model.Protocol; import org.duniter.elasticsearch.model.SynchroResult; import org.duniter.elasticsearch.service.AbstractSynchroService; import org.duniter.elasticsearch.service.ServiceLocator; +import org.duniter.elasticsearch.subscription.dao.SubscriptionIndexDao; +import org.duniter.elasticsearch.subscription.dao.record.SubscriptionRecordDao; +import org.duniter.elasticsearch.subscription.model.Protocol; import org.duniter.elasticsearch.threadpool.ThreadPool; import org.duniter.elasticsearch.user.PluginSettings; -import org.elasticsearch.client.Client; import org.elasticsearch.common.inject.Inject; /** @@ -52,8 +47,8 @@ public class SynchroService extends AbstractSynchroService { } public void synchronize() { - logger.info("Synchronizing Gchange data..."); - Peer peer = getPeerFromAPI(Protocol.GCHANGE_API); + logger.info("Synchronizing subscription data..."); + Peer peer = getPeerFromAPI(Protocol.EMAIL_API); synchronize(peer); } @@ -63,25 +58,18 @@ public class SynchroService extends AbstractSynchroService { long sinceTime = 0; // TODO: get last sync time from somewhere ? (e.g. a specific index) - logger.info(String.format("[%s] Synchronizing gchange data since %s...", peer.toString(), sinceTime)); + logger.info(String.format("[%s] Synchronizing subscription data since %s...", peer.toString(), sinceTime)); SynchroResult result = new SynchroResult(); long time = System.currentTimeMillis(); - importMarketChanges(result, peer, sinceTime); - importRegistryChanges(result, peer, sinceTime); + importMailChanges(result, peer, sinceTime); long duration = System.currentTimeMillis() - time; - logger.info(String.format("[%s] Synchronizing gchange data since %s [OK] %s (in %s ms)", peer.toString(), sinceTime, result.toString(), duration)); + logger.info(String.format("[%s] Synchronizing subscription data since %s [OK] %s (in %s ms)", peer.toString(), sinceTime, result.toString(), duration)); } - protected void importMarketChanges(SynchroResult result, Peer peer, long sinceTime) { - importChanges(result, peer, MarketIndexDao.INDEX, MarketRecordDao.TYPE, sinceTime); - importChanges(result, peer, MarketIndexDao.INDEX, MarketCommentDao.TYPE, sinceTime); - } - - protected void importRegistryChanges(SynchroResult result, Peer peer, long sinceTime) { - importChanges(result, peer, RegistryIndexDao.INDEX, RegistryRecordDao.TYPE, sinceTime); - importChanges(result, peer, RegistryIndexDao.INDEX, RegistryCommentDao.TYPE, sinceTime); + protected void importMailChanges(SynchroResult result, Peer peer, long sinceTime) { + importChanges(result, peer, SubscriptionIndexDao.INDEX, SubscriptionRecordDao.TYPE, sinceTime); } } diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/DateRenderer.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/DateRenderer.java new file mode 100644 index 00000000..eb84ec8d --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/DateRenderer.java @@ -0,0 +1,43 @@ +package org.duniter.elasticsearch.subscription.util.stringtemplate; + +import org.stringtemplate.v4.AttributeRenderer; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +public class DateRenderer implements AttributeRenderer { + + public DateRenderer() { + } + + public String toString(Object o, String formatString, Locale locale) { + if(formatString == null) { + formatString = "short"; + } + + Date d; + if(o instanceof Calendar) { + d = ((Calendar)o).getTime(); + } else { + d = (Date)o; + } + + Integer styleI = (Integer)org.stringtemplate.v4.DateRenderer.formatToInt.get(formatString); + Object f; + if(styleI == null) { + f = new SimpleDateFormat(formatString, locale); + } else { + int style = styleI.intValue(); + if(formatString.startsWith("date:")) { + f = DateFormat.getDateInstance(style, locale); + } else if(formatString.startsWith("time:")) { + f = DateFormat.getTimeInstance(style, locale); + } else { + f = DateFormat.getDateTimeInstance(style, style, locale); + } + } + + return ((DateFormat)f).format(d); + } +} \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/I18nRenderer.java b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/I18nRenderer.java new file mode 100644 index 00000000..fbcd6a98 --- /dev/null +++ b/duniter4j-es-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/I18nRenderer.java @@ -0,0 +1,24 @@ +package org.duniter.elasticsearch.subscription.util.stringtemplate; + +import org.duniter.core.util.CollectionUtils; +import org.duniter.core.util.StringUtils; +import org.nuiton.i18n.I18n; +import org.stringtemplate.v4.AttributeRenderer; + +import java.util.Locale; + +/** + * Created by blavenie on 10/04/17. + */ +public class I18nRenderer implements AttributeRenderer{ + + @Override + public String toString(Object key, String formatString, Locale locale) { + if (formatString == null || !formatString.startsWith("i18n")) return key.toString(); + String[] params = formatString.startsWith("i18n:") ? formatString.substring(5).split(",") : null; + if (CollectionUtils.isNotEmpty(params)) { + return I18n.l(locale, key.toString(), params); + } + return I18n.l(locale, key.toString()); + } +} diff --git a/duniter4j-es-gchange/src/main/misc/index.sh b/duniter4j-es-subscription/src/main/misc/index.sh similarity index 100% rename from duniter4j-es-gchange/src/main/misc/index.sh rename to duniter4j-es-subscription/src/main/misc/index.sh diff --git a/duniter4j-es-subscription/src/main/resources/i18n/duniter4j-es-subscription_en_GB.properties b/duniter4j-es-subscription/src/main/resources/i18n/duniter4j-es-subscription_en_GB.properties new file mode 100644 index 00000000..d179ccf7 --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/i18n/duniter4j-es-subscription_en_GB.properties @@ -0,0 +1,7 @@ +duniter4j.es.subscription.email.footer.disableHelp=You can disable this email notification service in the page <a href\="%s">Online services</a> of Cesium+. +duniter4j.es.subscription.email.footer.sendBy=This email has sent you the Cesium+ node of <a href\="%s">%s</a>. +duniter4j.es.subscription.email.header=Hello <b>%s</b>\!<br/>You received %s new notifications\: +duniter4j.es.subscription.email.notificationsDivider=Notifications list\: +duniter4j.es.subscription.email.openCesium=Open Cesium+ +duniter4j.es.subscription.email.subject=You received %s new notifications +duniter4j.es.subscription.error.mailDisabling=Unable to process email subscriptions\: Email sending is disabled in the configuration diff --git a/duniter4j-es-subscription/src/main/resources/i18n/duniter4j-es-subscription_fr_FR.properties b/duniter4j-es-subscription/src/main/resources/i18n/duniter4j-es-subscription_fr_FR.properties new file mode 100644 index 00000000..37f541ed --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/i18n/duniter4j-es-subscription_fr_FR.properties @@ -0,0 +1,11 @@ +duniter4j.es.subscription.email.footer=Cet email vous a été envoyé par Cesium+.<br/><small>vous pouvez désactiver ce service de notification par email, dans la rubrique <a href\="%s">Services en ligne</a> de Cesium+. +duniter4j.es.subscription.email.footer.disableHelp=Vous pouvez désactiver ce service de notification par email, dans la rubrique <a href\="%s">Services en ligne</a> de Cesium+. +duniter4j.es.subscription.email.footer.disableHelp.text=Vous pouvez désactiver ce service de notification par email, dans la rubrique "Services en ligne" de Cesium+ (%s). +duniter4j.es.subscription.email.footer.sendBy=Cet email vous a été envoyé le noeud Cesium+ de <a href\="%1$s">%2$s</a>. +duniter4j.es.subscription.email.footer.sendBy.text=Cet email vous a été envoyé le noeud Cesium+ de %2$s (%1$s). +duniter4j.es.subscription.email.header=Bonjour <b>%s</b> \!<br/>Vous avez %s notifications non lues. +duniter4j.es.subscription.email.header.text=Bonjour %s \!\nVous avez %s notifications non lues. +duniter4j.es.subscription.email.notificationsDivider=Liste des notifications \: +duniter4j.es.subscription.email.openCesium=Ouvrir Cesium+ +duniter4j.es.subscription.email.subject=%s nouvelles notifications non lues +duniter4j.es.subscription.error.mailDisabling=Impossible de traiter les abonnements email\: la fonction d'envoi d'email est désactivée dans la configuration diff --git a/duniter4j-es-gchange/src/main/resources/plugin-security.policy b/duniter4j-es-subscription/src/main/resources/plugin-security.policy similarity index 100% rename from duniter4j-es-gchange/src/main/resources/plugin-security.policy rename to duniter4j-es-subscription/src/main/resources/plugin-security.policy diff --git a/duniter4j-es-subscription/src/main/resources/subscription-categories-bulk-insert.json b/duniter4j-es-subscription/src/main/resources/subscription-categories-bulk-insert.json new file mode 100644 index 00000000..37e83c19 --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/subscription-categories-bulk-insert.json @@ -0,0 +1,9 @@ +{ "index": { "_id": "_notification"}} +{ "name": "Notifications" , "parent": null} +{ "index": { "_id": "email"}} +{ "name": "Email", "parent": "_notification"} + +{ "index": { "_id": "_service"}} +{ "name": "Services de paiement" , "parent": null} +{ "index": { "_id": "transfer"}} +{ "name": "Virement automatique", "parent": "_service"} \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/resources/templates/css.st b/duniter4j-es-subscription/src/main/resources/templates/css.st new file mode 100644 index 00000000..30a453a5 --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/templates/css.st @@ -0,0 +1,10738 @@ +css() ::= << + html, body, div, span, applet, object, iframe, + h1, h2, h3, h4, h5, h6, p, blockquote, pre, + a, abbr, acronym, address, big, cite, code, + del, dfn, em, img, ins, kbd, q, s, samp, + small, strike, strong, sub, sup, tt, var, + b, i, u, center, + dl, dt, dd, ol, ul, li, + fieldset, form, label, legend, + table, caption, tbody, tfoot, thead, tr, th, td, + article, aside, canvas, details, embed, fieldset, + figure, figcaption, footer, header, hgroup, + menu, nav, output, ruby, section, summary, + time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + vertical-align: baseline; + font: inherit; + font-size: 100%; } + + /** + * Hide the `template` element in IE, Safari, and Firefox < 22. + */ + [hidden], + template { + display: none; } + + script { + display: none !important; } + + /* ========================================================================== + Base + ========================================================================== */ + /** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + html { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + font-family: sans-serif; + /* 1 */ + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + /* 2 */ + -webkit-text-size-adjust: 100%; + /* 2 */ } + + /** + * Remove default margin. + */ + body { + margin: 0; + line-height: 1; } + + /** + * Remove default outlines. + */ + a, + button, + :focus, + a:focus, + button:focus, + a:active, + a:hover { + outline: 0; } + + /* * + * Remove tap highlight color + */ + a { + -webkit-user-drag: none; + -webkit-tap-highlight-color: transparent; + -webkit-tap-highlight-color: transparent; } + a[href]:hover { + cursor: pointer; } + + /* ========================================================================== + Typography + ========================================================================== */ + /** + * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. + */ + b, + strong { + font-weight: bold; } + + /** + * Address styling not present in Safari 5 and Chrome. + */ + dfn { + font-style: italic; } + + /** + * Address differences between Firefox and other browsers. + */ + hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; } + + /** + * Correct font family set oddly in Safari 5 and Chrome. + */ + code, + kbd, + pre, + samp { + font-size: 1em; + font-family: monospace, serif; } + + /** + * Improve readability of pre-formatted text in all browsers. + */ + pre { + white-space: pre-wrap; } + + /** + * Set consistent quote types. + */ + q { + quotes: "\201C" "\201D" "\2018" "\2019"; } + + /** + * Address inconsistent and variable font size in all browsers. + */ + small { + font-size: 80%; } + + /** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + sub, + sup { + position: relative; + vertical-align: baseline; + font-size: 75%; + line-height: 0; } + + sup { + top: -0.5em; } + + sub { + bottom: -0.25em; } + + /** + * Define consistent border, margin, and padding. + */ + fieldset { + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; + border: 1px solid #c0c0c0; } + + /** + * 1. Correct `color` not being inherited in IE 8/9. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + legend { + padding: 0; + /* 2 */ + border: 0; + /* 1 */ } + + /** + * 1. Correct font family not being inherited in all browsers. + * 2. Correct font size not being inherited in all browsers. + * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. + * 4. Remove any default :focus styles + * 5. Make sure webkit font smoothing is being inherited + * 6. Remove default gradient in Android Firefox / FirefoxOS + */ + button, + input, + select, + textarea { + margin: 0; + /* 3 */ + font-size: 100%; + /* 2 */ + font-family: inherit; + /* 1 */ + outline-offset: 0; + /* 4 */ + outline-style: none; + /* 4 */ + outline-width: 0; + /* 4 */ + -webkit-font-smoothing: inherit; + /* 5 */ + background-image: none; + /* 6 */ } + + /** + * Address Firefox 4+ setting `line-height` on `input` using `importnt` in + * the UA stylesheet. + */ + button, + input { + line-height: normal; } + + /** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. + * Correct `select` style inheritance in Firefox 4+ and Opera. + */ + button, + select { + text-transform: none; } + + /** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + button, + html input[type="button"], + input[type="reset"], + input[type="submit"] { + cursor: pointer; + /* 3 */ + -webkit-appearance: button; + /* 2 */ } + + /** + * Re-set default cursor for disabled elements. + */ + button[disabled], + html input[disabled] { + cursor: default; } + + /** + * Remove inner padding and border in Firefox 4+. + */ + button::-moz-focus-inner, + input::-moz-focus-inner { + padding: 0; + border: 0; } + + img { + -webkit-user-drag: none; } + + /** + * Scaffolding + * -------------------------------------------------- + */ + *, + *:before, + *:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } + + html { + overflow: hidden; + -ms-touch-action: pan-y; + touch-action: pan-y; } + + body, + .ionic-body { + -webkit-touch-callout: none; + -webkit-font-smoothing: antialiased; + font-smoothing: antialiased; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + text-size-adjust: none; + -webkit-tap-highlight-color: transparent; + -webkit-tap-highlight-color: transparent; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: hidden; + margin: 0; + padding: 0; + color: #000; + word-wrap: break-word; + font-size: 14px; + font-family: -apple-system; + font-family: "-apple-system", "Helvetica Neue", "Roboto", "Segoe UI", sans-serif; + line-height: 20px; + text-rendering: optimizeLegibility; + -webkit-backface-visibility: hidden; + -webkit-user-drag: none; + -ms-content-zooming: none; } + + .content { + position: relative; } + + /* If you change these, change platform.scss as well */ + .has-header { + top: 44px; } + + .no-header { + top: 0; } + + .has-subheader { + top: 88px; } + + .has-tabs-top { + top: 93px; } + + .has-header.has-subheader.has-tabs-top { + top: 137px; } + + .has-footer { + bottom: 44px; } + + .has-subfooter { + bottom: 88px; } + + .has-tabs, + .bar-footer.has-tabs { + bottom: 49px; } + .has-tabs.pane, + .bar-footer.has-tabs.pane { + bottom: 49px; + height: auto; } + + .bar-subfooter.has-tabs { + bottom: 93px; } + + .has-footer.has-tabs { + bottom: 93px; } + + /** + * Typography + * -------------------------------------------------- + */ + p { + margin: 0 0 10px; } + + small { + font-size: 85%; } + + cite { + font-style: normal; } + + .text-left { + text-align: left; } + + .text-right { + text-align: right; } + + .text-center, .item.large-button-bar { + text-align: center; } + + h1, h2, h3, h4, h5, h6, + .h1, .h2, .h3, .h4, .h5, .h6 { + color: #000; + font-weight: 500; + font-family: "-apple-system", "Helvetica Neue", "Roboto", "Segoe UI", sans-serif; + line-height: 1.2; } + h1 small, h2 small, h3 small, h4 small, h5 small, h6 small, + .h1 small, .h2 small, .h3 small, .h4 small, .h5 small, .h6 small { + font-weight: normal; + line-height: 1; } + + h1, .h1, + h2, .h2, + h3, .h3 { + margin-top: 20px; + margin-bottom: 10px; } + h1:first-child, .h1:first-child, + h2:first-child, .h2:first-child, + h3:first-child, .h3:first-child { + margin-top: 0; } + h1 + h1, h1 + .h1, + h1 + h2, h1 + .h2, + h1 + h3, h1 + .h3, .h1 + h1, .h1 + .h1, + .h1 + h2, .h1 + .h2, + .h1 + h3, .h1 + .h3, + h2 + h1, + h2 + .h1, + h2 + h2, + h2 + .h2, + h2 + h3, + h2 + .h3, .h2 + h1, .h2 + .h1, + .h2 + h2, .h2 + .h2, + .h2 + h3, .h2 + .h3, + h3 + h1, + h3 + .h1, + h3 + h2, + h3 + .h2, + h3 + h3, + h3 + .h3, .h3 + h1, .h3 + .h1, + .h3 + h2, .h3 + .h2, + .h3 + h3, .h3 + .h3 { + margin-top: 10px; } + + h4, .h4, + h5, .h5, + h6, .h6 { + margin-top: 10px; + margin-bottom: 10px; } + + 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; } + + h1 small, .h1 small { + font-size: 24px; } + + h2 small, .h2 small { + font-size: 18px; } + + h3 small, .h3 small, + h4 small, .h4 small { + font-size: 14px; } + + dl { + margin-bottom: 20px; } + + dt, + dd { + line-height: 1.42857; } + + dt { + font-weight: bold; } + + blockquote { + margin: 0 0 20px; + padding: 10px 20px; + border-left: 5px solid gray; } + blockquote p { + font-weight: 300; + font-size: 17.5px; + line-height: 1.25; } + blockquote p:last-child { + margin-bottom: 0; } + blockquote small { + display: block; + line-height: 1.42857; } + blockquote small:before { + content: '\2014 \00A0'; } + + q:before, + q:after, + blockquote:before, + blockquote:after { + content: ""; } + + address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 1.42857; } + + a { + color: #387ef5; } + + a.subdued { + padding-right: 10px; + color: #888; + text-decoration: none; } + a.subdued:hover { + text-decoration: none; } + a.subdued:last-child { + padding-right: 0; } + + /** + * Bar (Headers and Footers) + * -------------------------------------------------- + */ + .bar { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: absolute; + right: 0; + left: 0; + z-index: 9; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 5px; + width: 100%; + height: 44px; + border-width: 0; + border-style: solid; + border-top: 1px solid transparent; + border-bottom: 1px solid #ddd; + background-color: white; + /* border-width: 1px will actually create 2 device pixels on retina */ + /* this nifty trick sets an actual 1px border on hi-res displays */ + background-size: 0; } + @media (min--moz-device-pixel-ratio: 1.5), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi), (min-resolution: 1.5dppx) { + .bar { + border: none; + background-image: linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%); + background-position: bottom; + background-size: 100% 1px; + background-repeat: no-repeat; } } + .bar.bar-clear { + border: none; + background: none; + color: #fff; } + .bar.bar-clear .button { + color: #fff; } + .bar.bar-clear .title { + color: #fff; } + .bar.item-input-inset .item-input-wrapper { + margin-top: -1px; } + .bar.item-input-inset .item-input-wrapper input { + padding-left: 8px; + width: 94%; + height: 28px; + background: transparent; } + .bar.bar-light { + border-color: #ddd; + background-color: white; + background-image: linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%); + color: #444; } + .bar.bar-light .title { + color: #444; } + .bar.bar-light.bar-footer { + background-image: linear-gradient(180deg, #ddd, #ddd 50%, transparent 50%); } + .bar.bar-stable { + border-color: #b2b2b2; + background-color: #f8f8f8; + background-image: linear-gradient(0deg, #b2b2b2, #b2b2b2 50%, transparent 50%); + color: #444; } + .bar.bar-stable .title { + color: #444; } + .bar.bar-stable.bar-footer { + background-image: linear-gradient(180deg, #b2b2b2, #b2b2b2 50%, transparent 50%); } + .bar.bar-positive { + border-color: #0c60ee; + background-color: #387ef5; + background-image: linear-gradient(0deg, #0c60ee, #0c60ee 50%, transparent 50%); + color: #fff; } + .bar.bar-positive .title { + color: #fff; } + .bar.bar-positive.bar-footer { + background-image: linear-gradient(180deg, #0c60ee, #0c60ee 50%, transparent 50%); } + .bar.bar-calm { + border-color: #0a9dc7; + background-color: #11c1f3; + background-image: linear-gradient(0deg, #0a9dc7, #0a9dc7 50%, transparent 50%); + color: #fff; } + .bar.bar-calm .title { + color: #fff; } + .bar.bar-calm.bar-footer { + background-image: linear-gradient(180deg, #0a9dc7, #0a9dc7 50%, transparent 50%); } + .bar.bar-assertive { + border-color: #e42112; + background-color: #ef473a; + background-image: linear-gradient(0deg, #e42112, #e42112 50%, transparent 50%); + color: #fff; } + .bar.bar-assertive .title { + color: #fff; } + .bar.bar-assertive.bar-footer { + background-image: linear-gradient(180deg, #e42112, #e42112 50%, transparent 50%); } + .bar.bar-balanced { + border-color: #28a54c; + background-color: #33cd5f; + background-image: linear-gradient(0deg, #28a54c, #28a54c 50%, transparent 50%); + color: #fff; } + .bar.bar-balanced .title { + color: #fff; } + .bar.bar-balanced.bar-footer { + background-image: linear-gradient(180deg, #28a54c, #28a54c 50%, transparent 50%); } + .bar.bar-energized { + border-color: #e6b500; + background-color: #ffc900; + background-image: linear-gradient(0deg, #e6b500, #e6b500 50%, transparent 50%); + color: #fff; } + .bar.bar-energized .title { + color: #fff; } + .bar.bar-energized.bar-footer { + background-image: linear-gradient(180deg, #e6b500, #e6b500 50%, transparent 50%); } + .bar.bar-royal { + border-color: #6b46e5; + background-color: #886aea; + background-image: linear-gradient(0deg, #6b46e5, #6b46e5 50%, transparent 50%); + color: #fff; } + .bar.bar-royal .title { + color: #fff; } + .bar.bar-royal.bar-footer { + background-image: linear-gradient(180deg, #6b46e5, #6b46e5 50%, transparent 50%); } + .bar.bar-dark { + border-color: #111; + background-color: #444444; + background-image: linear-gradient(0deg, #111, #111 50%, transparent 50%); + color: #fff; } + .bar.bar-dark .title { + color: #fff; } + .bar.bar-dark.bar-footer { + background-image: linear-gradient(180deg, #111, #111 50%, transparent 50%); } + .bar .title { + display: block; + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 0; + overflow: hidden; + margin: 0 10px; + min-width: 30px; + height: 43px; + text-align: center; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 17px; + font-weight: 500; + line-height: 44px; } + .bar .title.title-left { + text-align: left; } + .bar .title.title-right { + text-align: right; } + .bar .title a { + color: inherit; } + .bar .button, .bar button { + z-index: 1; + padding: 0 8px; + min-width: initial; + min-height: 31px; + font-weight: 400; + font-size: 13px; + line-height: 32px; } + .bar .button.button-icon:before, + .bar .button .icon:before, + .bar .button .icon-help:before, + .bar .button .icon-alert:before, + .bar .button #menu .footer .icon-help:before, #menu .footer + .bar .button .icon-help:before, .bar .button.icon:before, .bar .button.icon-help:before, .bar .button.icon-alert:before, .bar #menu .footer .button.icon-help:before, #menu .footer .bar .button.icon-help:before, .bar .button.icon-left:before, .bar .button.icon-right:before, .bar button.button-icon:before, + .bar button .icon:before, + .bar button .icon-help:before, + .bar button .icon-alert:before, + .bar button #menu .footer .icon-help:before, #menu .footer + .bar button .icon-help:before, .bar button.icon:before, .bar button.icon-help:before, .bar button.icon-alert:before, .bar #menu .footer button.icon-help:before, #menu .footer .bar button.icon-help:before, .bar button.icon-left:before, .bar button.icon-right:before { + padding-right: 2px; + padding-left: 2px; + font-size: 20px; + line-height: 32px; } + .bar .button.button-icon, .bar button.button-icon { + font-size: 17px; } + .bar .button.button-icon .icon:before, .bar .button.button-icon .icon-help:before, .bar .button.button-icon .icon-alert:before, .bar .button.button-icon #menu .footer .icon-help:before, #menu .footer .bar .button.button-icon .icon-help:before, .bar .button.button-icon:before, .bar .button.button-icon.icon-left:before, .bar .button.button-icon.icon-right:before, .bar button.button-icon .icon:before, .bar button.button-icon .icon-help:before, .bar button.button-icon .icon-alert:before, .bar button.button-icon #menu .footer .icon-help:before, #menu .footer .bar button.button-icon .icon-help:before, .bar button.button-icon:before, .bar button.button-icon.icon-left:before, .bar button.button-icon.icon-right:before { + vertical-align: top; + font-size: 32px; + line-height: 32px; } + .bar .button.button-clear, .bar .button.button-text, .bar button.button-clear, .bar button.button-text { + padding-right: 2px; + padding-left: 2px; + font-weight: 300; + font-size: 17px; } + .bar .button.button-clear .icon:before, .bar .button.button-text .icon:before, .bar .button.button-clear .icon-help:before, .bar .button.button-text .icon-help:before, .bar .button.button-clear .icon-alert:before, .bar .button.button-text .icon-alert:before, .bar .button.button-clear #menu .footer .icon-help:before, #menu .footer .bar .button.button-clear .icon-help:before, .bar .button.button-text #menu .footer .icon-help:before, #menu .footer .bar .button.button-text .icon-help:before, .bar .button.button-clear.icon:before, .bar .button.icon.button-text:before, .bar .button.button-text.icon-help:before, .bar .button.button-text.icon-alert:before, .bar #menu .footer .button.button-text.icon-help:before, #menu .footer .bar .button.button-text.icon-help:before, .bar .button.button-clear.icon-help:before, .bar .button.button-clear.icon-alert:before, .bar #menu .footer .button.button-clear.icon-help:before, #menu .footer .bar .button.button-clear.icon-help:before, .bar .button.button-clear.icon-left:before, .bar .button.icon-left.button-text:before, .bar .button.button-clear.icon-right:before, .bar .button.icon-right.button-text:before, .bar button.button-clear .icon:before, .bar button.button-text .icon:before, .bar button.button-clear .icon-help:before, .bar button.button-text .icon-help:before, .bar button.button-clear .icon-alert:before, .bar button.button-text .icon-alert:before, .bar button.button-clear #menu .footer .icon-help:before, #menu .footer .bar button.button-clear .icon-help:before, .bar button.button-text #menu .footer .icon-help:before, #menu .footer .bar button.button-text .icon-help:before, .bar button.button-clear.icon:before, .bar button.icon.button-text:before, .bar button.button-text.icon-help:before, .bar button.button-text.icon-alert:before, .bar #menu .footer button.button-text.icon-help:before, #menu .footer .bar button.button-text.icon-help:before, .bar button.button-clear.icon-help:before, .bar button.button-clear.icon-alert:before, .bar #menu .footer button.button-clear.icon-help:before, #menu .footer .bar button.button-clear.icon-help:before, .bar button.button-clear.icon-left:before, .bar button.icon-left.button-text:before, .bar button.button-clear.icon-right:before, .bar button.icon-right.button-text:before { + font-size: 32px; + line-height: 32px; } + .bar .button.back-button, .bar button.back-button { + display: block; + margin-right: 5px; + padding: 0; + white-space: nowrap; + font-weight: 400; } + .bar .button.back-button.active, .bar .button.back-button.activated, .bar button.back-button.active, .bar button.back-button.activated { + opacity: 0.2; } + .bar .button-bar > .button, + .bar .buttons > .button { + min-height: 31px; + line-height: 32px; } + .bar .button-bar + .button, + .bar .button + .button-bar { + margin-left: 5px; } + .bar .buttons, + .bar .buttons.primary-buttons, + .bar .buttons.secondary-buttons { + display: inherit; } + .bar .buttons span { + display: inline-block; } + .bar .buttons-left span { + margin-right: 5px; + display: inherit; } + .bar .buttons-right span { + margin-left: 5px; + display: inherit; } + .bar .title + .button:last-child, + .bar > .button + .button:last-child, + .bar > .button.pull-right, .popover-helptip + .bar > .button.icon.icon-right, .popover-helptip + .bar > .button.icon-right.icon-help, .popover-helptip + .bar > .button.icon-right.icon-alert, .popover-helptip #menu .footer + .bar > .button.icon-right.icon-help, #menu .footer .popover-helptip + .bar > .button.icon-right.icon-help, .popover-helptip + .bar > .button.icon.icon-center, .popover-helptip + .bar > .button.icon-center.icon-help, .popover-helptip + .bar > .button.icon-center.icon-alert, .popover-helptip #menu .footer + .bar > .button.icon-center.icon-help, #menu .footer .popover-helptip + .bar > .button.icon-center.icon-help, .popover-helptip + .bar > .button.icon.icon-bottom-right, .popover-helptip + .bar > .button.icon-bottom-right.icon-help, .popover-helptip + .bar > .button.icon-bottom-right.icon-alert, .popover-helptip #menu .footer + .bar > .button.icon-bottom-right.icon-help, #menu .footer .popover-helptip + .bar > .button.icon-bottom-right.icon-help, .popover-helptip + .bar > .button.icon.icon-bottom-center, .popover-helptip + .bar > .button.icon-bottom-center.icon-help, .popover-helptip + .bar > .button.icon-bottom-center.icon-alert, .popover-helptip #menu .footer + .bar > .button.icon-bottom-center.icon-help, #menu .footer .popover-helptip + .bar > .button.icon-bottom-center.icon-help, + .bar .buttons.pull-right, + .bar .popover-helptip .buttons.icon.icon-right, .popover-helptip + .bar .buttons.icon.icon-right, + .bar .popover-helptip .buttons.icon-right.icon-help, .popover-helptip + .bar .buttons.icon-right.icon-help, + .bar .popover-helptip .buttons.icon-right.icon-alert, .popover-helptip + .bar .buttons.icon-right.icon-alert, + .bar .popover-helptip #menu .footer .buttons.icon-right.icon-help, .popover-helptip #menu .footer + .bar .buttons.icon-right.icon-help, + .bar #menu .footer .popover-helptip .buttons.icon-right.icon-help, #menu .footer .popover-helptip + .bar .buttons.icon-right.icon-help, + .bar .popover-helptip .buttons.icon.icon-center, .popover-helptip + .bar .buttons.icon.icon-center, + .bar .popover-helptip .buttons.icon-center.icon-help, .popover-helptip + .bar .buttons.icon-center.icon-help, + .bar .popover-helptip .buttons.icon-center.icon-alert, .popover-helptip + .bar .buttons.icon-center.icon-alert, + .bar .popover-helptip #menu .footer .buttons.icon-center.icon-help, .popover-helptip #menu .footer + .bar .buttons.icon-center.icon-help, + .bar #menu .footer .popover-helptip .buttons.icon-center.icon-help, #menu .footer .popover-helptip + .bar .buttons.icon-center.icon-help, + .bar .popover-helptip .buttons.icon.icon-bottom-right, .popover-helptip + .bar .buttons.icon.icon-bottom-right, + .bar .popover-helptip .buttons.icon-bottom-right.icon-help, .popover-helptip + .bar .buttons.icon-bottom-right.icon-help, + .bar .popover-helptip .buttons.icon-bottom-right.icon-alert, .popover-helptip + .bar .buttons.icon-bottom-right.icon-alert, + .bar .popover-helptip #menu .footer .buttons.icon-bottom-right.icon-help, .popover-helptip #menu .footer + .bar .buttons.icon-bottom-right.icon-help, + .bar #menu .footer .popover-helptip .buttons.icon-bottom-right.icon-help, #menu .footer .popover-helptip + .bar .buttons.icon-bottom-right.icon-help, + .bar .popover-helptip .buttons.icon.icon-bottom-center, .popover-helptip + .bar .buttons.icon.icon-bottom-center, + .bar .popover-helptip .buttons.icon-bottom-center.icon-help, .popover-helptip + .bar .buttons.icon-bottom-center.icon-help, + .bar .popover-helptip .buttons.icon-bottom-center.icon-alert, .popover-helptip + .bar .buttons.icon-bottom-center.icon-alert, + .bar .popover-helptip #menu .footer .buttons.icon-bottom-center.icon-help, .popover-helptip #menu .footer + .bar .buttons.icon-bottom-center.icon-help, + .bar #menu .footer .popover-helptip .buttons.icon-bottom-center.icon-help, #menu .footer .popover-helptip + .bar .buttons.icon-bottom-center.icon-help, + .bar .title + .buttons { + position: absolute; + top: 5px; + right: 5px; + bottom: 5px; } + + .platform-android .nav-bar-has-subheader .bar { + background-image: none; } + + .platform-android .bar .back-button .icon:before, .platform-android .bar .back-button .icon-help:before, .platform-android .bar .back-button .icon-alert:before, .platform-android .bar .back-button #menu .footer .icon-help:before, #menu .footer .platform-android .bar .back-button .icon-help:before { + font-size: 24px; } + + .platform-android .bar .title { + font-size: 19px; + line-height: 44px; } + + .bar-light .button { + border-color: #ddd; + background-color: white; + color: #444; } + .bar-light .button:hover { + color: #444; + text-decoration: none; } + .bar-light .button.active, .bar-light .button.activated { + border-color: #ccc; + background-color: #fafafa; } + .bar-light .button.button-clear, .bar-light .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #444; + font-size: 17px; } + .bar-light .button.button-icon { + border-color: transparent; + background: none; } + + .bar-stable .button { + border-color: #b2b2b2; + background-color: #f8f8f8; + color: #444; } + .bar-stable .button:hover { + color: #444; + text-decoration: none; } + .bar-stable .button.active, .bar-stable .button.activated { + border-color: #a2a2a2; + background-color: #e5e5e5; } + .bar-stable .button.button-clear, .bar-stable .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #444; + font-size: 17px; } + .bar-stable .button.button-icon { + border-color: transparent; + background: none; } + + .bar-positive .button { + border-color: #0c60ee; + background-color: #387ef5; + color: #fff; } + .bar-positive .button:hover { + color: #fff; + text-decoration: none; } + .bar-positive .button.active, .bar-positive .button.activated { + border-color: #0c60ee; + background-color: #0c60ee; } + .bar-positive .button.button-clear, .bar-positive .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-positive .button.button-icon { + border-color: transparent; + background: none; } + + .bar-calm .button { + border-color: #0a9dc7; + background-color: #11c1f3; + color: #fff; } + .bar-calm .button:hover { + color: #fff; + text-decoration: none; } + .bar-calm .button.active, .bar-calm .button.activated { + border-color: #0a9dc7; + background-color: #0a9dc7; } + .bar-calm .button.button-clear, .bar-calm .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-calm .button.button-icon { + border-color: transparent; + background: none; } + + .bar-assertive .button { + border-color: #e42112; + background-color: #ef473a; + color: #fff; } + .bar-assertive .button:hover { + color: #fff; + text-decoration: none; } + .bar-assertive .button.active, .bar-assertive .button.activated { + border-color: #e42112; + background-color: #e42112; } + .bar-assertive .button.button-clear, .bar-assertive .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-assertive .button.button-icon { + border-color: transparent; + background: none; } + + .bar-balanced .button { + border-color: #28a54c; + background-color: #33cd5f; + color: #fff; } + .bar-balanced .button:hover { + color: #fff; + text-decoration: none; } + .bar-balanced .button.active, .bar-balanced .button.activated { + border-color: #28a54c; + background-color: #28a54c; } + .bar-balanced .button.button-clear, .bar-balanced .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-balanced .button.button-icon { + border-color: transparent; + background: none; } + + .bar-energized .button { + border-color: #e6b500; + background-color: #ffc900; + color: #fff; } + .bar-energized .button:hover { + color: #fff; + text-decoration: none; } + .bar-energized .button.active, .bar-energized .button.activated { + border-color: #e6b500; + background-color: #e6b500; } + .bar-energized .button.button-clear, .bar-energized .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-energized .button.button-icon { + border-color: transparent; + background: none; } + + .bar-royal .button { + border-color: #6b46e5; + background-color: #886aea; + color: #fff; } + .bar-royal .button:hover { + color: #fff; + text-decoration: none; } + .bar-royal .button.active, .bar-royal .button.activated { + border-color: #6b46e5; + background-color: #6b46e5; } + .bar-royal .button.button-clear, .bar-royal .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-royal .button.button-icon { + border-color: transparent; + background: none; } + + .bar-dark .button { + border-color: #111; + background-color: #444444; + color: #fff; } + .bar-dark .button:hover { + color: #fff; + text-decoration: none; } + .bar-dark .button.active, .bar-dark .button.activated { + border-color: #000; + background-color: #262626; } + .bar-dark .button.button-clear, .bar-dark .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-dark .button.button-icon { + border-color: transparent; + background: none; } + + .bar-header { + top: 0; + border-top-width: 0; + border-bottom-width: 1px; } + .bar-header.has-tabs-top { + border-bottom-width: 0px; + background-image: none; } + + .tabs-top .bar-header { + border-bottom-width: 0px; + background-image: none; } + + .bar-footer { + bottom: 0; + border-top-width: 1px; + border-bottom-width: 0; + background-position: top; + height: 44px; } + .bar-footer.item-input-inset { + position: absolute; } + .bar-footer .title { + height: 43px; + line-height: 44px; } + + .bar-tabs { + padding: 0; } + + .bar-subheader { + top: 44px; + height: 44px; } + .bar-subheader .title { + height: 43px; + line-height: 44px; } + + .bar-subfooter { + bottom: 44px; + height: 44px; } + .bar-subfooter .title { + height: 43px; + line-height: 44px; } + + .nav-bar-block { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 9; } + + .bar .back-button.hide, + .bar .buttons .hide { + display: none; } + + .nav-bar-tabs-top .bar { + background-image: none; } + + /** + * Tabs + * -------------------------------------------------- + * A navigation bar with any number of tab items supported. + */ + .tabs { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-direction: normal; + -webkit-box-orient: horizontal; + -webkit-flex-direction: horizontal; + -moz-flex-direction: horizontal; + -ms-flex-direction: horizontal; + flex-direction: horizontal; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + -moz-justify-content: center; + justify-content: center; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + border-color: #b2b2b2; + background-color: #f8f8f8; + background-image: linear-gradient(0deg, #b2b2b2, #b2b2b2 50%, transparent 50%); + color: #444; + position: absolute; + bottom: 0; + z-index: 5; + width: 100%; + height: 49px; + border-style: solid; + border-top-width: 1px; + background-size: 0; + line-height: 49px; } + .tabs .tab-item .badge { + background-color: #444; + color: #f8f8f8; } + @media (min--moz-device-pixel-ratio: 1.5), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi), (min-resolution: 1.5dppx) { + .tabs { + padding-top: 2px; + border-top: none !important; + border-bottom: none; + background-position: top; + background-size: 100% 1px; + background-repeat: no-repeat; } } + + /* Allow parent element of tabs to define color, or just the tab itself */ + .tabs-light > .tabs, + .tabs.tabs-light { + border-color: #ddd; + background-color: #fff; + background-image: linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%); + color: #444; } + .tabs-light > .tabs .tab-item .badge, + .tabs.tabs-light .tab-item .badge { + background-color: #444; + color: #fff; } + + .tabs-stable > .tabs, + .tabs.tabs-stable { + border-color: #b2b2b2; + background-color: #f8f8f8; + background-image: linear-gradient(0deg, #b2b2b2, #b2b2b2 50%, transparent 50%); + color: #444; } + .tabs-stable > .tabs .tab-item .badge, + .tabs.tabs-stable .tab-item .badge { + background-color: #444; + color: #f8f8f8; } + + .tabs-positive > .tabs, + .tabs.tabs-positive { + border-color: #0c60ee; + background-color: #387ef5; + background-image: linear-gradient(0deg, #0c60ee, #0c60ee 50%, transparent 50%); + color: #fff; } + .tabs-positive > .tabs .tab-item .badge, + .tabs.tabs-positive .tab-item .badge { + background-color: #fff; + color: #387ef5; } + + .tabs-calm > .tabs, + .tabs.tabs-calm { + border-color: #0a9dc7; + background-color: #11c1f3; + background-image: linear-gradient(0deg, #0a9dc7, #0a9dc7 50%, transparent 50%); + color: #fff; } + .tabs-calm > .tabs .tab-item .badge, + .tabs.tabs-calm .tab-item .badge { + background-color: #fff; + color: #11c1f3; } + + .tabs-assertive > .tabs, + .tabs.tabs-assertive { + border-color: #e42112; + background-color: #ef473a; + background-image: linear-gradient(0deg, #e42112, #e42112 50%, transparent 50%); + color: #fff; } + .tabs-assertive > .tabs .tab-item .badge, + .tabs.tabs-assertive .tab-item .badge { + background-color: #fff; + color: #ef473a; } + + .tabs-balanced > .tabs, + .tabs.tabs-balanced { + border-color: #28a54c; + background-color: #33cd5f; + background-image: linear-gradient(0deg, #28a54c, #28a54c 50%, transparent 50%); + color: #fff; } + .tabs-balanced > .tabs .tab-item .badge, + .tabs.tabs-balanced .tab-item .badge { + background-color: #fff; + color: #33cd5f; } + + .tabs-energized > .tabs, + .tabs.tabs-energized { + border-color: #e6b500; + background-color: #ffc900; + background-image: linear-gradient(0deg, #e6b500, #e6b500 50%, transparent 50%); + color: #fff; } + .tabs-energized > .tabs .tab-item .badge, + .tabs.tabs-energized .tab-item .badge { + background-color: #fff; + color: #ffc900; } + + .tabs-royal > .tabs, + .tabs.tabs-royal { + border-color: #6b46e5; + background-color: #886aea; + background-image: linear-gradient(0deg, #6b46e5, #6b46e5 50%, transparent 50%); + color: #fff; } + .tabs-royal > .tabs .tab-item .badge, + .tabs.tabs-royal .tab-item .badge { + background-color: #fff; + color: #886aea; } + + .tabs-dark > .tabs, + .tabs.tabs-dark { + border-color: #111; + background-color: #444; + background-image: linear-gradient(0deg, #111, #111 50%, transparent 50%); + color: #fff; } + .tabs-dark > .tabs .tab-item .badge, + .tabs.tabs-dark .tab-item .badge { + background-color: #fff; + color: #444; } + + .tabs-striped .tabs { + background-color: white; + background-image: none; + border: none; + border-bottom: 1px solid #ddd; + padding-top: 2px; } + + .tabs-striped .tab-item.tab-item-active, .tabs-striped .tab-item.active, .tabs-striped .tab-item.activated { + margin-top: -2px; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #444; } + .tabs-striped .tab-item.tab-item-active .badge, .tabs-striped .tab-item.active .badge, .tabs-striped .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-striped.tabs-light .tabs { + background-color: #fff; } + + .tabs-striped.tabs-light .tab-item { + color: rgba(68, 68, 68, 0.4); + opacity: 1; } + .tabs-striped.tabs-light .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-light .tab-item.tab-item-active, .tabs-striped.tabs-light .tab-item.active, .tabs-striped.tabs-light .tab-item.activated { + margin-top: -2px; + color: #444; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #444; } + + .tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-striped.tabs-stable .tabs { + background-color: #f8f8f8; } + + .tabs-striped.tabs-stable .tab-item { + color: rgba(68, 68, 68, 0.4); + opacity: 1; } + .tabs-striped.tabs-stable .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-stable .tab-item.tab-item-active, .tabs-striped.tabs-stable .tab-item.active, .tabs-striped.tabs-stable .tab-item.activated { + margin-top: -2px; + color: #444; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #444; } + + .tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-striped.tabs-positive .tabs { + background-color: #387ef5; } + + .tabs-striped.tabs-positive .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-positive .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-positive .tab-item.tab-item-active, .tabs-striped.tabs-positive .tab-item.active, .tabs-striped.tabs-positive .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } + + .tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-striped.tabs-calm .tabs { + background-color: #11c1f3; } + + .tabs-striped.tabs-calm .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-calm .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-calm .tab-item.tab-item-active, .tabs-striped.tabs-calm .tab-item.active, .tabs-striped.tabs-calm .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } + + .tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-striped.tabs-assertive .tabs { + background-color: #ef473a; } + + .tabs-striped.tabs-assertive .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-assertive .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-assertive .tab-item.tab-item-active, .tabs-striped.tabs-assertive .tab-item.active, .tabs-striped.tabs-assertive .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } + + .tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-striped.tabs-balanced .tabs { + background-color: #33cd5f; } + + .tabs-striped.tabs-balanced .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-balanced .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-balanced .tab-item.tab-item-active, .tabs-striped.tabs-balanced .tab-item.active, .tabs-striped.tabs-balanced .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } + + .tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-striped.tabs-energized .tabs { + background-color: #ffc900; } + + .tabs-striped.tabs-energized .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-energized .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-energized .tab-item.tab-item-active, .tabs-striped.tabs-energized .tab-item.active, .tabs-striped.tabs-energized .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } + + .tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-striped.tabs-royal .tabs { + background-color: #886aea; } + + .tabs-striped.tabs-royal .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-royal .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-royal .tab-item.tab-item-active, .tabs-striped.tabs-royal .tab-item.active, .tabs-striped.tabs-royal .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } + + .tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-striped.tabs-dark .tabs { + background-color: #444; } + + .tabs-striped.tabs-dark .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-dark .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-dark .tab-item.tab-item-active, .tabs-striped.tabs-dark .tab-item.active, .tabs-striped.tabs-dark .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } + + .tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-striped.tabs-background-light .tabs { + background-color: #fff; + background-image: none; } + + .tabs-striped.tabs-background-stable .tabs { + background-color: #f8f8f8; + background-image: none; } + + .tabs-striped.tabs-background-positive .tabs { + background-color: #387ef5; + background-image: none; } + + .tabs-striped.tabs-background-calm .tabs { + background-color: #11c1f3; + background-image: none; } + + .tabs-striped.tabs-background-assertive .tabs { + background-color: #ef473a; + background-image: none; } + + .tabs-striped.tabs-background-balanced .tabs { + background-color: #33cd5f; + background-image: none; } + + .tabs-striped.tabs-background-energized .tabs { + background-color: #ffc900; + background-image: none; } + + .tabs-striped.tabs-background-royal .tabs { + background-color: #886aea; + background-image: none; } + + .tabs-striped.tabs-background-dark .tabs { + background-color: #444; + background-image: none; } + + .tabs-striped.tabs-color-light .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-light .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-light .tab-item.tab-item-active, .tabs-striped.tabs-color-light .tab-item.active, .tabs-striped.tabs-color-light .tab-item.activated { + margin-top: -2px; + color: #fff; + border: 0 solid #fff; + border-top-width: 2px; } + .tabs-striped.tabs-color-light .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-light .tab-item.active .badge, .tabs-striped.tabs-color-light .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-striped.tabs-color-stable .tab-item { + color: rgba(248, 248, 248, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-stable .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-stable .tab-item.tab-item-active, .tabs-striped.tabs-color-stable .tab-item.active, .tabs-striped.tabs-color-stable .tab-item.activated { + margin-top: -2px; + color: #f8f8f8; + border: 0 solid #f8f8f8; + border-top-width: 2px; } + .tabs-striped.tabs-color-stable .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-stable .tab-item.active .badge, .tabs-striped.tabs-color-stable .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-striped.tabs-color-positive .tab-item { + color: rgba(56, 126, 245, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-positive .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-positive .tab-item.tab-item-active, .tabs-striped.tabs-color-positive .tab-item.active, .tabs-striped.tabs-color-positive .tab-item.activated { + margin-top: -2px; + color: #387ef5; + border: 0 solid #387ef5; + border-top-width: 2px; } + .tabs-striped.tabs-color-positive .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-positive .tab-item.active .badge, .tabs-striped.tabs-color-positive .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-striped.tabs-color-calm .tab-item { + color: rgba(17, 193, 243, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-calm .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-calm .tab-item.tab-item-active, .tabs-striped.tabs-color-calm .tab-item.active, .tabs-striped.tabs-color-calm .tab-item.activated { + margin-top: -2px; + color: #11c1f3; + border: 0 solid #11c1f3; + border-top-width: 2px; } + .tabs-striped.tabs-color-calm .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-calm .tab-item.active .badge, .tabs-striped.tabs-color-calm .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-striped.tabs-color-assertive .tab-item { + color: rgba(239, 71, 58, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-assertive .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-assertive .tab-item.tab-item-active, .tabs-striped.tabs-color-assertive .tab-item.active, .tabs-striped.tabs-color-assertive .tab-item.activated { + margin-top: -2px; + color: #ef473a; + border: 0 solid #ef473a; + border-top-width: 2px; } + .tabs-striped.tabs-color-assertive .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-assertive .tab-item.active .badge, .tabs-striped.tabs-color-assertive .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-striped.tabs-color-balanced .tab-item { + color: rgba(51, 205, 95, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-balanced .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-balanced .tab-item.tab-item-active, .tabs-striped.tabs-color-balanced .tab-item.active, .tabs-striped.tabs-color-balanced .tab-item.activated { + margin-top: -2px; + color: #33cd5f; + border: 0 solid #33cd5f; + border-top-width: 2px; } + .tabs-striped.tabs-color-balanced .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-balanced .tab-item.active .badge, .tabs-striped.tabs-color-balanced .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-striped.tabs-color-energized .tab-item { + color: rgba(255, 201, 0, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-energized .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-energized .tab-item.tab-item-active, .tabs-striped.tabs-color-energized .tab-item.active, .tabs-striped.tabs-color-energized .tab-item.activated { + margin-top: -2px; + color: #ffc900; + border: 0 solid #ffc900; + border-top-width: 2px; } + .tabs-striped.tabs-color-energized .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-energized .tab-item.active .badge, .tabs-striped.tabs-color-energized .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-striped.tabs-color-royal .tab-item { + color: rgba(136, 106, 234, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-royal .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-royal .tab-item.tab-item-active, .tabs-striped.tabs-color-royal .tab-item.active, .tabs-striped.tabs-color-royal .tab-item.activated { + margin-top: -2px; + color: #886aea; + border: 0 solid #886aea; + border-top-width: 2px; } + .tabs-striped.tabs-color-royal .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-royal .tab-item.active .badge, .tabs-striped.tabs-color-royal .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-striped.tabs-color-dark .tab-item { + color: rgba(68, 68, 68, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-dark .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-dark .tab-item.tab-item-active, .tabs-striped.tabs-color-dark .tab-item.active, .tabs-striped.tabs-color-dark .tab-item.activated { + margin-top: -2px; + color: #444; + border: 0 solid #444; + border-top-width: 2px; } + .tabs-striped.tabs-color-dark .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-dark .tab-item.active .badge, .tabs-striped.tabs-color-dark .tab-item.activated .badge { + top: 2px; + opacity: 1; } + + .tabs-background-light .tabs, + .tabs-background-light > .tabs { + background-color: #fff; + background-image: linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%); + border-color: #ddd; } + + .tabs-background-stable .tabs, + .tabs-background-stable > .tabs { + background-color: #f8f8f8; + background-image: linear-gradient(0deg, #b2b2b2, #b2b2b2 50%, transparent 50%); + border-color: #b2b2b2; } + + .tabs-background-positive .tabs, + .tabs-background-positive > .tabs { + background-color: #387ef5; + background-image: linear-gradient(0deg, #0c60ee, #0c60ee 50%, transparent 50%); + border-color: #0c60ee; } + + .tabs-background-calm .tabs, + .tabs-background-calm > .tabs { + background-color: #11c1f3; + background-image: linear-gradient(0deg, #0a9dc7, #0a9dc7 50%, transparent 50%); + border-color: #0a9dc7; } + + .tabs-background-assertive .tabs, + .tabs-background-assertive > .tabs { + background-color: #ef473a; + background-image: linear-gradient(0deg, #e42112, #e42112 50%, transparent 50%); + border-color: #e42112; } + + .tabs-background-balanced .tabs, + .tabs-background-balanced > .tabs { + background-color: #33cd5f; + background-image: linear-gradient(0deg, #28a54c, #28a54c 50%, transparent 50%); + border-color: #28a54c; } + + .tabs-background-energized .tabs, + .tabs-background-energized > .tabs { + background-color: #ffc900; + background-image: linear-gradient(0deg, #e6b500, #e6b500 50%, transparent 50%); + border-color: #e6b500; } + + .tabs-background-royal .tabs, + .tabs-background-royal > .tabs { + background-color: #886aea; + background-image: linear-gradient(0deg, #6b46e5, #6b46e5 50%, transparent 50%); + border-color: #6b46e5; } + + .tabs-background-dark .tabs, + .tabs-background-dark > .tabs { + background-color: #444; + background-image: linear-gradient(0deg, #111, #111 50%, transparent 50%); + border-color: #111; } + + .tabs-color-light .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-color-light .tab-item .badge { + opacity: 0.4; } + .tabs-color-light .tab-item.tab-item-active, .tabs-color-light .tab-item.active, .tabs-color-light .tab-item.activated { + color: #fff; + border: 0 solid #fff; } + .tabs-color-light .tab-item.tab-item-active .badge, .tabs-color-light .tab-item.active .badge, .tabs-color-light .tab-item.activated .badge { + opacity: 1; } + + .tabs-color-stable .tab-item { + color: rgba(248, 248, 248, 0.4); + opacity: 1; } + .tabs-color-stable .tab-item .badge { + opacity: 0.4; } + .tabs-color-stable .tab-item.tab-item-active, .tabs-color-stable .tab-item.active, .tabs-color-stable .tab-item.activated { + color: #f8f8f8; + border: 0 solid #f8f8f8; } + .tabs-color-stable .tab-item.tab-item-active .badge, .tabs-color-stable .tab-item.active .badge, .tabs-color-stable .tab-item.activated .badge { + opacity: 1; } + + .tabs-color-positive .tab-item { + color: rgba(56, 126, 245, 0.4); + opacity: 1; } + .tabs-color-positive .tab-item .badge { + opacity: 0.4; } + .tabs-color-positive .tab-item.tab-item-active, .tabs-color-positive .tab-item.active, .tabs-color-positive .tab-item.activated { + color: #387ef5; + border: 0 solid #387ef5; } + .tabs-color-positive .tab-item.tab-item-active .badge, .tabs-color-positive .tab-item.active .badge, .tabs-color-positive .tab-item.activated .badge { + opacity: 1; } + + .tabs-color-calm .tab-item { + color: rgba(17, 193, 243, 0.4); + opacity: 1; } + .tabs-color-calm .tab-item .badge { + opacity: 0.4; } + .tabs-color-calm .tab-item.tab-item-active, .tabs-color-calm .tab-item.active, .tabs-color-calm .tab-item.activated { + color: #11c1f3; + border: 0 solid #11c1f3; } + .tabs-color-calm .tab-item.tab-item-active .badge, .tabs-color-calm .tab-item.active .badge, .tabs-color-calm .tab-item.activated .badge { + opacity: 1; } + + .tabs-color-assertive .tab-item { + color: rgba(239, 71, 58, 0.4); + opacity: 1; } + .tabs-color-assertive .tab-item .badge { + opacity: 0.4; } + .tabs-color-assertive .tab-item.tab-item-active, .tabs-color-assertive .tab-item.active, .tabs-color-assertive .tab-item.activated { + color: #ef473a; + border: 0 solid #ef473a; } + .tabs-color-assertive .tab-item.tab-item-active .badge, .tabs-color-assertive .tab-item.active .badge, .tabs-color-assertive .tab-item.activated .badge { + opacity: 1; } + + .tabs-color-balanced .tab-item { + color: rgba(51, 205, 95, 0.4); + opacity: 1; } + .tabs-color-balanced .tab-item .badge { + opacity: 0.4; } + .tabs-color-balanced .tab-item.tab-item-active, .tabs-color-balanced .tab-item.active, .tabs-color-balanced .tab-item.activated { + color: #33cd5f; + border: 0 solid #33cd5f; } + .tabs-color-balanced .tab-item.tab-item-active .badge, .tabs-color-balanced .tab-item.active .badge, .tabs-color-balanced .tab-item.activated .badge { + opacity: 1; } + + .tabs-color-energized .tab-item { + color: rgba(255, 201, 0, 0.4); + opacity: 1; } + .tabs-color-energized .tab-item .badge { + opacity: 0.4; } + .tabs-color-energized .tab-item.tab-item-active, .tabs-color-energized .tab-item.active, .tabs-color-energized .tab-item.activated { + color: #ffc900; + border: 0 solid #ffc900; } + .tabs-color-energized .tab-item.tab-item-active .badge, .tabs-color-energized .tab-item.active .badge, .tabs-color-energized .tab-item.activated .badge { + opacity: 1; } + + .tabs-color-royal .tab-item { + color: rgba(136, 106, 234, 0.4); + opacity: 1; } + .tabs-color-royal .tab-item .badge { + opacity: 0.4; } + .tabs-color-royal .tab-item.tab-item-active, .tabs-color-royal .tab-item.active, .tabs-color-royal .tab-item.activated { + color: #886aea; + border: 0 solid #886aea; } + .tabs-color-royal .tab-item.tab-item-active .badge, .tabs-color-royal .tab-item.active .badge, .tabs-color-royal .tab-item.activated .badge { + opacity: 1; } + + .tabs-color-dark .tab-item { + color: rgba(68, 68, 68, 0.4); + opacity: 1; } + .tabs-color-dark .tab-item .badge { + opacity: 0.4; } + .tabs-color-dark .tab-item.tab-item-active, .tabs-color-dark .tab-item.active, .tabs-color-dark .tab-item.activated { + color: #444; + border: 0 solid #444; } + .tabs-color-dark .tab-item.tab-item-active .badge, .tabs-color-dark .tab-item.active .badge, .tabs-color-dark .tab-item.activated .badge { + opacity: 1; } + + ion-tabs.tabs-color-active-light .tab-item { + color: #444; } + ion-tabs.tabs-color-active-light .tab-item.tab-item-active, ion-tabs.tabs-color-active-light .tab-item.active, ion-tabs.tabs-color-active-light .tab-item.activated { + color: #fff; } + + ion-tabs.tabs-striped.tabs-color-active-light .tab-item.tab-item-active, ion-tabs.tabs-striped.tabs-color-active-light .tab-item.active, ion-tabs.tabs-striped.tabs-color-active-light .tab-item.activated { + border-color: #fff; + color: #fff; } + + ion-tabs.tabs-color-active-stable .tab-item { + color: #444; } + ion-tabs.tabs-color-active-stable .tab-item.tab-item-active, ion-tabs.tabs-color-active-stable .tab-item.active, ion-tabs.tabs-color-active-stable .tab-item.activated { + color: #f8f8f8; } + + ion-tabs.tabs-striped.tabs-color-active-stable .tab-item.tab-item-active, ion-tabs.tabs-striped.tabs-color-active-stable .tab-item.active, ion-tabs.tabs-striped.tabs-color-active-stable .tab-item.activated { + border-color: #f8f8f8; + color: #f8f8f8; } + + ion-tabs.tabs-color-active-positive .tab-item { + color: #444; } + ion-tabs.tabs-color-active-positive .tab-item.tab-item-active, ion-tabs.tabs-color-active-positive .tab-item.active, ion-tabs.tabs-color-active-positive .tab-item.activated { + color: #387ef5; } + + ion-tabs.tabs-striped.tabs-color-active-positive .tab-item.tab-item-active, ion-tabs.tabs-striped.tabs-color-active-positive .tab-item.active, ion-tabs.tabs-striped.tabs-color-active-positive .tab-item.activated { + border-color: #387ef5; + color: #387ef5; } + + ion-tabs.tabs-color-active-calm .tab-item { + color: #444; } + ion-tabs.tabs-color-active-calm .tab-item.tab-item-active, ion-tabs.tabs-color-active-calm .tab-item.active, ion-tabs.tabs-color-active-calm .tab-item.activated { + color: #11c1f3; } + + ion-tabs.tabs-striped.tabs-color-active-calm .tab-item.tab-item-active, ion-tabs.tabs-striped.tabs-color-active-calm .tab-item.active, ion-tabs.tabs-striped.tabs-color-active-calm .tab-item.activated { + border-color: #11c1f3; + color: #11c1f3; } + + ion-tabs.tabs-color-active-assertive .tab-item { + color: #444; } + ion-tabs.tabs-color-active-assertive .tab-item.tab-item-active, ion-tabs.tabs-color-active-assertive .tab-item.active, ion-tabs.tabs-color-active-assertive .tab-item.activated { + color: #ef473a; } + + ion-tabs.tabs-striped.tabs-color-active-assertive .tab-item.tab-item-active, ion-tabs.tabs-striped.tabs-color-active-assertive .tab-item.active, ion-tabs.tabs-striped.tabs-color-active-assertive .tab-item.activated { + border-color: #ef473a; + color: #ef473a; } + + ion-tabs.tabs-color-active-balanced .tab-item { + color: #444; } + ion-tabs.tabs-color-active-balanced .tab-item.tab-item-active, ion-tabs.tabs-color-active-balanced .tab-item.active, ion-tabs.tabs-color-active-balanced .tab-item.activated { + color: #33cd5f; } + + ion-tabs.tabs-striped.tabs-color-active-balanced .tab-item.tab-item-active, ion-tabs.tabs-striped.tabs-color-active-balanced .tab-item.active, ion-tabs.tabs-striped.tabs-color-active-balanced .tab-item.activated { + border-color: #33cd5f; + color: #33cd5f; } + + ion-tabs.tabs-color-active-energized .tab-item { + color: #444; } + ion-tabs.tabs-color-active-energized .tab-item.tab-item-active, ion-tabs.tabs-color-active-energized .tab-item.active, ion-tabs.tabs-color-active-energized .tab-item.activated { + color: #ffc900; } + + ion-tabs.tabs-striped.tabs-color-active-energized .tab-item.tab-item-active, ion-tabs.tabs-striped.tabs-color-active-energized .tab-item.active, ion-tabs.tabs-striped.tabs-color-active-energized .tab-item.activated { + border-color: #ffc900; + color: #ffc900; } + + ion-tabs.tabs-color-active-royal .tab-item { + color: #444; } + ion-tabs.tabs-color-active-royal .tab-item.tab-item-active, ion-tabs.tabs-color-active-royal .tab-item.active, ion-tabs.tabs-color-active-royal .tab-item.activated { + color: #886aea; } + + ion-tabs.tabs-striped.tabs-color-active-royal .tab-item.tab-item-active, ion-tabs.tabs-striped.tabs-color-active-royal .tab-item.active, ion-tabs.tabs-striped.tabs-color-active-royal .tab-item.activated { + border-color: #886aea; + color: #886aea; } + + ion-tabs.tabs-color-active-dark .tab-item { + color: #fff; } + ion-tabs.tabs-color-active-dark .tab-item.tab-item-active, ion-tabs.tabs-color-active-dark .tab-item.active, ion-tabs.tabs-color-active-dark .tab-item.activated { + color: #444; } + + ion-tabs.tabs-striped.tabs-color-active-dark .tab-item.tab-item-active, ion-tabs.tabs-striped.tabs-color-active-dark .tab-item.active, ion-tabs.tabs-striped.tabs-color-active-dark .tab-item.activated { + border-color: #444; + color: #444; } + + .tabs-top.tabs-striped { + padding-bottom: 0; } + .tabs-top.tabs-striped .tab-item { + background: transparent; + -webkit-transition: color .1s ease; + -moz-transition: color .1s ease; + -ms-transition: color .1s ease; + -o-transition: color .1s ease; + transition: color .1s ease; } + .tabs-top.tabs-striped .tab-item.tab-item-active, .tabs-top.tabs-striped .tab-item.active, .tabs-top.tabs-striped .tab-item.activated { + margin-top: 1px; + border-width: 0px 0px 2px 0px !important; + border-style: solid; } + .tabs-top.tabs-striped .tab-item.tab-item-active > .badge, .tabs-top.tabs-striped .tab-item.tab-item-active > i, .tabs-top.tabs-striped .tab-item.active > .badge, .tabs-top.tabs-striped .tab-item.active > i, .tabs-top.tabs-striped .tab-item.activated > .badge, .tabs-top.tabs-striped .tab-item.activated > i { + margin-top: -1px; } + .tabs-top.tabs-striped .tab-item .badge { + -webkit-transition: color .2s ease; + -moz-transition: color .2s ease; + -ms-transition: color .2s ease; + -o-transition: color .2s ease; + transition: color .2s ease; } + .tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.tab-item-active .tab-title, .tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.tab-item-active i, .tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.active .tab-title, .tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.active i, .tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.activated .tab-title, .tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.activated i { + display: block; + margin-top: -1px; } + .tabs-top.tabs-striped.tabs-icon-left .tab-item { + margin-top: 1px; } + .tabs-top.tabs-striped.tabs-icon-left .tab-item.tab-item-active .tab-title, .tabs-top.tabs-striped.tabs-icon-left .tab-item.tab-item-active i, .tabs-top.tabs-striped.tabs-icon-left .tab-item.active .tab-title, .tabs-top.tabs-striped.tabs-icon-left .tab-item.active i, .tabs-top.tabs-striped.tabs-icon-left .tab-item.activated .tab-title, .tabs-top.tabs-striped.tabs-icon-left .tab-item.activated i { + margin-top: -0.1em; } + + /* Allow parent element to have tabs-top */ + /* If you change this, change platform.scss as well */ + .tabs-top > .tabs, + .tabs.tabs-top { + top: 44px; + padding-top: 0; + background-position: bottom; + border-top-width: 0; + border-bottom-width: 1px; } + .tabs-top > .tabs .tab-item.tab-item-active .badge, .tabs-top > .tabs .tab-item.active .badge, .tabs-top > .tabs .tab-item.activated .badge, + .tabs.tabs-top .tab-item.tab-item-active .badge, + .tabs.tabs-top .tab-item.active .badge, + .tabs.tabs-top .tab-item.activated .badge { + top: 4%; } + + .tabs-top ~ .bar-header { + border-bottom-width: 0; } + + .tab-item { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + display: block; + overflow: hidden; + max-width: 150px; + height: 100%; + color: inherit; + text-align: center; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: 400; + font-size: 14px; + font-family: "-apple-system", "Helvetica Neue", "Roboto", "Segoe UI", sans-serif; + opacity: 0.7; } + .tab-item:hover { + cursor: pointer; } + .tab-item.tab-hidden { + display: none; } + + .tabs-item-hide > .tabs, + .tabs.tabs-item-hide { + display: none; } + + .tabs-icon-top > .tabs .tab-item, + .tabs-icon-top.tabs .tab-item, + .tabs-icon-bottom > .tabs .tab-item, + .tabs-icon-bottom.tabs .tab-item { + font-size: 10px; + line-height: 14px; } + + .tab-item .icon, .tab-item .icon-help, .tab-item .icon-alert, .tab-item #menu .footer .icon-help, #menu .footer .tab-item .icon-help { + display: block; + margin: 0 auto; + height: 32px; + font-size: 32px; } + + .tabs-icon-left.tabs .tab-item, + .tabs-icon-left > .tabs .tab-item, + .tabs-icon-right.tabs .tab-item, + .tabs-icon-right > .tabs .tab-item { + font-size: 10px; } + .tabs-icon-left.tabs .tab-item .icon, .tabs-icon-left.tabs .tab-item .icon-help, .tabs-icon-left.tabs .tab-item .icon-alert, .tabs-icon-left.tabs .tab-item #menu .footer .icon-help, #menu .footer .tabs-icon-left.tabs .tab-item .icon-help, .tabs-icon-left.tabs .tab-item .tab-title, + .tabs-icon-left > .tabs .tab-item .icon, + .tabs-icon-left > .tabs .tab-item .icon-help, + .tabs-icon-left > .tabs .tab-item .icon-alert, + .tabs-icon-left > .tabs .tab-item #menu .footer .icon-help, #menu .footer + .tabs-icon-left > .tabs .tab-item .icon-help, + .tabs-icon-left > .tabs .tab-item .tab-title, + .tabs-icon-right.tabs .tab-item .icon, + .tabs-icon-right.tabs .tab-item .icon-help, + .tabs-icon-right.tabs .tab-item .icon-alert, + .tabs-icon-right.tabs .tab-item #menu .footer .icon-help, #menu .footer + .tabs-icon-right.tabs .tab-item .icon-help, + .tabs-icon-right.tabs .tab-item .tab-title, + .tabs-icon-right > .tabs .tab-item .icon, + .tabs-icon-right > .tabs .tab-item .icon-help, + .tabs-icon-right > .tabs .tab-item .icon-alert, + .tabs-icon-right > .tabs .tab-item #menu .footer .icon-help, #menu .footer + .tabs-icon-right > .tabs .tab-item .icon-help, + .tabs-icon-right > .tabs .tab-item .tab-title { + display: inline-block; + vertical-align: top; + margin-top: -.1em; } + .tabs-icon-left.tabs .tab-item .icon:before, .tabs-icon-left.tabs .tab-item .icon-help:before, .tabs-icon-left.tabs .tab-item .icon-alert:before, .tabs-icon-left.tabs .tab-item #menu .footer .icon-help:before, #menu .footer .tabs-icon-left.tabs .tab-item .icon-help:before, .tabs-icon-left.tabs .tab-item .tab-title:before, + .tabs-icon-left > .tabs .tab-item .icon:before, + .tabs-icon-left > .tabs .tab-item .icon-help:before, + .tabs-icon-left > .tabs .tab-item .icon-alert:before, + .tabs-icon-left > .tabs .tab-item #menu .footer .icon-help:before, #menu .footer + .tabs-icon-left > .tabs .tab-item .icon-help:before, + .tabs-icon-left > .tabs .tab-item .tab-title:before, + .tabs-icon-right.tabs .tab-item .icon:before, + .tabs-icon-right.tabs .tab-item .icon-help:before, + .tabs-icon-right.tabs .tab-item .icon-alert:before, + .tabs-icon-right.tabs .tab-item #menu .footer .icon-help:before, #menu .footer + .tabs-icon-right.tabs .tab-item .icon-help:before, + .tabs-icon-right.tabs .tab-item .tab-title:before, + .tabs-icon-right > .tabs .tab-item .icon:before, + .tabs-icon-right > .tabs .tab-item .icon-help:before, + .tabs-icon-right > .tabs .tab-item .icon-alert:before, + .tabs-icon-right > .tabs .tab-item #menu .footer .icon-help:before, #menu .footer + .tabs-icon-right > .tabs .tab-item .icon-help:before, + .tabs-icon-right > .tabs .tab-item .tab-title:before { + font-size: 24px; + line-height: 49px; } + + .tabs-icon-left > .tabs .tab-item .icon, .tabs-icon-left > .tabs .tab-item .icon-help, .tabs-icon-left > .tabs .tab-item .icon-alert, .tabs-icon-left > .tabs .tab-item #menu .footer .icon-help, #menu .footer .tabs-icon-left > .tabs .tab-item .icon-help, + .tabs-icon-left.tabs .tab-item .icon, + .tabs-icon-left.tabs .tab-item .icon-help, + .tabs-icon-left.tabs .tab-item .icon-alert, + .tabs-icon-left.tabs .tab-item #menu .footer .icon-help, #menu .footer + .tabs-icon-left.tabs .tab-item .icon-help { + padding-right: 3px; } + + .tabs-icon-right > .tabs .tab-item .icon, .tabs-icon-right > .tabs .tab-item .icon-help, .tabs-icon-right > .tabs .tab-item .icon-alert, .tabs-icon-right > .tabs .tab-item #menu .footer .icon-help, #menu .footer .tabs-icon-right > .tabs .tab-item .icon-help, + .tabs-icon-right.tabs .tab-item .icon, + .tabs-icon-right.tabs .tab-item .icon-help, + .tabs-icon-right.tabs .tab-item .icon-alert, + .tabs-icon-right.tabs .tab-item #menu .footer .icon-help, #menu .footer + .tabs-icon-right.tabs .tab-item .icon-help { + padding-left: 3px; } + + .tabs-icon-only > .tabs .icon, .tabs-icon-only > .tabs .icon-help, .tabs-icon-only > .tabs .icon-alert, .tabs-icon-only > .tabs #menu .footer .icon-help, #menu .footer .tabs-icon-only > .tabs .icon-help, + .tabs-icon-only.tabs .icon, + .tabs-icon-only.tabs .icon-help, + .tabs-icon-only.tabs .icon-alert, + .tabs-icon-only.tabs #menu .footer .icon-help, #menu .footer + .tabs-icon-only.tabs .icon-help { + line-height: inherit; } + + .tab-item.has-badge { + position: relative; } + + .tab-item .badge { + position: absolute; + top: 4%; + right: 33%; + right: calc(50% - 26px); + padding: 1px 6px; + height: auto; + font-size: 12px; + line-height: 16px; } + + /* Navigational tab */ + /* Active state for tab */ + .tab-item.tab-item-active, + .tab-item.active, + .tab-item.activated { + opacity: 1; } + .tab-item.tab-item-active.tab-item-light, + .tab-item.active.tab-item-light, + .tab-item.activated.tab-item-light { + color: #fff; } + .tab-item.tab-item-active.tab-item-stable, + .tab-item.active.tab-item-stable, + .tab-item.activated.tab-item-stable { + color: #f8f8f8; } + .tab-item.tab-item-active.tab-item-positive, + .tab-item.active.tab-item-positive, + .tab-item.activated.tab-item-positive { + color: #387ef5; } + .tab-item.tab-item-active.tab-item-calm, + .tab-item.active.tab-item-calm, + .tab-item.activated.tab-item-calm { + color: #11c1f3; } + .tab-item.tab-item-active.tab-item-assertive, + .tab-item.active.tab-item-assertive, + .tab-item.activated.tab-item-assertive { + color: #ef473a; } + .tab-item.tab-item-active.tab-item-balanced, + .tab-item.active.tab-item-balanced, + .tab-item.activated.tab-item-balanced { + color: #33cd5f; } + .tab-item.tab-item-active.tab-item-energized, + .tab-item.active.tab-item-energized, + .tab-item.activated.tab-item-energized { + color: #ffc900; } + .tab-item.tab-item-active.tab-item-royal, + .tab-item.active.tab-item-royal, + .tab-item.activated.tab-item-royal { + color: #886aea; } + .tab-item.tab-item-active.tab-item-dark, + .tab-item.active.tab-item-dark, + .tab-item.activated.tab-item-dark { + color: #444; } + + .item.tabs { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + padding: 0; } + .item.tabs .icon:before, .item.tabs .icon-help:before, .item.tabs .icon-alert:before, .item.tabs #menu .footer .icon-help:before, #menu .footer .item.tabs .icon-help:before { + position: relative; } + + .tab-item.disabled, + .tab-item[disabled] { + opacity: .4; + cursor: default; + pointer-events: none; } + + .nav-bar-tabs-top.hide ~ .view-container .tabs-top .tabs { + top: 0; } + + .pane[hide-nav-bar="true"] .has-tabs-top { + top: 49px; } + + /** + * Menus + * -------------------------------------------------- + * Side panel structure + */ + .menu { + position: absolute; + top: 0; + bottom: 0; + z-index: 0; + overflow: hidden; + min-height: 100%; + max-height: 100%; + width: 275px; + background-color: #fff; } + .menu .scroll-content { + z-index: 10; } + .menu .bar-header { + z-index: 11; } + + .menu-content { + -webkit-transform: none; + transform: none; + box-shadow: -1px 0px 2px rgba(0, 0, 0, 0.2), 1px 0px 2px rgba(0, 0, 0, 0.2); } + + .menu-open .menu-content .pane, + .menu-open .menu-content .scroll-content { + pointer-events: none; } + + .menu-open .menu-content .scroll-content .scroll { + pointer-events: none; } + + .menu-open .menu-content .scroll-content:not(.overflow-scroll) { + overflow: hidden; } + + .grade-b .menu-content, + .grade-c .menu-content { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + right: -1px; + left: -1px; + border-right: 1px solid #ccc; + border-left: 1px solid #ccc; + box-shadow: none; } + + .menu-left { + left: 0; } + + .menu-right { + right: 0; } + + .aside-open.aside-resizing .menu-right { + display: none; } + + .menu-animated { + -webkit-transition: -webkit-transform 200ms ease; + transition: transform 200ms ease; } + + /** + * Modals + * -------------------------------------------------- + * Modals are independent windows that slide in from off-screen. + */ + .modal-backdrop, + .modal-backdrop-bg { + position: fixed; + top: 0; + left: 0; + z-index: 10; + width: 100%; + height: 100%; } + + .modal-backdrop-bg { + pointer-events: none; } + + .modal { + display: block; + position: absolute; + top: 0; + z-index: 10; + overflow: hidden; + min-height: 100%; + width: 100%; + background-color: #fff; } + + @media (min-width: 680px) { + .modal { + top: 20%; + right: 20%; + bottom: 20%; + left: 20%; + min-height: 240px; + width: 60%; } + .modal.ng-leave-active { + bottom: 0; } + .platform-ios.platform-cordova .modal-wrapper .modal .bar-header:not(.bar-subheader) { + height: 44px; } + .platform-ios.platform-cordova .modal-wrapper .modal .bar-header:not(.bar-subheader) > * { + margin-top: 0; } + .platform-ios.platform-cordova .modal-wrapper .modal .tabs-top > .tabs, + .platform-ios.platform-cordova .modal-wrapper .modal .tabs.tabs-top { + top: 44px; } + .platform-ios.platform-cordova .modal-wrapper .modal .has-header, + .platform-ios.platform-cordova .modal-wrapper .modal .bar-subheader { + top: 44px; } + .platform-ios.platform-cordova .modal-wrapper .modal .has-subheader { + top: 88px; } + .platform-ios.platform-cordova .modal-wrapper .modal .has-header.has-tabs-top { + top: 93px; } + .platform-ios.platform-cordova .modal-wrapper .modal .has-header.has-subheader.has-tabs-top { + top: 137px; } + .modal-backdrop-bg { + -webkit-transition: opacity 300ms ease-in-out; + transition: opacity 300ms ease-in-out; + background-color: #000; + opacity: 0; } + .active .modal-backdrop-bg { + opacity: 0.5; } } + + .modal-open { + pointer-events: none; } + .modal-open .modal, + .modal-open .modal-backdrop { + pointer-events: auto; } + .modal-open.loading-active .modal, + .modal-open.loading-active .modal-backdrop { + pointer-events: none; } + + /** + * Popovers + * -------------------------------------------------- + * Popovers are independent views which float over content + */ + .popover-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 10; + width: 100%; + height: 100%; + background-color: transparent; } + .popover-backdrop.active { + background-color: rgba(0, 0, 0, 0.1); } + + .popover { + position: absolute; + top: 25%; + left: 50%; + z-index: 10; + display: block; + margin-top: 12px; + margin-left: -110px; + height: 280px; + width: 220px; + background-color: #fff; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); + opacity: 0; } + .popover .item:first-child { + border-top: 0; } + .popover .item:last-child { + border-bottom: 0; } + .popover.popover-bottom { + margin-top: -12px; } + + .popover, + .popover .bar-header { + border-radius: 2px; } + + .popover .scroll-content { + z-index: 1; + margin: 2px 0; } + + .popover .bar-header { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; } + + .popover .has-header { + border-top-right-radius: 0; + border-top-left-radius: 0; } + + .popover-arrow { + display: none; } + + .platform-ios .popover { + box-shadow: 0 0 40px rgba(0, 0, 0, 0.08); + border-radius: 10px; } + + .platform-ios .popover .bar-header { + -webkit-border-top-right-radius: 10px; + border-top-right-radius: 10px; + -webkit-border-top-left-radius: 10px; + border-top-left-radius: 10px; } + + .platform-ios .popover .scroll-content { + margin: 8px 0; + border-radius: 10px; } + + .platform-ios .popover .scroll-content.has-header { + margin-top: 0; } + + .platform-ios .popover-arrow { + position: absolute; + display: block; + top: -17px; + width: 30px; + height: 19px; + overflow: hidden; } + .platform-ios .popover-arrow:after { + position: absolute; + top: 12px; + left: 5px; + width: 20px; + height: 20px; + background-color: #fff; + border-radius: 3px; + content: ''; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); } + + .platform-ios .popover-bottom .popover-arrow { + top: auto; + bottom: -10px; } + .platform-ios .popover-bottom .popover-arrow:after { + top: -6px; } + + .platform-android .popover { + margin-top: -32px; + background-color: #fafafa; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35); } + .platform-android .popover .item { + border-color: #fafafa; + background-color: #fafafa; + color: #4d4d4d; } + .platform-android .popover.popover-bottom { + margin-top: 32px; } + + .platform-android .popover-backdrop, + .platform-android .popover-backdrop.active { + background-color: transparent; } + + .popover-open { + pointer-events: none; } + .popover-open .popover, + .popover-open .popover-backdrop { + pointer-events: auto; } + .popover-open.loading-active .popover, + .popover-open.loading-active .popover-backdrop { + pointer-events: none; } + + @media (min-width: 680px) { + .popover { + width: 360px; + margin-left: -180px; } } + + /** + * Popups + * -------------------------------------------------- + */ + .popup-container { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: transparent; + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + -moz-justify-content: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + z-index: 12; + visibility: hidden; } + .popup-container.popup-showing { + visibility: visible; } + .popup-container.popup-hidden .popup { + -webkit-animation-name: scaleOut; + animation-name: scaleOut; + -webkit-animation-duration: 0.1s; + animation-duration: 0.1s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; } + .popup-container.active .popup { + -webkit-animation-name: superScaleIn; + animation-name: superScaleIn; + -webkit-animation-duration: 0.2s; + animation-duration: 0.2s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; } + .popup-container .popup { + width: 250px; + max-width: 100%; + max-height: 90%; + border-radius: 0px; + background-color: rgba(255, 255, 255, 0.9); + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-direction: normal; + -webkit-box-orient: vertical; + -webkit-flex-direction: column; + -moz-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } + .popup-container input, + .popup-container textarea { + width: 100%; } + + .popup-head { + padding: 15px 10px; + border-bottom: 1px solid #eee; + text-align: center; } + + .popup-title { + margin: 0; + padding: 0; + font-size: 15px; } + + .popup-sub-title { + margin: 5px 0 0 0; + padding: 0; + font-weight: normal; + font-size: 11px; } + + .popup-body { + padding: 10px; + overflow: auto; } + + .popup-buttons { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-direction: normal; + -webkit-box-orient: horizontal; + -webkit-flex-direction: row; + -moz-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 10px; + min-height: 65px; } + .popup-buttons .button { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + display: block; + min-height: 45px; + border-radius: 2px; + line-height: 20px; + margin-right: 5px; } + .popup-buttons .button:last-child { + margin-right: 0px; } + + .popup-open { + pointer-events: none; } + .popup-open.modal-open .modal { + pointer-events: none; } + .popup-open .popup-backdrop, .popup-open .popup { + pointer-events: auto; } + + /** + * Loading + * -------------------------------------------------- + */ + .loading-container { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + z-index: 13; + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + -moz-justify-content: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + -webkit-transition: 0.2s opacity linear; + transition: 0.2s opacity linear; + visibility: hidden; + opacity: 0; } + .loading-container:not(.visible) .icon, .loading-container:not(.visible) .icon-help, .loading-container:not(.visible) .icon-alert, .loading-container:not(.visible) #menu .footer .icon-help, #menu .footer .loading-container:not(.visible) .icon-help, + .loading-container:not(.visible) .spinner { + display: none; } + .loading-container.visible { + visibility: visible; } + .loading-container.active { + opacity: 1; } + .loading-container .loading { + padding: 20px; + border-radius: 5px; + background-color: rgba(0, 0, 0, 0.7); + color: #fff; + text-align: center; + text-overflow: ellipsis; + font-size: 15px; } + .loading-container .loading h1, .loading-container .loading h2, .loading-container .loading h3, .loading-container .loading h4, .loading-container .loading h5, .loading-container .loading h6 { + color: #fff; } + + /** + * Items + * -------------------------------------------------- + */ + .item { + border-color: #ddd; + background-color: #fff; + color: #444; + position: relative; + z-index: 2; + display: block; + margin: -1px; + padding: 16px; + border-width: 1px; + border-style: solid; + font-size: 16px; } + .item h2 { + margin: 0 0 2px 0; + font-size: 16px; + font-weight: normal; } + .item h3 { + margin: 0 0 4px 0; + font-size: 14px; } + .item h4 { + margin: 0 0 4px 0; + font-size: 12px; } + .item h5, .item h6 { + margin: 0 0 3px 0; + font-size: 10px; } + .item p { + color: #666; + font-size: 14px; + margin-bottom: 2px; } + .item h1:last-child, + .item h2:last-child, + .item h3:last-child, + .item h4:last-child, + .item h5:last-child, + .item h6:last-child, + .item p:last-child { + margin-bottom: 0; } + .item .badge { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + position: absolute; + top: 16px; + right: 32px; } + .item.item-button-right .badge { + right: 67px; } + .item.item-divider .badge { + top: 8px; } + .item .badge + .badge { + margin-right: 5px; } + .item.item-light { + border-color: #ddd; + background-color: #fff; + color: #444; } + .item.item-stable { + border-color: #b2b2b2; + background-color: #f8f8f8; + color: #444; } + .item.item-positive { + border-color: #0c60ee; + background-color: #387ef5; + color: #fff; } + .item.item-calm { + border-color: #0a9dc7; + background-color: #11c1f3; + color: #fff; } + .item.item-assertive { + border-color: #e42112; + background-color: #ef473a; + color: #fff; } + .item.item-balanced { + border-color: #28a54c; + background-color: #33cd5f; + color: #fff; } + .item.item-energized { + border-color: #e6b500; + background-color: #ffc900; + color: #fff; } + .item.item-royal { + border-color: #6b46e5; + background-color: #886aea; + color: #fff; } + .item.item-dark { + border-color: #111; + background-color: #444; + color: #fff; } + .item[ng-click]:hover { + cursor: pointer; } + + .list-borderless .item, + .item-borderless { + border-width: 0; } + + .item.active, + .item.activated, + .item-complex.active .item-content, + .item-complex.activated .item-content, + .item .item-content.active, + .item .item-content.activated { + border-color: #ccc; + background-color: #D9D9D9; } + .item.active.item-complex > .item-content, + .item.activated.item-complex > .item-content, + .item-complex.active .item-content.item-complex > .item-content, + .item-complex.activated .item-content.item-complex > .item-content, + .item .item-content.active.item-complex > .item-content, + .item .item-content.activated.item-complex > .item-content { + border-color: #ccc; + background-color: #D9D9D9; } + .item.active.item-light, + .item.activated.item-light, + .item-complex.active .item-content.item-light, + .item-complex.activated .item-content.item-light, + .item .item-content.active.item-light, + .item .item-content.activated.item-light { + border-color: #ccc; + background-color: #fafafa; } + .item.active.item-light.item-complex > .item-content, + .item.activated.item-light.item-complex > .item-content, + .item-complex.active .item-content.item-light.item-complex > .item-content, + .item-complex.activated .item-content.item-light.item-complex > .item-content, + .item .item-content.active.item-light.item-complex > .item-content, + .item .item-content.activated.item-light.item-complex > .item-content { + border-color: #ccc; + background-color: #fafafa; } + .item.active.item-stable, + .item.activated.item-stable, + .item-complex.active .item-content.item-stable, + .item-complex.activated .item-content.item-stable, + .item .item-content.active.item-stable, + .item .item-content.activated.item-stable { + border-color: #a2a2a2; + background-color: #e5e5e5; } + .item.active.item-stable.item-complex > .item-content, + .item.activated.item-stable.item-complex > .item-content, + .item-complex.active .item-content.item-stable.item-complex > .item-content, + .item-complex.activated .item-content.item-stable.item-complex > .item-content, + .item .item-content.active.item-stable.item-complex > .item-content, + .item .item-content.activated.item-stable.item-complex > .item-content { + border-color: #a2a2a2; + background-color: #e5e5e5; } + .item.active.item-positive, + .item.activated.item-positive, + .item-complex.active .item-content.item-positive, + .item-complex.activated .item-content.item-positive, + .item .item-content.active.item-positive, + .item .item-content.activated.item-positive { + border-color: #0c60ee; + background-color: #0c60ee; } + .item.active.item-positive.item-complex > .item-content, + .item.activated.item-positive.item-complex > .item-content, + .item-complex.active .item-content.item-positive.item-complex > .item-content, + .item-complex.activated .item-content.item-positive.item-complex > .item-content, + .item .item-content.active.item-positive.item-complex > .item-content, + .item .item-content.activated.item-positive.item-complex > .item-content { + border-color: #0c60ee; + background-color: #0c60ee; } + .item.active.item-calm, + .item.activated.item-calm, + .item-complex.active .item-content.item-calm, + .item-complex.activated .item-content.item-calm, + .item .item-content.active.item-calm, + .item .item-content.activated.item-calm { + border-color: #0a9dc7; + background-color: #0a9dc7; } + .item.active.item-calm.item-complex > .item-content, + .item.activated.item-calm.item-complex > .item-content, + .item-complex.active .item-content.item-calm.item-complex > .item-content, + .item-complex.activated .item-content.item-calm.item-complex > .item-content, + .item .item-content.active.item-calm.item-complex > .item-content, + .item .item-content.activated.item-calm.item-complex > .item-content { + border-color: #0a9dc7; + background-color: #0a9dc7; } + .item.active.item-assertive, + .item.activated.item-assertive, + .item-complex.active .item-content.item-assertive, + .item-complex.activated .item-content.item-assertive, + .item .item-content.active.item-assertive, + .item .item-content.activated.item-assertive { + border-color: #e42112; + background-color: #e42112; } + .item.active.item-assertive.item-complex > .item-content, + .item.activated.item-assertive.item-complex > .item-content, + .item-complex.active .item-content.item-assertive.item-complex > .item-content, + .item-complex.activated .item-content.item-assertive.item-complex > .item-content, + .item .item-content.active.item-assertive.item-complex > .item-content, + .item .item-content.activated.item-assertive.item-complex > .item-content { + border-color: #e42112; + background-color: #e42112; } + .item.active.item-balanced, + .item.activated.item-balanced, + .item-complex.active .item-content.item-balanced, + .item-complex.activated .item-content.item-balanced, + .item .item-content.active.item-balanced, + .item .item-content.activated.item-balanced { + border-color: #28a54c; + background-color: #28a54c; } + .item.active.item-balanced.item-complex > .item-content, + .item.activated.item-balanced.item-complex > .item-content, + .item-complex.active .item-content.item-balanced.item-complex > .item-content, + .item-complex.activated .item-content.item-balanced.item-complex > .item-content, + .item .item-content.active.item-balanced.item-complex > .item-content, + .item .item-content.activated.item-balanced.item-complex > .item-content { + border-color: #28a54c; + background-color: #28a54c; } + .item.active.item-energized, + .item.activated.item-energized, + .item-complex.active .item-content.item-energized, + .item-complex.activated .item-content.item-energized, + .item .item-content.active.item-energized, + .item .item-content.activated.item-energized { + border-color: #e6b500; + background-color: #e6b500; } + .item.active.item-energized.item-complex > .item-content, + .item.activated.item-energized.item-complex > .item-content, + .item-complex.active .item-content.item-energized.item-complex > .item-content, + .item-complex.activated .item-content.item-energized.item-complex > .item-content, + .item .item-content.active.item-energized.item-complex > .item-content, + .item .item-content.activated.item-energized.item-complex > .item-content { + border-color: #e6b500; + background-color: #e6b500; } + .item.active.item-royal, + .item.activated.item-royal, + .item-complex.active .item-content.item-royal, + .item-complex.activated .item-content.item-royal, + .item .item-content.active.item-royal, + .item .item-content.activated.item-royal { + border-color: #6b46e5; + background-color: #6b46e5; } + .item.active.item-royal.item-complex > .item-content, + .item.activated.item-royal.item-complex > .item-content, + .item-complex.active .item-content.item-royal.item-complex > .item-content, + .item-complex.activated .item-content.item-royal.item-complex > .item-content, + .item .item-content.active.item-royal.item-complex > .item-content, + .item .item-content.activated.item-royal.item-complex > .item-content { + border-color: #6b46e5; + background-color: #6b46e5; } + .item.active.item-dark, + .item.activated.item-dark, + .item-complex.active .item-content.item-dark, + .item-complex.activated .item-content.item-dark, + .item .item-content.active.item-dark, + .item .item-content.activated.item-dark { + border-color: #000; + background-color: #262626; } + .item.active.item-dark.item-complex > .item-content, + .item.activated.item-dark.item-complex > .item-content, + .item-complex.active .item-content.item-dark.item-complex > .item-content, + .item-complex.activated .item-content.item-dark.item-complex > .item-content, + .item .item-content.active.item-dark.item-complex > .item-content, + .item .item-content.activated.item-dark.item-complex > .item-content { + border-color: #000; + background-color: #262626; } + + .item, + .item h1, + .item h2, + .item h3, + .item h4, + .item h5, + .item h6, + .item p, + .item-content, + .item-content h1, + .item-content h2, + .item-content h3, + .item-content h4, + .item-content h5, + .item-content h6, + .item-content p { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + + a.item { + color: inherit; + text-decoration: none; } + a.item:hover, a.item:focus { + text-decoration: none; } + + /** + * Complex Items + * -------------------------------------------------- + * Adding .item-complex allows the .item to be slidable and + * have options underneath the button, but also requires an + * additional .item-content element inside .item. + * Basically .item-complex removes any default settings which + * .item added, so that .item-content looks them as just .item. + */ + .item-complex, + a.item.item-complex, + button.item.item-complex { + padding: 0; } + + .item-complex .item-content, + .item-radio .item-content { + position: relative; + z-index: 2; + padding: 16px 49px 16px 16px; + border: none; + background-color: #fff; } + + a.item-content { + display: block; + color: inherit; + text-decoration: none; } + + .item-text-wrap .item, + .item-text-wrap .item-content, + .item-text-wrap, + .item-text-wrap h1, + .item-text-wrap h2, + .item-text-wrap h3, + .item-text-wrap h4, + .item-text-wrap h5, + .item-text-wrap h6, + .item-text-wrap p, + .item-complex.item-text-wrap .item-content, + .item-body h1, + .item-body h2, + .item-body h3, + .item-body h4, + .item-body h5, + .item-body h6, + .item-body p { + overflow: visible; + white-space: normal; } + + .item-complex.item-text-wrap, + .item-complex.item-text-wrap h1, + .item-complex.item-text-wrap h2, + .item-complex.item-text-wrap h3, + .item-complex.item-text-wrap h4, + .item-complex.item-text-wrap h5, + .item-complex.item-text-wrap h6, + .item-complex.item-text-wrap p { + overflow: visible; + white-space: normal; } + + .item-complex.item-light > .item-content { + border-color: #ddd; + background-color: #fff; + color: #444; } + .item-complex.item-light > .item-content.active, .item-complex.item-light > .item-content:active { + border-color: #ccc; + background-color: #fafafa; } + .item-complex.item-light > .item-content.active.item-complex > .item-content, .item-complex.item-light > .item-content:active.item-complex > .item-content { + border-color: #ccc; + background-color: #fafafa; } + + .item-complex.item-stable > .item-content { + border-color: #b2b2b2; + background-color: #f8f8f8; + color: #444; } + .item-complex.item-stable > .item-content.active, .item-complex.item-stable > .item-content:active { + border-color: #a2a2a2; + background-color: #e5e5e5; } + .item-complex.item-stable > .item-content.active.item-complex > .item-content, .item-complex.item-stable > .item-content:active.item-complex > .item-content { + border-color: #a2a2a2; + background-color: #e5e5e5; } + + .item-complex.item-positive > .item-content { + border-color: #0c60ee; + background-color: #387ef5; + color: #fff; } + .item-complex.item-positive > .item-content.active, .item-complex.item-positive > .item-content:active { + border-color: #0c60ee; + background-color: #0c60ee; } + .item-complex.item-positive > .item-content.active.item-complex > .item-content, .item-complex.item-positive > .item-content:active.item-complex > .item-content { + border-color: #0c60ee; + background-color: #0c60ee; } + + .item-complex.item-calm > .item-content { + border-color: #0a9dc7; + background-color: #11c1f3; + color: #fff; } + .item-complex.item-calm > .item-content.active, .item-complex.item-calm > .item-content:active { + border-color: #0a9dc7; + background-color: #0a9dc7; } + .item-complex.item-calm > .item-content.active.item-complex > .item-content, .item-complex.item-calm > .item-content:active.item-complex > .item-content { + border-color: #0a9dc7; + background-color: #0a9dc7; } + + .item-complex.item-assertive > .item-content { + border-color: #e42112; + background-color: #ef473a; + color: #fff; } + .item-complex.item-assertive > .item-content.active, .item-complex.item-assertive > .item-content:active { + border-color: #e42112; + background-color: #e42112; } + .item-complex.item-assertive > .item-content.active.item-complex > .item-content, .item-complex.item-assertive > .item-content:active.item-complex > .item-content { + border-color: #e42112; + background-color: #e42112; } + + .item-complex.item-balanced > .item-content { + border-color: #28a54c; + background-color: #33cd5f; + color: #fff; } + .item-complex.item-balanced > .item-content.active, .item-complex.item-balanced > .item-content:active { + border-color: #28a54c; + background-color: #28a54c; } + .item-complex.item-balanced > .item-content.active.item-complex > .item-content, .item-complex.item-balanced > .item-content:active.item-complex > .item-content { + border-color: #28a54c; + background-color: #28a54c; } + + .item-complex.item-energized > .item-content { + border-color: #e6b500; + background-color: #ffc900; + color: #fff; } + .item-complex.item-energized > .item-content.active, .item-complex.item-energized > .item-content:active { + border-color: #e6b500; + background-color: #e6b500; } + .item-complex.item-energized > .item-content.active.item-complex > .item-content, .item-complex.item-energized > .item-content:active.item-complex > .item-content { + border-color: #e6b500; + background-color: #e6b500; } + + .item-complex.item-royal > .item-content { + border-color: #6b46e5; + background-color: #886aea; + color: #fff; } + .item-complex.item-royal > .item-content.active, .item-complex.item-royal > .item-content:active { + border-color: #6b46e5; + background-color: #6b46e5; } + .item-complex.item-royal > .item-content.active.item-complex > .item-content, .item-complex.item-royal > .item-content:active.item-complex > .item-content { + border-color: #6b46e5; + background-color: #6b46e5; } + + .item-complex.item-dark > .item-content { + border-color: #111; + background-color: #444; + color: #fff; } + .item-complex.item-dark > .item-content.active, .item-complex.item-dark > .item-content:active { + border-color: #000; + background-color: #262626; } + .item-complex.item-dark > .item-content.active.item-complex > .item-content, .item-complex.item-dark > .item-content:active.item-complex > .item-content { + border-color: #000; + background-color: #262626; } + + /** + * Item Icons + * -------------------------------------------------- + */ + .item-icon-left .icon, .item-icon-left .icon-help, .item-icon-left .icon-alert, .item-icon-left #menu .footer .icon-help, #menu .footer .item-icon-left .icon-help, + .item-icon-right .icon, + .item-icon-right .icon-help, + .item-icon-right .icon-alert, + .item-icon-right #menu .footer .icon-help, #menu .footer + .item-icon-right .icon-help { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 0; + height: 100%; + font-size: 32px; } + .item-icon-left .icon:before, .item-icon-left .icon-help:before, .item-icon-left .icon-alert:before, .item-icon-left #menu .footer .icon-help:before, #menu .footer .item-icon-left .icon-help:before, + .item-icon-right .icon:before, + .item-icon-right .icon-help:before, + .item-icon-right .icon-alert:before, + .item-icon-right #menu .footer .icon-help:before, #menu .footer + .item-icon-right .icon-help:before { + display: block; + width: 32px; + text-align: center; } + + .item .fill-icon { + min-width: 30px; + min-height: 30px; + font-size: 28px; } + + .item-icon-left { + padding-left: 54px; } + .item-icon-left .icon, .item-icon-left .icon-help, .item-icon-left .icon-alert, .item-icon-left #menu .footer .icon-help, #menu .footer .item-icon-left .icon-help { + left: 11px; } + + .item-complex.item-icon-left { + padding-left: 0; } + .item-complex.item-icon-left .item-content { + padding-left: 54px; } + + .item-icon-right { + padding-right: 54px; } + .item-icon-right .icon, .item-icon-right .icon-help, .item-icon-right .icon-alert, .item-icon-right #menu .footer .icon-help, #menu .footer .item-icon-right .icon-help { + right: 11px; } + + .item-complex.item-icon-right { + padding-right: 0; } + .item-complex.item-icon-right .item-content { + padding-right: 54px; } + + .item-icon-left.item-icon-right .icon:first-child, .item-icon-left.item-icon-right .icon-help:first-child, .item-icon-left.item-icon-right .icon-alert:first-child, .item-icon-left.item-icon-right #menu .footer .icon-help:first-child, #menu .footer .item-icon-left.item-icon-right .icon-help:first-child { + right: auto; } + + .item-icon-left.item-icon-right .icon:last-child, .item-icon-left.item-icon-right .icon-help:last-child, .item-icon-left.item-icon-right .icon-alert:last-child, .item-icon-left.item-icon-right #menu .footer .icon-help:last-child, #menu .footer .item-icon-left.item-icon-right .icon-help:last-child, + .item-icon-left .item-delete .icon, + .item-icon-left .item-delete .icon-help, + .item-icon-left .item-delete .icon-alert, + .item-icon-left .item-delete #menu .footer .icon-help, #menu .footer + .item-icon-left .item-delete .icon-help { + left: auto; } + + .item-icon-left .icon-accessory, + .item-icon-right .icon-accessory { + color: #ccc; + font-size: 16px; } + + .item-icon-left .icon-accessory { + left: 3px; } + + .item-icon-right .icon-accessory { + right: 3px; } + + /** + * Item Button + * -------------------------------------------------- + * An item button is a child button inside an .item (not the entire .item) + */ + .item-button-left { + padding-left: 72px; } + + .item-button-left > .button, + .item-button-left .item-content > .button { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 8px; + left: 11px; + min-width: 34px; + min-height: 34px; + font-size: 18px; + line-height: 32px; } + .item-button-left > .button .icon:before, .item-button-left > .button .icon-help:before, .item-button-left > .button .icon-alert:before, .item-button-left > .button #menu .footer .icon-help:before, #menu .footer .item-button-left > .button .icon-help:before, + .item-button-left .item-content > .button .icon:before, + .item-button-left .item-content > .button .icon-help:before, + .item-button-left .item-content > .button .icon-alert:before, + .item-button-left .item-content > .button #menu .footer .icon-help:before, #menu .footer + .item-button-left .item-content > .button .icon-help:before { + position: relative; + left: auto; + width: auto; + line-height: 31px; } + .item-button-left > .button > .button, + .item-button-left .item-content > .button > .button { + margin: 0px 2px; + min-height: 34px; + font-size: 18px; + line-height: 32px; } + + .item-button-right, + a.item.item-button-right, + button.item.item-button-right { + padding-right: 80px; } + + .item-button-right > .button, + .item-button-right .item-content > .button, + .item-button-right > .buttons, + .item-button-right .item-content > .buttons { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 8px; + right: 16px; + min-width: 34px; + min-height: 34px; + font-size: 18px; + line-height: 32px; } + .item-button-right > .button .icon:before, .item-button-right > .button .icon-help:before, .item-button-right > .button .icon-alert:before, .item-button-right > .button #menu .footer .icon-help:before, #menu .footer .item-button-right > .button .icon-help:before, + .item-button-right .item-content > .button .icon:before, + .item-button-right .item-content > .button .icon-help:before, + .item-button-right .item-content > .button .icon-alert:before, + .item-button-right .item-content > .button #menu .footer .icon-help:before, #menu .footer + .item-button-right .item-content > .button .icon-help:before, + .item-button-right > .buttons .icon:before, + .item-button-right > .buttons .icon-help:before, + .item-button-right > .buttons .icon-alert:before, + .item-button-right > .buttons #menu .footer .icon-help:before, #menu .footer + .item-button-right > .buttons .icon-help:before, + .item-button-right .item-content > .buttons .icon:before, + .item-button-right .item-content > .buttons .icon-help:before, + .item-button-right .item-content > .buttons .icon-alert:before, + .item-button-right .item-content > .buttons #menu .footer .icon-help:before, #menu .footer + .item-button-right .item-content > .buttons .icon-help:before { + position: relative; + left: auto; + width: auto; + line-height: 31px; } + .item-button-right > .button > .button, + .item-button-right .item-content > .button > .button, + .item-button-right > .buttons > .button, + .item-button-right .item-content > .buttons > .button { + margin: 0px 2px; + min-width: 34px; + min-height: 34px; + font-size: 18px; + line-height: 32px; } + + .item-button-left.item-button-right .button:first-child { + right: auto; } + + .item-button-left.item-button-right .button:last-child { + left: auto; } + + .item-avatar, + .item-avatar .item-content, + .item-avatar-left, + .item-avatar-left .item-content { + padding-left: 72px; + min-height: 72px; } + .item-avatar > img:first-child, + .item-avatar .item-image, + .item-avatar .item-content > img:first-child, + .item-avatar .item-content .item-image, + .item-avatar-left > img:first-child, + .item-avatar-left .item-image, + .item-avatar-left .item-content > img:first-child, + .item-avatar-left .item-content .item-image { + position: absolute; + top: 16px; + left: 16px; + max-width: 40px; + max-height: 40px; + width: 100%; + height: 100%; + border-radius: 50%; } + + .item-avatar-right, + .item-avatar-right .item-content { + padding-right: 72px; + min-height: 72px; } + .item-avatar-right > img:first-child, + .item-avatar-right .item-image, + .item-avatar-right .item-content > img:first-child, + .item-avatar-right .item-content .item-image { + position: absolute; + top: 16px; + right: 16px; + max-width: 40px; + max-height: 40px; + width: 100%; + height: 100%; + border-radius: 50%; } + + .item-thumbnail-left, + .item-thumbnail-left .item-content { + padding-top: 8px; + padding-left: 106px; + min-height: 100px; } + .item-thumbnail-left > img:first-child, + .item-thumbnail-left .item-image, + .item-thumbnail-left .item-content > img:first-child, + .item-thumbnail-left .item-content .item-image { + position: absolute; + top: 10px; + left: 10px; + max-width: 80px; + max-height: 80px; + width: 100%; + height: 100%; } + + .item-avatar.item-complex, + .item-avatar-left.item-complex, + .item-thumbnail-left.item-complex { + padding-top: 0; + padding-left: 0; } + + .item-thumbnail-right, + .item-thumbnail-right .item-content { + padding-top: 8px; + padding-right: 106px; + min-height: 100px; } + .item-thumbnail-right > img:first-child, + .item-thumbnail-right .item-image, + .item-thumbnail-right .item-content > img:first-child, + .item-thumbnail-right .item-content .item-image { + position: absolute; + top: 10px; + right: 10px; + max-width: 80px; + max-height: 80px; + width: 100%; + height: 100%; } + + .item-avatar-right.item-complex, + .item-thumbnail-right.item-complex { + padding-top: 0; + padding-right: 0; } + + .item-image { + padding: 0; + text-align: center; } + .item-image img:first-child, .item-image .list-img { + width: 100%; + vertical-align: middle; } + + .item-body { + overflow: auto; + padding: 16px; + text-overflow: inherit; + white-space: normal; } + .item-body h1, .item-body h2, .item-body h3, .item-body h4, .item-body h5, .item-body h6, .item-body p { + margin-top: 16px; + margin-bottom: 16px; } + + .item-divider { + padding-top: 8px; + padding-bottom: 8px; + min-height: 30px; + background-color: #f5f5f5; + color: #222; + font-weight: 500; } + + .platform-ios .item-divider-platform, + .item-divider-ios { + padding-top: 26px; + text-transform: uppercase; + font-weight: 300; + font-size: 13px; + background-color: #efeff4; + color: #555; } + + .platform-android .item-divider-platform, + .item-divider-android { + font-weight: 300; + font-size: 13px; } + + .item-note { + float: right; + color: #aaa; + font-size: 14px; } + + .item-left-editable .item-content, + .item-right-editable .item-content { + -webkit-transition-duration: 250ms; + transition-duration: 250ms; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; + -webkit-transition-property: -webkit-transform; + -moz-transition-property: -moz-transform; + transition-property: transform; } + + .list-left-editing .item-left-editable .item-content, + .item-left-editing.item-left-editable .item-content { + -webkit-transform: translate3d(50px, 0, 0); + transform: translate3d(50px, 0, 0); } + + .item-remove-animate.ng-leave { + -webkit-transition-duration: 300ms; + transition-duration: 300ms; } + + .item-remove-animate.ng-leave .item-content, .item-remove-animate.ng-leave:last-of-type { + -webkit-transition-duration: 300ms; + transition-duration: 300ms; + -webkit-transition-timing-function: ease-in; + transition-timing-function: ease-in; + -webkit-transition-property: all; + transition-property: all; } + + .item-remove-animate.ng-leave.ng-leave-active .item-content { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0) !important; + transform: translate3d(-100%, 0, 0) !important; } + + .item-remove-animate.ng-leave.ng-leave-active:last-of-type { + opacity: 0; } + + .item-remove-animate.ng-leave.ng-leave-active ~ ion-item:not(.ng-leave) { + -webkit-transform: translate3d(0, -webkit-calc(-100% + 1px), 0); + transform: translate3d(0, calc(-100% + 1px), 0); + -webkit-transition-duration: 300ms; + transition-duration: 300ms; + -webkit-transition-timing-function: cubic-bezier(0.25, 0.81, 0.24, 1); + transition-timing-function: cubic-bezier(0.25, 0.81, 0.24, 1); + -webkit-transition-property: all; + transition-property: all; } + + .item-left-edit { + -webkit-transition: all ease-in-out 125ms; + transition: all ease-in-out 125ms; + position: absolute; + top: 0; + left: 0; + z-index: 0; + width: 50px; + height: 100%; + line-height: 100%; + display: none; + opacity: 0; + -webkit-transform: translate3d(-21px, 0, 0); + transform: translate3d(-21px, 0, 0); } + .item-left-edit .button { + height: 100%; } + .item-left-edit .button.icon, .item-left-edit .button.icon-help, .item-left-edit .button.icon-alert, .item-left-edit #menu .footer .button.icon-help, #menu .footer .item-left-edit .button.icon-help { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 0; + height: 100%; } + .item-left-edit.visible { + display: block; } + .item-left-edit.visible.active { + opacity: 1; + -webkit-transform: translate3d(8px, 0, 0); + transform: translate3d(8px, 0, 0); } + + .list-left-editing .item-left-edit { + -webkit-transition-delay: 125ms; + transition-delay: 125ms; } + + .item-delete .button.icon, .item-delete .button.icon-help, .item-delete .button.icon-alert, .item-delete #menu .footer .button.icon-help, #menu .footer .item-delete .button.icon-help { + color: #ef473a; + font-size: 24px; } + .item-delete .button.icon:hover, .item-delete .button.icon-help:hover, .item-delete .button.icon-alert:hover, .item-delete #menu .footer .button.icon-help:hover, #menu .footer .item-delete .button.icon-help:hover { + opacity: .7; } + + .item-right-edit { + -webkit-transition: all ease-in-out 250ms; + transition: all ease-in-out 250ms; + position: absolute; + top: 0; + right: 0; + z-index: 3; + width: 75px; + height: 100%; + background: inherit; + padding-left: 20px; + display: block; + opacity: 0; + -webkit-transform: translate3d(75px, 0, 0); + transform: translate3d(75px, 0, 0); } + .item-right-edit .button { + min-width: 50px; + height: 100%; } + .item-right-edit .button.icon, .item-right-edit .button.icon-help, .item-right-edit .button.icon-alert, .item-right-edit #menu .footer .button.icon-help, #menu .footer .item-right-edit .button.icon-help { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 0; + height: 100%; + font-size: 32px; } + .item-right-edit.visible { + display: block; } + .item-right-edit.visible.active { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + + .item-reorder .button.icon, .item-reorder .button.icon-help, .item-reorder .button.icon-alert, .item-reorder #menu .footer .button.icon-help, #menu .footer .item-reorder .button.icon-help { + color: #444; + font-size: 32px; } + + .item-reordering { + position: absolute; + left: 0; + top: 0; + z-index: 9; + width: 100%; + box-shadow: 0px 0px 10px 0px #aaa; } + .item-reordering .item-reorder { + z-index: 9; } + + .item-placeholder { + opacity: 0.7; } + + /** + * The hidden right-side buttons that can be exposed under a list item + * with dragging. + */ + .item-options { + position: absolute; + top: 0; + right: 0; + z-index: 1; + height: 100%; } + .item-options .button { + height: 100%; + border: none; + border-radius: 0; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -moz-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; } + .item-options .button:before { + margin: 0 auto; } + + /** + * Lists + * -------------------------------------------------- + */ + .list { + position: relative; + padding-top: 1px; + padding-bottom: 1px; + padding-left: 0; + margin-bottom: 20px; } + + .list:last-child { + margin-bottom: 0px; } + .list:last-child.card { + margin-bottom: 40px; } + + /** + * List Header + * -------------------------------------------------- + */ + .list-header { + margin-top: 20px; + padding: 5px 15px; + background-color: transparent; + color: #222; + font-weight: bold; } + + .card.list .list-item { + padding-right: 1px; + padding-left: 1px; } + + /** + * Cards and Inset Lists + * -------------------------------------------------- + * A card and list-inset are close to the same thing, except a card as a box shadow. + */ + .card, + .list-inset { + overflow: hidden; + margin: 20px 10px; + border-radius: 2px; + background-color: #fff; } + + .card { + padding-top: 1px; + padding-bottom: 1px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); } + .card .item { + border-left: 0; + border-right: 0; } + .card .item:first-child { + border-top: 0; } + .card .item:last-child { + border-bottom: 0; } + + .padding .card, .item.large-button-bar .card, .padding .list-inset, .item.large-button-bar .list-inset { + margin-left: 0; + margin-right: 0; } + + .card .item:first-child, + .list-inset .item:first-child, + .padding > .list .item:first-child, .item.large-button-bar > .list .item:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; } + .card .item:first-child .item-content, + .list-inset .item:first-child .item-content, + .padding > .list .item:first-child .item-content, .item.large-button-bar > .list .item:first-child .item-content { + border-top-left-radius: 2px; + border-top-right-radius: 2px; } + + .card .item:last-child, + .list-inset .item:last-child, + .padding > .list .item:last-child, .item.large-button-bar > .list .item:last-child { + border-bottom-right-radius: 2px; + border-bottom-left-radius: 2px; } + .card .item:last-child .item-content, + .list-inset .item:last-child .item-content, + .padding > .list .item:last-child .item-content, .item.large-button-bar > .list .item:last-child .item-content { + border-bottom-right-radius: 2px; + border-bottom-left-radius: 2px; } + + .card .item:last-child, + .list-inset .item:last-child { + margin-bottom: -1px; } + + .card .item, + .list-inset .item, + .padding > .list .item, .item.large-button-bar > .list .item, + .padding-horizontal > .list .item { + margin-right: 0; + margin-left: 0; } + .card .item.item-input input, + .list-inset .item.item-input input, + .padding > .list .item.item-input input, .item.large-button-bar > .list .item.item-input input, + .padding-horizontal > .list .item.item-input input { + padding-right: 44px; } + + .padding-left > .list .item { + margin-left: 0; } + + .padding-right > .list .item, .popover-share .bar-footer .button-close > .list .item { + margin-right: 0; } + + /** + * Badges + * -------------------------------------------------- + */ + .badge { + background-color: transparent; + color: #AAAAAA; + z-index: 1; + display: inline-block; + padding: 3px 8px; + min-width: 10px; + border-radius: 10px; + vertical-align: baseline; + text-align: center; + white-space: nowrap; + font-weight: bold; + font-size: 14px; + line-height: 16px; } + .badge:empty { + display: none; } + + .tabs .tab-item .badge.badge-light, + .badge.badge-light { + background-color: #fff; + color: #444; } + + .tabs .tab-item .badge.badge-stable, + .badge.badge-stable { + background-color: #f8f8f8; + color: #444; } + + .tabs .tab-item .badge.badge-positive, + .badge.badge-positive { + background-color: #387ef5; + color: #fff; } + + .tabs .tab-item .badge.badge-calm, + .badge.badge-calm { + background-color: #11c1f3; + color: #fff; } + + .tabs .tab-item .badge.badge-assertive, .tabs .tab-item .badge.badge-editable:hover, + .badge.badge-assertive, + .badge.badge-editable:hover { + background-color: #ef473a; + color: #fff; } + + .tabs .tab-item .badge.badge-balanced, + .badge.badge-balanced { + background-color: #33cd5f; + color: #fff; } + + .tabs .tab-item .badge.badge-energized, + .badge.badge-energized { + background-color: #ffc900; + color: #fff; } + + .tabs .tab-item .badge.badge-royal, + .badge.badge-royal { + background-color: #886aea; + color: #fff; } + + .tabs .tab-item .badge.badge-dark, + .badge.badge-dark { + background-color: #444; + color: #fff; } + + .button .badge { + position: relative; + top: -1px; } + + /** + * Slide Box + * -------------------------------------------------- + */ + .slider { + position: relative; + visibility: hidden; + overflow: hidden; } + + .slider-slides { + position: relative; + height: 100%; } + + .slider-slide { + position: relative; + display: block; + float: left; + width: 100%; + height: 100%; + vertical-align: top; } + + .slider-slide-image > img { + width: 100%; } + + .slider-pager { + position: absolute; + bottom: 20px; + z-index: 1; + width: 100%; + height: 15px; + text-align: center; } + .slider-pager .slider-pager-page { + display: inline-block; + margin: 0px 3px; + width: 15px; + color: #000; + text-decoration: none; + opacity: 0.3; } + .slider-pager .slider-pager-page.active { + -webkit-transition: opacity 0.4s ease-in; + transition: opacity 0.4s ease-in; + opacity: 1; } + + .slider-slide.ng-enter, .slider-slide.ng-leave, .slider-slide.ng-animate, + .slider-pager-page.ng-enter, + .slider-pager-page.ng-leave, + .slider-pager-page.ng-animate { + -webkit-transition: none !important; + transition: none !important; } + + .slider-slide.ng-animate, + .slider-pager-page.ng-animate { + -webkit-animation: none 0s; + animation: none 0s; } + + /** + * Swiper 3.2.7 + * Most modern mobile touch slider and framework with hardware accelerated transitions + * + * http://www.idangero.us/swiper/ + * + * Copyright 2015, Vladimir Kharlampidi + * The iDangero.us + * http://www.idangero.us/ + * + * Licensed under MIT + * + * Released on: December 7, 2015 + */ + .swiper-container { + margin: 0 auto; + position: relative; + overflow: hidden; + /* Fix of Webkit flickering */ + z-index: 1; } + + .swiper-container-no-flexbox .swiper-slide { + float: left; } + + .swiper-container-vertical > .swiper-wrapper { + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -ms-flex-direction: column; + -webkit-flex-direction: column; + flex-direction: column; } + + .swiper-wrapper { + position: relative; + width: 100%; + height: 100%; + z-index: 1; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; + -webkit-transition-property: -webkit-transform; + -moz-transition-property: -moz-transform; + -o-transition-property: -o-transform; + -ms-transition-property: -ms-transform; + transition-property: transform; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; } + + .swiper-container-android .swiper-slide, + .swiper-wrapper { + -webkit-transform: translate3d(0px, 0, 0); + -moz-transform: translate3d(0px, 0, 0); + -o-transform: translate(0px, 0px); + -ms-transform: translate3d(0px, 0, 0); + transform: translate3d(0px, 0, 0); } + + .swiper-container-multirow > .swiper-wrapper { + -webkit-box-lines: multiple; + -moz-box-lines: multiple; + -ms-flex-wrap: wrap; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; } + + .swiper-container-free-mode > .swiper-wrapper { + -webkit-transition-timing-function: ease-out; + -moz-transition-timing-function: ease-out; + -ms-transition-timing-function: ease-out; + -o-transition-timing-function: ease-out; + transition-timing-function: ease-out; + margin: 0 auto; } + + .swiper-slide { + display: block; + -webkit-flex-shrink: 0; + -ms-flex: 0 0 auto; + flex-shrink: 0; + width: 100%; + height: 100%; + position: relative; } + + /* Auto Height */ + .swiper-container-autoheight, + .swiper-container-autoheight .swiper-slide { + height: auto; } + + .swiper-container-autoheight .swiper-wrapper { + -webkit-box-align: start; + -ms-flex-align: start; + -webkit-align-items: flex-start; + align-items: flex-start; + -webkit-transition-property: -webkit-transform, height; + -moz-transition-property: -moz-transform; + -o-transition-property: -o-transform; + -ms-transition-property: -ms-transform; + transition-property: transform, height; } + + /* a11y */ + .swiper-container .swiper-notification { + position: absolute; + left: 0; + top: 0; + pointer-events: none; + opacity: 0; + z-index: -1000; } + + /* IE10 Windows Phone 8 Fixes */ + .swiper-wp8-horizontal { + -ms-touch-action: pan-y; + touch-action: pan-y; } + + .swiper-wp8-vertical { + -ms-touch-action: pan-x; + touch-action: pan-x; } + + /* Arrows */ + .swiper-button-prev, + .swiper-button-next { + position: absolute; + top: 50%; + width: 27px; + height: 44px; + margin-top: -22px; + z-index: 10; + cursor: pointer; + -moz-background-size: 27px 44px; + -webkit-background-size: 27px 44px; + background-size: 27px 44px; + background-position: center; + background-repeat: no-repeat; } + + .swiper-button-prev.swiper-button-disabled, + .swiper-button-next.swiper-button-disabled { + opacity: 0.35; + cursor: auto; + pointer-events: none; } + + .swiper-button-prev, + .swiper-container-rtl .swiper-button-next { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E"); + left: 10px; + right: auto; } + + .swiper-button-prev.swiper-button-black, + .swiper-container-rtl .swiper-button-next.swiper-button-black { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E"); } + + .swiper-button-prev.swiper-button-white, + .swiper-container-rtl .swiper-button-next.swiper-button-white { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E"); } + + .swiper-button-next, + .swiper-container-rtl .swiper-button-prev { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E"); + right: 10px; + left: auto; } + + .swiper-button-next.swiper-button-black, + .swiper-container-rtl .swiper-button-prev.swiper-button-black { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E"); } + + .swiper-button-next.swiper-button-white, + .swiper-container-rtl .swiper-button-prev.swiper-button-white { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E"); } + + /* Pagination Styles */ + .swiper-pagination { + position: absolute; + text-align: center; + -webkit-transition: 300ms; + -moz-transition: 300ms; + -o-transition: 300ms; + transition: 300ms; + -webkit-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + z-index: 10; } + + .swiper-pagination.swiper-pagination-hidden { + opacity: 0; } + + .swiper-pagination-bullet { + width: 8px; + height: 8px; + display: inline-block; + border-radius: 100%; + background: #000; + opacity: 0.2; } + + button.swiper-pagination-bullet { + border: none; + margin: 0; + padding: 0; + box-shadow: none; + -moz-appearance: none; + -ms-appearance: none; + -webkit-appearance: none; + appearance: none; } + + .swiper-pagination-clickable .swiper-pagination-bullet { + cursor: pointer; } + + .swiper-pagination-white .swiper-pagination-bullet { + background: #fff; } + + .swiper-pagination-bullet-active { + opacity: 1; } + + .swiper-pagination-white .swiper-pagination-bullet-active { + background: #fff; } + + .swiper-pagination-black .swiper-pagination-bullet-active { + background: #000; } + + .swiper-container-vertical > .swiper-pagination { + right: 10px; + top: 50%; + -webkit-transform: translate3d(0px, -50%, 0); + -moz-transform: translate3d(0px, -50%, 0); + -o-transform: translate(0px, -50%); + -ms-transform: translate3d(0px, -50%, 0); + transform: translate3d(0px, -50%, 0); } + + .swiper-container-vertical > .swiper-pagination .swiper-pagination-bullet { + margin: 5px 0; + display: block; } + + .swiper-container-horizontal > .swiper-pagination { + bottom: 10px; + left: 0; + width: 100%; } + + .swiper-container-horizontal > .swiper-pagination .swiper-pagination-bullet { + margin: 0 5px; } + + /* 3D Container */ + .swiper-container-3d { + -webkit-perspective: 1200px; + -moz-perspective: 1200px; + -o-perspective: 1200px; + perspective: 1200px; } + + .swiper-container-3d .swiper-wrapper, + .swiper-container-3d .swiper-slide, + .swiper-container-3d .swiper-slide-shadow-left, + .swiper-container-3d .swiper-slide-shadow-right, + .swiper-container-3d .swiper-slide-shadow-top, + .swiper-container-3d .swiper-slide-shadow-bottom, + .swiper-container-3d .swiper-cube-shadow { + -webkit-transform-style: preserve-3d; + -moz-transform-style: preserve-3d; + -ms-transform-style: preserve-3d; + transform-style: preserve-3d; } + + .swiper-container-3d .swiper-slide-shadow-left, + .swiper-container-3d .swiper-slide-shadow-right, + .swiper-container-3d .swiper-slide-shadow-top, + .swiper-container-3d .swiper-slide-shadow-bottom { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 10; } + + .swiper-container-3d .swiper-slide-shadow-left { + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(transparent)); + /* Safari 4+, Chrome */ + background-image: -webkit-linear-gradient(right, rgba(0, 0, 0, 0.5), transparent); + /* Chrome 10+, Safari 5.1+, iOS 5+ */ + background-image: -moz-linear-gradient(right, rgba(0, 0, 0, 0.5), transparent); + /* Firefox 3.6-15 */ + background-image: -o-linear-gradient(right, rgba(0, 0, 0, 0.5), transparent); + /* Opera 11.10-12.00 */ + background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), transparent); + /* Firefox 16+, IE10, Opera 12.50+ */ } + + .swiper-container-3d .swiper-slide-shadow-right { + background-image: -webkit-gradient(linear, right top, left top, from(rgba(0, 0, 0, 0.5)), to(transparent)); + /* Safari 4+, Chrome */ + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5), transparent); + /* Chrome 10+, Safari 5.1+, iOS 5+ */ + background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.5), transparent); + /* Firefox 3.6-15 */ + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5), transparent); + /* Opera 11.10-12.00 */ + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5), transparent); + /* Firefox 16+, IE10, Opera 12.50+ */ } + + .swiper-container-3d .swiper-slide-shadow-top { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.5)), to(transparent)); + /* Safari 4+, Chrome */ + background-image: -webkit-linear-gradient(bottom, rgba(0, 0, 0, 0.5), transparent); + /* Chrome 10+, Safari 5.1+, iOS 5+ */ + background-image: -moz-linear-gradient(bottom, rgba(0, 0, 0, 0.5), transparent); + /* Firefox 3.6-15 */ + background-image: -o-linear-gradient(bottom, rgba(0, 0, 0, 0.5), transparent); + /* Opera 11.10-12.00 */ + background-image: linear-gradient(to top, rgba(0, 0, 0, 0.5), transparent); + /* Firefox 16+, IE10, Opera 12.50+ */ } + + .swiper-container-3d .swiper-slide-shadow-bottom { + background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0.5)), to(transparent)); + /* Safari 4+, Chrome */ + background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.5), transparent); + /* Chrome 10+, Safari 5.1+, iOS 5+ */ + background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.5), transparent); + /* Firefox 3.6-15 */ + background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.5), transparent); + /* Opera 11.10-12.00 */ + background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), transparent); + /* Firefox 16+, IE10, Opera 12.50+ */ } + + /* Coverflow */ + .swiper-container-coverflow .swiper-wrapper { + /* Windows 8 IE 10 fix */ + -ms-perspective: 1200px; } + + /* Fade */ + .swiper-container-fade.swiper-container-free-mode .swiper-slide { + -webkit-transition-timing-function: ease-out; + -moz-transition-timing-function: ease-out; + -ms-transition-timing-function: ease-out; + -o-transition-timing-function: ease-out; + transition-timing-function: ease-out; } + + .swiper-container-fade .swiper-slide { + pointer-events: none; } + + .swiper-container-fade .swiper-slide .swiper-slide { + pointer-events: none; } + + .swiper-container-fade .swiper-slide-active, + .swiper-container-fade .swiper-slide-active .swiper-slide-active { + pointer-events: auto; } + + /* Cube */ + .swiper-container-cube { + overflow: visible; } + + .swiper-container-cube .swiper-slide { + pointer-events: none; + visibility: hidden; + -webkit-transform-origin: 0 0; + -moz-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; + width: 100%; + height: 100%; + z-index: 1; } + + .swiper-container-cube.swiper-container-rtl .swiper-slide { + -webkit-transform-origin: 100% 0; + -moz-transform-origin: 100% 0; + -ms-transform-origin: 100% 0; + transform-origin: 100% 0; } + + .swiper-container-cube .swiper-slide-active, + .swiper-container-cube .swiper-slide-next, + .swiper-container-cube .swiper-slide-prev, + .swiper-container-cube .swiper-slide-next + .swiper-slide { + pointer-events: auto; + visibility: visible; } + + .swiper-container-cube .swiper-slide-shadow-top, + .swiper-container-cube .swiper-slide-shadow-bottom, + .swiper-container-cube .swiper-slide-shadow-left, + .swiper-container-cube .swiper-slide-shadow-right { + z-index: 0; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; } + + .swiper-container-cube .swiper-cube-shadow { + position: absolute; + left: 0; + bottom: 0px; + width: 100%; + height: 100%; + background: #000; + opacity: 0.6; + -webkit-filter: blur(50px); + filter: blur(50px); + z-index: 0; } + + /* Scrollbar */ + .swiper-scrollbar { + border-radius: 10px; + position: relative; + -ms-touch-action: none; + background: rgba(0, 0, 0, 0.1); } + + .swiper-container-horizontal > .swiper-scrollbar { + position: absolute; + left: 1%; + bottom: 3px; + z-index: 50; + height: 5px; + width: 98%; } + + .swiper-container-vertical > .swiper-scrollbar { + position: absolute; + right: 3px; + top: 1%; + z-index: 50; + width: 5px; + height: 98%; } + + .swiper-scrollbar-drag { + height: 100%; + width: 100%; + position: relative; + background: rgba(0, 0, 0, 0.5); + border-radius: 10px; + left: 0; + top: 0; } + + .swiper-scrollbar-cursor-drag { + cursor: move; } + + /* Preloader */ + .swiper-lazy-preloader { + width: 42px; + height: 42px; + position: absolute; + left: 50%; + top: 50%; + margin-left: -21px; + margin-top: -21px; + z-index: 10; + -webkit-transform-origin: 50%; + -moz-transform-origin: 50%; + transform-origin: 50%; + -webkit-animation: swiper-preloader-spin 1s steps(12, end) infinite; + -moz-animation: swiper-preloader-spin 1s steps(12, end) infinite; + animation: swiper-preloader-spin 1s steps(12, end) infinite; } + + .swiper-lazy-preloader:after { + display: block; + content: ""; + width: 100%; + height: 100%; + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%236c6c6c'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"); + background-position: 50%; + -webkit-background-size: 100%; + background-size: 100%; + background-repeat: no-repeat; } + + .swiper-lazy-preloader-white:after { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%23fff'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"); } + + @-webkit-keyframes swiper-preloader-spin { + 100% { + -webkit-transform: rotate(360deg); } } + + @keyframes swiper-preloader-spin { + 100% { + transform: rotate(360deg); } } + + ion-slides { + width: 100%; + height: 100%; + display: block; } + + .slide-zoom { + display: block; + width: 100%; + text-align: center; } + + .swiper-container { + width: 100%; + height: 100%; + padding: 0; + overflow: hidden; } + + .swiper-wrapper { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + padding: 0; } + + .swiper-slide { + width: 100%; + height: 100%; + box-sizing: border-box; + /* Center slide text vertically */ } + .swiper-slide img { + width: auto; + height: auto; + max-width: 100%; + max-height: 100%; } + + .scroll-refresher { + position: absolute; + top: -60px; + right: 0; + left: 0; + overflow: hidden; + margin: auto; + height: 60px; } + .scroll-refresher .ionic-refresher-content { + position: absolute; + bottom: 15px; + left: 0; + width: 100%; + color: #666666; + text-align: center; + font-size: 30px; } + .scroll-refresher .ionic-refresher-content .text-refreshing, + .scroll-refresher .ionic-refresher-content .text-pulling { + font-size: 16px; + line-height: 16px; } + .scroll-refresher .ionic-refresher-content.ionic-refresher-with-text { + bottom: 10px; } + .scroll-refresher .icon-refreshing, + .scroll-refresher .icon-pulling { + width: 100%; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transform-style: preserve-3d; + transform-style: preserve-3d; } + .scroll-refresher .icon-pulling { + -webkit-animation-name: refresh-spin-back; + animation-name: refresh-spin-back; + -webkit-animation-duration: 200ms; + animation-duration: 200ms; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; + -webkit-animation-fill-mode: none; + animation-fill-mode: none; + -webkit-transform: translate3d(0, 0, 0) rotate(0deg); + transform: translate3d(0, 0, 0) rotate(0deg); } + .scroll-refresher .icon-refreshing, + .scroll-refresher .text-refreshing { + display: none; } + .scroll-refresher .icon-refreshing { + -webkit-animation-duration: 1.5s; + animation-duration: 1.5s; } + .scroll-refresher.active .icon-pulling:not(.pulling-rotation-disabled) { + -webkit-animation-name: refresh-spin; + animation-name: refresh-spin; + -webkit-transform: translate3d(0, 0, 0) rotate(-180deg); + transform: translate3d(0, 0, 0) rotate(-180deg); } + .scroll-refresher.active.refreshing { + -webkit-transition: -webkit-transform 0.2s; + transition: -webkit-transform 0.2s; + -webkit-transition: transform 0.2s; + transition: transform 0.2s; + -webkit-transform: scale(1, 1); + transform: scale(1, 1); } + .scroll-refresher.active.refreshing .icon-pulling, + .scroll-refresher.active.refreshing .text-pulling { + display: none; } + .scroll-refresher.active.refreshing .icon-refreshing, + .scroll-refresher.active.refreshing .text-refreshing { + display: block; } + .scroll-refresher.active.refreshing.refreshing-tail { + -webkit-transform: scale(0, 0); + transform: scale(0, 0); } + + .overflow-scroll > .scroll { + -webkit-overflow-scrolling: touch; + width: 100%; } + .overflow-scroll > .scroll.overscroll { + position: fixed; + right: 0; + left: 0; } + + .overflow-scroll.padding > .scroll.overscroll, .overflow-scroll.item.large-button-bar > .scroll.overscroll { + padding: 10px; } + + @-webkit-keyframes refresh-spin { + 0% { + -webkit-transform: translate3d(0, 0, 0) rotate(0); } + 100% { + -webkit-transform: translate3d(0, 0, 0) rotate(180deg); } } + + @keyframes refresh-spin { + 0% { + transform: translate3d(0, 0, 0) rotate(0); } + 100% { + transform: translate3d(0, 0, 0) rotate(180deg); } } + + @-webkit-keyframes refresh-spin-back { + 0% { + -webkit-transform: translate3d(0, 0, 0) rotate(180deg); } + 100% { + -webkit-transform: translate3d(0, 0, 0) rotate(0); } } + + @keyframes refresh-spin-back { + 0% { + transform: translate3d(0, 0, 0) rotate(180deg); } + 100% { + transform: translate3d(0, 0, 0) rotate(0); } } + + /** + * Spinners + * -------------------------------------------------- + */ + .spinner { + stroke: #444; + fill: #444; } + .spinner svg { + width: 28px; + height: 28px; } + .spinner.spinner-light { + stroke: #fff; + fill: #fff; } + .spinner.spinner-stable { + stroke: #f8f8f8; + fill: #f8f8f8; } + .spinner.spinner-positive { + stroke: #387ef5; + fill: #387ef5; } + .spinner.spinner-calm { + stroke: #11c1f3; + fill: #11c1f3; } + .spinner.spinner-balanced { + stroke: #33cd5f; + fill: #33cd5f; } + .spinner.spinner-assertive { + stroke: #ef473a; + fill: #ef473a; } + .spinner.spinner-energized { + stroke: #ffc900; + fill: #ffc900; } + .spinner.spinner-royal { + stroke: #886aea; + fill: #886aea; } + .spinner.spinner-dark { + stroke: #444; + fill: #444; } + + .spinner-android { + stroke: #4b8bf4; } + + .spinner-ios, + .spinner-ios-small { + stroke: #69717d; } + + .spinner-spiral .stop1 { + stop-color: #fff; + stop-opacity: 0; } + + .spinner-spiral.spinner-light .stop1 { + stop-color: #444; } + + .spinner-spiral.spinner-light .stop2 { + stop-color: #fff; } + + .spinner-spiral.spinner-stable .stop2 { + stop-color: #f8f8f8; } + + .spinner-spiral.spinner-positive .stop2 { + stop-color: #387ef5; } + + .spinner-spiral.spinner-calm .stop2 { + stop-color: #11c1f3; } + + .spinner-spiral.spinner-balanced .stop2 { + stop-color: #33cd5f; } + + .spinner-spiral.spinner-assertive .stop2 { + stop-color: #ef473a; } + + .spinner-spiral.spinner-energized .stop2 { + stop-color: #ffc900; } + + .spinner-spiral.spinner-royal .stop2 { + stop-color: #886aea; } + + .spinner-spiral.spinner-dark .stop2 { + stop-color: #444; } + + /** + * Forms + * -------------------------------------------------- + */ + form { + margin: 0 0 1.42857; } + + legend { + display: block; + margin-bottom: 1.42857; + padding: 0; + width: 100%; + border: 1px solid #ddd; + color: #444; + font-size: 21px; + line-height: 2.85714; } + legend small { + color: #f8f8f8; + font-size: 1.07143; } + + label, + input, + button, + select, + textarea { + font-weight: normal; + font-size: 14px; + line-height: 1.42857; } + + input, + button, + select, + textarea { + font-family: "-apple-system", "Helvetica Neue", "Roboto", "Segoe UI", sans-serif; } + + .item-input { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: relative; + overflow: hidden; + padding: 6px 0 5px 16px; } + .item-input input { + -webkit-border-radius: 0; + border-radius: 0; + -webkit-box-flex: 1; + -webkit-flex: 1 220px; + -moz-box-flex: 1; + -moz-flex: 1 220px; + -ms-flex: 1 220px; + flex: 1 220px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + margin: 0; + padding-right: 24px; + background-color: transparent; } + .item-input .button .icon, .item-input .button .icon-help, .item-input .button .icon-alert, .item-input .button #menu .footer .icon-help, #menu .footer .item-input .button .icon-help { + -webkit-box-flex: 0; + -webkit-flex: 0 0 24px; + -moz-box-flex: 0; + -moz-flex: 0 0 24px; + -ms-flex: 0 0 24px; + flex: 0 0 24px; + position: static; + display: inline-block; + height: auto; + text-align: center; + font-size: 16px; } + .item-input .button-bar { + -webkit-border-radius: 0; + border-radius: 0; + -webkit-box-flex: 1; + -webkit-flex: 1 0 220px; + -moz-box-flex: 1; + -moz-flex: 1 0 220px; + -ms-flex: 1 0 220px; + flex: 1 0 220px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } + .item-input .icon, .item-input .icon-help, .item-input .icon-alert, .item-input #menu .footer .icon-help, #menu .footer .item-input .icon-help { + min-width: 14px; } + + .platform-windowsphone .item-input input { + flex-shrink: 1; } + + .item-input-inset { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: relative; + overflow: hidden; + padding: 10.66667px; } + + .item-input-wrapper { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -webkit-flex: 1 0; + -moz-box-flex: 1; + -moz-flex: 1 0; + -ms-flex: 1 0; + flex: 1 0; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + -webkit-border-radius: 4px; + border-radius: 4px; + padding-right: 8px; + padding-left: 8px; + background: #eee; } + + .item-input-inset .item-input-wrapper input { + padding-left: 4px; + height: 29px; + background: transparent; + line-height: 18px; } + + .item-input-wrapper ~ .button { + margin-left: 10.66667px; } + + .input-label { + display: table; + padding: 7px 10px 7px 0px; + max-width: 200px; + width: 35%; + color: #444; + font-size: 16px; } + + .placeholder-icon { + color: #aaa; } + .placeholder-icon:first-child { + padding-right: 6px; } + .placeholder-icon:last-child { + padding-left: 6px; } + + .item-stacked-label { + display: block; + background-color: transparent; + box-shadow: none; } + .item-stacked-label .input-label, .item-stacked-label .icon, .item-stacked-label .icon-help, .item-stacked-label .icon-alert, .item-stacked-label #menu .footer .icon-help, #menu .footer .item-stacked-label .icon-help { + display: inline-block; + padding: 4px 0 0 0px; + vertical-align: middle; } + + .item-stacked-label input, + .item-stacked-label textarea { + -webkit-border-radius: 2px; + border-radius: 2px; + padding: 4px 8px 3px 0; + border: none; + background-color: #fff; } + + .item-stacked-label input { + overflow: hidden; + height: 46px; } + + .item-select.item-stacked-label select { + position: relative; + padding: 0px; + max-width: 90%; + direction: ltr; + white-space: pre-wrap; + margin: -3px; } + + .item-floating-label { + display: block; + background-color: transparent; + box-shadow: none; } + .item-floating-label .input-label { + position: relative; + padding: 5px 0 0 0; + opacity: 0; + top: 10px; + -webkit-transition: opacity 0.15s ease-in, top 0.2s linear; + transition: opacity 0.15s ease-in, top 0.2s linear; } + .item-floating-label .input-label.has-input { + opacity: 1; + top: 0; + -webkit-transition: opacity 0.15s ease-in, top 0.2s linear; + transition: opacity 0.15s ease-in, top 0.2s linear; } + + textarea, + input[type="text"], + input[type="password"], + input[type="datetime"], + input[type="datetime-local"], + input[type="date"], + input[type="month"], + input[type="time"], + input[type="week"], + input[type="number"], + input[type="email"], + input[type="url"], + input[type="search"], + input[type="tel"], + input[type="color"] { + display: block; + padding-top: 2px; + padding-left: 0; + height: 34px; + color: #111; + vertical-align: middle; + font-size: 14px; + line-height: 16px; } + + .platform-ios input[type="datetime-local"], + .platform-ios input[type="date"], + .platform-ios input[type="month"], + .platform-ios input[type="time"], + .platform-ios input[type="week"], + .platform-android input[type="datetime-local"], + .platform-android input[type="date"], + .platform-android input[type="month"], + .platform-android input[type="time"], + .platform-android input[type="week"] { + padding-top: 8px; } + + .item-input input, + .item-input textarea { + width: 100%; } + + textarea { + padding-left: 0; } + textarea::-moz-placeholder { + color: #aaaaaa; } + textarea:-ms-input-placeholder { + color: #aaaaaa; } + textarea::-webkit-input-placeholder { + color: #aaaaaa; + text-indent: -3px; } + + textarea { + height: auto; } + + textarea, + input[type="text"], + input[type="password"], + input[type="datetime"], + input[type="datetime-local"], + input[type="date"], + input[type="month"], + input[type="time"], + input[type="week"], + input[type="number"], + input[type="email"], + input[type="url"], + input[type="search"], + input[type="tel"], + input[type="color"] { + border: 0; } + + input[type="radio"], + input[type="checkbox"] { + margin: 0; + line-height: normal; } + + .item-input input[type="file"], + .item-input input[type="image"], + .item-input input[type="submit"], + .item-input input[type="reset"], + .item-input input[type="button"], + .item-input input[type="radio"], + .item-input input[type="checkbox"] { + width: auto; } + + input[type="file"] { + line-height: 34px; } + + .previous-input-focus, + .cloned-text-input + input, + .cloned-text-input + textarea { + position: absolute !important; + left: -9999px; + width: 200px; } + + input::-moz-placeholder, + textarea::-moz-placeholder { + color: #aaaaaa; } + + input:-ms-input-placeholder, + textarea:-ms-input-placeholder { + color: #aaaaaa; } + + input::-webkit-input-placeholder, + textarea::-webkit-input-placeholder { + color: #aaaaaa; + text-indent: 0; } + + input[disabled], + select[disabled], + textarea[disabled], + input[readonly]:not(.cloned-text-input), + textarea[readonly]:not(.cloned-text-input), + select[readonly] { + background-color: #f8f8f8; + cursor: not-allowed; } + + input[type="radio"][disabled], + input[type="checkbox"][disabled], + input[type="radio"][readonly], + input[type="checkbox"][readonly] { + background-color: transparent; } + + /** + * Checkbox + * -------------------------------------------------- + */ + .checkbox { + position: relative; + display: inline-block; + padding: 7px 7px; + cursor: pointer; } + .checkbox input:before, + .checkbox .checkbox-icon:before { + border-color: #ddd; } + .checkbox input:checked:before, + .checkbox input:checked + .checkbox-icon:before { + background: #387ef5; + border-color: #387ef5; } + + .checkbox-light input:before, + .checkbox-light .checkbox-icon:before { + border-color: #ddd; } + + .checkbox-light input:checked:before, + .checkbox-light input:checked + .checkbox-icon:before { + background: #ddd; + border-color: #ddd; } + + .checkbox-stable input:before, + .checkbox-stable .checkbox-icon:before { + border-color: #b2b2b2; } + + .checkbox-stable input:checked:before, + .checkbox-stable input:checked + .checkbox-icon:before { + background: #b2b2b2; + border-color: #b2b2b2; } + + .checkbox-positive input:before, + .checkbox-positive .checkbox-icon:before { + border-color: #387ef5; } + + .checkbox-positive input:checked:before, + .checkbox-positive input:checked + .checkbox-icon:before { + background: #387ef5; + border-color: #387ef5; } + + .checkbox-calm input:before, + .checkbox-calm .checkbox-icon:before { + border-color: #11c1f3; } + + .checkbox-calm input:checked:before, + .checkbox-calm input:checked + .checkbox-icon:before { + background: #11c1f3; + border-color: #11c1f3; } + + .checkbox-assertive input:before, + .checkbox-assertive .checkbox-icon:before { + border-color: #ef473a; } + + .checkbox-assertive input:checked:before, + .checkbox-assertive input:checked + .checkbox-icon:before { + background: #ef473a; + border-color: #ef473a; } + + .checkbox-balanced input:before, + .checkbox-balanced .checkbox-icon:before { + border-color: #33cd5f; } + + .checkbox-balanced input:checked:before, + .checkbox-balanced input:checked + .checkbox-icon:before { + background: #33cd5f; + border-color: #33cd5f; } + + .checkbox-energized input:before, + .checkbox-energized .checkbox-icon:before { + border-color: #ffc900; } + + .checkbox-energized input:checked:before, + .checkbox-energized input:checked + .checkbox-icon:before { + background: #ffc900; + border-color: #ffc900; } + + .checkbox-royal input:before, + .checkbox-royal .checkbox-icon:before { + border-color: #886aea; } + + .checkbox-royal input:checked:before, + .checkbox-royal input:checked + .checkbox-icon:before { + background: #886aea; + border-color: #886aea; } + + .checkbox-dark input:before, + .checkbox-dark .checkbox-icon:before { + border-color: #444; } + + .checkbox-dark input:checked:before, + .checkbox-dark input:checked + .checkbox-icon:before { + background: #444; + border-color: #444; } + + .checkbox input:disabled:before, + .checkbox input:disabled + .checkbox-icon:before { + border-color: #ddd; } + + .checkbox input:disabled:checked:before, + .checkbox input:disabled:checked + .checkbox-icon:before { + background: #ddd; } + + .checkbox.checkbox-input-hidden input { + display: none !important; } + + .checkbox input, + .checkbox-icon { + position: relative; + width: 28px; + height: 28px; + display: block; + border: 0; + background: transparent; + cursor: pointer; + -webkit-appearance: none; } + .checkbox input:before, + .checkbox-icon:before { + display: table; + width: 100%; + height: 100%; + border-width: 1px; + border-style: solid; + border-radius: 28px; + background: #fff; + content: ' '; + -webkit-transition: background-color 20ms ease-in-out; + transition: background-color 20ms ease-in-out; } + + .checkbox input:checked:before, + input:checked + .checkbox-icon:before { + border-width: 2px; } + + .checkbox input:after, + .checkbox-icon:after { + -webkit-transition: opacity 0.05s ease-in-out; + transition: opacity 0.05s ease-in-out; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + position: absolute; + top: 33%; + left: 25%; + display: table; + width: 14px; + height: 6px; + border: 1px solid #fff; + border-top: 0; + border-right: 0; + content: ' '; + opacity: 0; } + + .platform-android .checkbox-platform input:before, + .platform-android .checkbox-platform .checkbox-icon:before, + .checkbox-square input:before, + .checkbox-square .checkbox-icon:before { + border-radius: 2px; + width: 72%; + height: 72%; + margin-top: 14%; + margin-left: 14%; + border-width: 2px; } + + .platform-android .checkbox-platform input:after, + .platform-android .checkbox-platform .checkbox-icon:after, + .checkbox-square input:after, + .checkbox-square .checkbox-icon:after { + border-width: 2px; + top: 19%; + left: 25%; + width: 13px; + height: 7px; } + + .platform-android .item-checkbox-right .checkbox-square .checkbox-icon::after { + top: 31%; } + + .grade-c .checkbox input:after, + .grade-c .checkbox-icon:after { + -webkit-transform: rotate(0); + transform: rotate(0); + top: 3px; + left: 4px; + border: none; + color: #fff; + content: '\2713'; + font-weight: bold; + font-size: 20px; } + + .checkbox input:checked:after, + input:checked + .checkbox-icon:after { + opacity: 1; } + + .item-checkbox { + padding-left: 60px; } + .item-checkbox.active { + box-shadow: none; } + + .item-checkbox .checkbox { + position: absolute; + top: 50%; + right: 8px; + left: 8px; + z-index: 3; + margin-top: -21px; } + + .item-checkbox.item-checkbox-right { + padding-right: 60px; + padding-left: 16px; } + + .item-checkbox-right .checkbox input, + .item-checkbox-right .checkbox-icon { + float: right; } + + /** + * Toggle + * -------------------------------------------------- + */ + .item-toggle { + pointer-events: none; } + + .toggle { + position: relative; + display: inline-block; + pointer-events: auto; + margin: -5px; + padding: 5px; } + .toggle input:checked + .track { + border-color: #4cd964; + background-color: #4cd964; } + .toggle.dragging .handle { + background-color: #f2f2f2 !important; } + + .toggle.toggle-light input:checked + .track { + border-color: #ddd; + background-color: #ddd; } + + .toggle.toggle-stable input:checked + .track { + border-color: #b2b2b2; + background-color: #b2b2b2; } + + .toggle.toggle-positive input:checked + .track { + border-color: #387ef5; + background-color: #387ef5; } + + .toggle.toggle-calm input:checked + .track { + border-color: #11c1f3; + background-color: #11c1f3; } + + .toggle.toggle-assertive input:checked + .track { + border-color: #ef473a; + background-color: #ef473a; } + + .toggle.toggle-balanced input:checked + .track { + border-color: #33cd5f; + background-color: #33cd5f; } + + .toggle.toggle-energized input:checked + .track { + border-color: #ffc900; + background-color: #ffc900; } + + .toggle.toggle-royal input:checked + .track { + border-color: #886aea; + background-color: #886aea; } + + .toggle.toggle-dark input:checked + .track { + border-color: #444; + background-color: #444; } + + .toggle input { + display: none; } + + /* the track appearance when the toggle is "off" */ + .toggle .track { + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; + -webkit-transition-duration: 0.3s; + transition-duration: 0.3s; + -webkit-transition-property: background-color, border; + transition-property: background-color, border; + display: inline-block; + box-sizing: border-box; + width: 51px; + height: 31px; + border: solid 2px #e6e6e6; + border-radius: 20px; + background-color: #fff; + content: ' '; + cursor: pointer; + pointer-events: none; } + + /* Fix to avoid background color bleeding */ + /* (occurred on (at least) Android 4.2, Asus MeMO Pad HD7 ME173X) */ + .platform-android4_2 .toggle .track { + -webkit-background-clip: padding-box; } + + /* the handle (circle) thats inside the toggle's track area */ + /* also the handle's appearance when it is "off" */ + .toggle .handle { + -webkit-transition: 0.3s cubic-bezier(0, 1.1, 1, 1.1); + transition: 0.3s cubic-bezier(0, 1.1, 1, 1.1); + -webkit-transition-property: background-color, transform; + transition-property: background-color, transform; + position: absolute; + display: block; + width: 27px; + height: 27px; + border-radius: 27px; + background-color: #fff; + top: 7px; + left: 7px; + box-shadow: 0 2px 7px rgba(0, 0, 0, 0.35), 0 1px 1px rgba(0, 0, 0, 0.15); } + .toggle .handle:before { + position: absolute; + top: -4px; + left: -21.5px; + padding: 18.5px 34px; + content: " "; } + + .toggle input:checked + .track .handle { + -webkit-transform: translate3d(20px, 0, 0); + transform: translate3d(20px, 0, 0); + background-color: #fff; } + + .item-toggle.active { + box-shadow: none; } + + .item-toggle, + .item-toggle.item-complex .item-content { + padding-right: 99px; } + + .item-toggle.item-complex { + padding-right: 0; } + + .item-toggle .toggle { + position: absolute; + top: 10px; + right: 16px; + z-index: 3; } + + .toggle input:disabled + .track { + opacity: .6; } + + .toggle-small .track { + border: 0; + width: 34px; + height: 15px; + background: #9e9e9e; } + + .toggle-small input:checked + .track { + background: rgba(0, 150, 137, 0.5); } + + .toggle-small .handle { + top: 2px; + left: 4px; + width: 21px; + height: 21px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25); } + + .toggle-small input:checked + .track .handle { + -webkit-transform: translate3d(16px, 0, 0); + transform: translate3d(16px, 0, 0); + background: #009689; } + + .toggle-small.item-toggle .toggle { + top: 19px; } + + .toggle-small .toggle-light input:checked + .track { + background-color: rgba(221, 221, 221, 0.5); } + + .toggle-small .toggle-light input:checked + .track .handle { + background-color: #ddd; } + + .toggle-small .toggle-stable input:checked + .track { + background-color: rgba(178, 178, 178, 0.5); } + + .toggle-small .toggle-stable input:checked + .track .handle { + background-color: #b2b2b2; } + + .toggle-small .toggle-positive input:checked + .track { + background-color: rgba(56, 126, 245, 0.5); } + + .toggle-small .toggle-positive input:checked + .track .handle { + background-color: #387ef5; } + + .toggle-small .toggle-calm input:checked + .track { + background-color: rgba(17, 193, 243, 0.5); } + + .toggle-small .toggle-calm input:checked + .track .handle { + background-color: #11c1f3; } + + .toggle-small .toggle-assertive input:checked + .track { + background-color: rgba(239, 71, 58, 0.5); } + + .toggle-small .toggle-assertive input:checked + .track .handle { + background-color: #ef473a; } + + .toggle-small .toggle-balanced input:checked + .track { + background-color: rgba(51, 205, 95, 0.5); } + + .toggle-small .toggle-balanced input:checked + .track .handle { + background-color: #33cd5f; } + + .toggle-small .toggle-energized input:checked + .track { + background-color: rgba(255, 201, 0, 0.5); } + + .toggle-small .toggle-energized input:checked + .track .handle { + background-color: #ffc900; } + + .toggle-small .toggle-royal input:checked + .track { + background-color: rgba(136, 106, 234, 0.5); } + + .toggle-small .toggle-royal input:checked + .track .handle { + background-color: #886aea; } + + .toggle-small .toggle-dark input:checked + .track { + background-color: rgba(68, 68, 68, 0.5); } + + .toggle-small .toggle-dark input:checked + .track .handle { + background-color: #444; } + + /** + * Radio Button Inputs + * -------------------------------------------------- + */ + .item-radio { + padding: 0; } + .item-radio:hover { + cursor: pointer; } + + .item-radio .item-content { + /* give some room to the right for the checkmark icon */ + padding-right: 64px; } + + .item-radio .radio-icon { + /* checkmark icon will be hidden by default */ + position: absolute; + top: 0; + right: 0; + z-index: 3; + visibility: hidden; + padding: 14px; + height: 100%; + font-size: 24px; } + + .item-radio input { + /* hide any radio button inputs elements (the ugly circles) */ + position: absolute; + left: -9999px; } + .item-radio input:checked + .radio-content .item-content { + /* style the item content when its checked */ + background: #f7f7f7; } + .item-radio input:checked + .radio-content .radio-icon { + /* show the checkmark icon when its checked */ + visibility: visible; } + + /** + * Buttons + * -------------------------------------------------- + */ + .button { + border-color: transparent; + background-color: #f8f8f8; + color: #444; + position: relative; + display: inline-block; + margin: 0; + padding: 0 12px; + min-width: 52px; + min-height: 47px; + border-width: 1px; + border-style: solid; + border-radius: 4px; + vertical-align: top; + text-align: center; + text-overflow: ellipsis; + font-size: 16px; + line-height: 42px; + cursor: pointer; } + .button:hover { + color: #444; + text-decoration: none; } + .button.active, .button.activated { + border-color: #a2a2a2; + background-color: #e5e5e5; } + .button:after { + position: absolute; + top: -6px; + right: -6px; + bottom: -6px; + left: -6px; + content: ' '; } + .button .icon, .button .icon-help, .button .icon-alert, .button #menu .footer .icon-help, #menu .footer .button .icon-help { + vertical-align: top; + pointer-events: none; } + .button .icon:before, .button .icon-help:before, .button .icon-alert:before, .button #menu .footer .icon-help:before, #menu .footer .button .icon-help:before, .button.icon:before, .button.icon-help:before, .button.icon-alert:before, #menu .footer .button.icon-help:before, .button.icon-left:before, .button.icon-right:before { + display: inline-block; + padding: 0 0 1px 0; + vertical-align: inherit; + font-size: 24px; + line-height: 41px; + pointer-events: none; } + .button.icon-left:before { + float: left; + padding-right: .2em; + padding-left: 0; } + .button.icon-right:before { + float: right; + padding-right: 0; + padding-left: .2em; } + .button.button-block, .button.button-full { + margin-top: 10px; + margin-bottom: 10px; } + .button.button-light { + border-color: transparent; + background-color: #fff; + color: #444; } + .button.button-light:hover { + color: #444; + text-decoration: none; } + .button.button-light.active, .button.button-light.activated { + border-color: #a2a2a2; + background-color: #fafafa; } + .button.button-light.button-clear, .button.button-light.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #ddd; } + .button.button-light.button-icon { + border-color: transparent; + background: none; } + .button.button-light.button-outline { + border-color: #ddd; + background: transparent; + color: #ddd; } + .button.button-light.button-outline.active, .button.button-light.button-outline.activated { + background-color: #ddd; + box-shadow: none; + color: #fff; } + .button.button-stable { + border-color: transparent; + background-color: #f8f8f8; + color: #444; } + .button.button-stable:hover { + color: #444; + text-decoration: none; } + .button.button-stable.active, .button.button-stable.activated { + border-color: #a2a2a2; + background-color: #e5e5e5; } + .button.button-stable.button-clear, .button.button-stable.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #b2b2b2; } + .button.button-stable.button-icon { + border-color: transparent; + background: none; } + .button.button-stable.button-outline { + border-color: #b2b2b2; + background: transparent; + color: #b2b2b2; } + .button.button-stable.button-outline.active, .button.button-stable.button-outline.activated { + background-color: #b2b2b2; + box-shadow: none; + color: #fff; } + .button.button-positive, .button.button-text { + border-color: transparent; + background-color: #387ef5; + color: #fff; } + .button.button-positive:hover, .button.button-text:hover { + color: #fff; + text-decoration: none; } + .button.button-positive.active, .button.active.button-text, .button.button-positive.activated, .button.activated.button-text { + border-color: #a2a2a2; + background-color: #0c60ee; } + .button.button-positive.button-clear, .button.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #387ef5; } + .button.button-positive.button-icon, .button.button-icon.button-text { + border-color: transparent; + background: none; } + .button.button-positive.button-outline, .button.button-outline.button-text { + border-color: #387ef5; + background: transparent; + color: #387ef5; } + .button.button-positive.button-outline.active, .button.button-outline.active.button-text, .button.button-positive.button-outline.activated, .button.button-outline.activated.button-text { + background-color: #387ef5; + box-shadow: none; + color: #fff; } + .button.button-calm { + border-color: transparent; + background-color: #11c1f3; + color: #fff; } + .button.button-calm:hover { + color: #fff; + text-decoration: none; } + .button.button-calm.active, .button.button-calm.activated { + border-color: #a2a2a2; + background-color: #0a9dc7; } + .button.button-calm.button-clear, .button.button-calm.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #11c1f3; } + .button.button-calm.button-icon { + border-color: transparent; + background: none; } + .button.button-calm.button-outline { + border-color: #11c1f3; + background: transparent; + color: #11c1f3; } + .button.button-calm.button-outline.active, .button.button-calm.button-outline.activated { + background-color: #11c1f3; + box-shadow: none; + color: #fff; } + .button.button-assertive { + border-color: transparent; + background-color: #ef473a; + color: #fff; } + .button.button-assertive:hover { + color: #fff; + text-decoration: none; } + .button.button-assertive.active, .button.button-assertive.activated { + border-color: #a2a2a2; + background-color: #e42112; } + .button.button-assertive.button-clear, .button.button-assertive.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #ef473a; } + .button.button-assertive.button-icon { + border-color: transparent; + background: none; } + .button.button-assertive.button-outline { + border-color: #ef473a; + background: transparent; + color: #ef473a; } + .button.button-assertive.button-outline.active, .button.button-assertive.button-outline.activated { + background-color: #ef473a; + box-shadow: none; + color: #fff; } + .button.button-balanced { + border-color: transparent; + background-color: #33cd5f; + color: #fff; } + .button.button-balanced:hover { + color: #fff; + text-decoration: none; } + .button.button-balanced.active, .button.button-balanced.activated { + border-color: #a2a2a2; + background-color: #28a54c; } + .button.button-balanced.button-clear, .button.button-balanced.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #33cd5f; } + .button.button-balanced.button-icon { + border-color: transparent; + background: none; } + .button.button-balanced.button-outline { + border-color: #33cd5f; + background: transparent; + color: #33cd5f; } + .button.button-balanced.button-outline.active, .button.button-balanced.button-outline.activated { + background-color: #33cd5f; + box-shadow: none; + color: #fff; } + .button.button-energized { + border-color: transparent; + background-color: #ffc900; + color: #fff; } + .button.button-energized:hover { + color: #fff; + text-decoration: none; } + .button.button-energized.active, .button.button-energized.activated { + border-color: #a2a2a2; + background-color: #e6b500; } + .button.button-energized.button-clear, .button.button-energized.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #ffc900; } + .button.button-energized.button-icon { + border-color: transparent; + background: none; } + .button.button-energized.button-outline { + border-color: #ffc900; + background: transparent; + color: #ffc900; } + .button.button-energized.button-outline.active, .button.button-energized.button-outline.activated { + background-color: #ffc900; + box-shadow: none; + color: #fff; } + .button.button-royal { + border-color: transparent; + background-color: #886aea; + color: #fff; } + .button.button-royal:hover { + color: #fff; + text-decoration: none; } + .button.button-royal.active, .button.button-royal.activated { + border-color: #a2a2a2; + background-color: #6b46e5; } + .button.button-royal.button-clear, .button.button-royal.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #886aea; } + .button.button-royal.button-icon { + border-color: transparent; + background: none; } + .button.button-royal.button-outline { + border-color: #886aea; + background: transparent; + color: #886aea; } + .button.button-royal.button-outline.active, .button.button-royal.button-outline.activated { + background-color: #886aea; + box-shadow: none; + color: #fff; } + .button.button-dark { + border-color: transparent; + background-color: #444; + color: #fff; } + .button.button-dark:hover { + color: #fff; + text-decoration: none; } + .button.button-dark.active, .button.button-dark.activated { + border-color: #a2a2a2; + background-color: #262626; } + .button.button-dark.button-clear, .button.button-dark.button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: #444; } + .button.button-dark.button-icon { + border-color: transparent; + background: none; } + .button.button-dark.button-outline { + border-color: #444; + background: transparent; + color: #444; } + .button.button-dark.button-outline.active, .button.button-dark.button-outline.activated { + background-color: #444; + box-shadow: none; + color: #fff; } + + .button-small, .button-text.button-small { + padding: 2px 4px 1px; + min-width: 28px; + min-height: 30px; + font-size: 12px; + line-height: 26px; } + .button-small .icon:before, .button-small .icon-help:before, .button-small .icon-alert:before, .button-small #menu .footer .icon-help:before, #menu .footer .button-small .icon-help:before, .button-small.icon:before, .button-small.icon-help:before, .button-small.icon-alert:before, #menu .footer .button-small.icon-help:before, .button-small.icon-left:before, .button-small.icon-right:before { + font-size: 16px; + line-height: 19px; + margin-top: 3px; } + + .button-large { + padding: 0 16px; + min-width: 68px; + min-height: 59px; + font-size: 20px; + line-height: 53px; } + .button-large .icon:before, .button-large .icon-help:before, .button-large .icon-alert:before, .button-large #menu .footer .icon-help:before, #menu .footer .button-large .icon-help:before, .button-large.icon:before, .button-large.icon-help:before, .button-large.icon-alert:before, #menu .footer .button-large.icon-help:before, .button-large.icon-left:before, .button-large.icon-right:before { + padding-bottom: 2px; + font-size: 32px; + line-height: 51px; } + + .button-icon { + -webkit-transition: opacity 0.1s; + transition: opacity 0.1s; + padding: 0 6px; + min-width: initial; + border-color: transparent; + background: none; } + .button-icon.button.active, .button-icon.button.activated { + border-color: transparent; + background: none; + box-shadow: none; + opacity: 0.3; } + .button-icon .icon:before, .button-icon .icon-help:before, .button-icon .icon-alert:before, .button-icon #menu .footer .icon-help:before, #menu .footer .button-icon .icon-help:before, .button-icon.icon:before, .button-icon.icon-help:before, .button-icon.icon-alert:before, #menu .footer .button-icon.icon-help:before { + font-size: 32px; } + + .button-clear, .button-text { + -webkit-transition: opacity 0.1s; + transition: opacity 0.1s; + padding: 0 6px; + max-height: 42px; + border-color: transparent; + background: none; + box-shadow: none; } + .button-clear.button-clear, .button-text { + border-color: transparent; + background: none; + box-shadow: none; + color: transparent; } + .button-clear.button-icon, .button-icon.button-text { + border-color: transparent; + background: none; } + .button-clear.active, .active.button-text, .button-clear.activated, .activated.button-text { + opacity: 0.3; } + + .button-outline { + -webkit-transition: opacity 0.1s; + transition: opacity 0.1s; + background: none; + box-shadow: none; } + .button-outline.button-outline { + border-color: transparent; + background: transparent; + color: transparent; } + .button-outline.button-outline.active, .button-outline.button-outline.activated { + background-color: transparent; + box-shadow: none; + color: #fff; } + + .padding > .button.button-block:first-child, .item.large-button-bar > .button.button-block:first-child { + margin-top: 0; } + + .button-block { + display: block; + clear: both; } + .button-block:after { + clear: both; } + + .button-full, + .button-full > .button { + display: block; + margin-right: 0; + margin-left: 0; + border-right-width: 0; + border-left-width: 0; + border-radius: 0; } + + button.button-block, + button.button-full, + .button-full > button.button, + input.button.button-block { + width: 100%; } + + a.button { + text-decoration: none; } + a.button .icon:before, a.button .icon-help:before, a.button .icon-alert:before, a.button #menu .footer .icon-help:before, #menu .footer a.button .icon-help:before, a.button.icon:before, a.button.icon-help:before, a.button.icon-alert:before, #menu .footer a.button.icon-help:before, a.button.icon-left:before, a.button.icon-right:before { + margin-top: 2px; } + + .button.disabled, + .button[disabled] { + opacity: .4; + cursor: default !important; + pointer-events: none; } + + /** + * Button Bar + * -------------------------------------------------- + */ + .button-bar { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + width: 100%; } + .button-bar.button-bar-inline { + display: block; + width: auto; + *zoom: 1; } + .button-bar.button-bar-inline:before, .button-bar.button-bar-inline:after { + display: table; + content: ""; + line-height: 0; } + .button-bar.button-bar-inline:after { + clear: both; } + .button-bar.button-bar-inline > .button { + width: auto; + display: inline-block; + float: left; } + .button-bar.bar-light > .button { + border-color: #ddd; } + .button-bar.bar-stable > .button { + border-color: #b2b2b2; } + .button-bar.bar-positive > .button { + border-color: #0c60ee; } + .button-bar.bar-calm > .button { + border-color: #0a9dc7; } + .button-bar.bar-assertive > .button { + border-color: #e42112; } + .button-bar.bar-balanced > .button { + border-color: #28a54c; } + .button-bar.bar-energized > .button { + border-color: #e6b500; } + .button-bar.bar-royal > .button { + border-color: #6b46e5; } + .button-bar.bar-dark > .button { + border-color: #111; } + + .button-bar > .button { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + display: block; + overflow: hidden; + padding: 0 16px; + width: 0; + border-width: 1px 0px 1px 1px; + border-radius: 0; + text-align: center; + text-overflow: ellipsis; + white-space: nowrap; } + .button-bar > .button:before, + .button-bar > .button .icon:before, + .button-bar > .button .icon-help:before, + .button-bar > .button .icon-alert:before, + .button-bar > .button #menu .footer .icon-help:before, #menu .footer + .button-bar > .button .icon-help:before { + line-height: 44px; } + .button-bar > .button:first-child { + border-radius: 4px 0px 0px 4px; } + .button-bar > .button:last-child { + border-right-width: 1px; + border-radius: 0px 4px 4px 0px; } + .button-bar > .button:only-child { + border-radius: 4px; } + + .button-bar > .button-small:before, + .button-bar > .button-small .icon:before, + .button-bar > .button-small .icon-help:before, + .button-bar > .button-small .icon-alert:before, + .button-bar > .button-small #menu .footer .icon-help:before, #menu .footer + .button-bar > .button-small .icon-help:before { + line-height: 28px; } + + /** + * Grid + * -------------------------------------------------- + * Using flexbox for the grid, inspired by Philip Walton: + * http://philipwalton.github.io/solved-by-flexbox/demos/grids/ + * By default each .col within a .row will evenly take up + * available width, and the height of each .col with take + * up the height of the tallest .col in the same .row. + */ + .row { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + padding: 5px; + width: 100%; } + + .row-wrap { + -webkit-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; } + + .row-no-padding { + padding: 0; } + .row-no-padding > .col { + padding: 0; } + + .row + .row { + margin-top: -5px; + padding-top: 0; } + + .col { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + display: block; + padding: 5px; + width: 100%; } + + /* Vertically Align Columns */ + /* .row-* vertically aligns every .col in the .row */ + .row-top { + -webkit-box-align: start; + -ms-flex-align: start; + -webkit-align-items: flex-start; + -moz-align-items: flex-start; + align-items: flex-start; } + + .row-bottom { + -webkit-box-align: end; + -ms-flex-align: end; + -webkit-align-items: flex-end; + -moz-align-items: flex-end; + align-items: flex-end; } + + .row-center { + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; } + + .row-stretch { + -webkit-box-align: stretch; + -ms-flex-align: stretch; + -webkit-align-items: stretch; + -moz-align-items: stretch; + align-items: stretch; } + + .row-baseline { + -webkit-box-align: baseline; + -ms-flex-align: baseline; + -webkit-align-items: baseline; + -moz-align-items: baseline; + align-items: baseline; } + + /* .col-* vertically aligns an individual .col */ + .col-top { + -webkit-align-self: flex-start; + -moz-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; } + + .col-bottom { + -webkit-align-self: flex-end; + -moz-align-self: flex-end; + -ms-flex-item-align: end; + align-self: flex-end; } + + .col-center { + -webkit-align-self: center; + -moz-align-self: center; + -ms-flex-item-align: center; + align-self: center; } + + /* Column Offsets */ + .col-offset-10 { + margin-left: 10%; } + + .col-offset-20 { + margin-left: 20%; } + + .col-offset-25 { + margin-left: 25%; } + + .col-offset-33, .col-offset-34 { + margin-left: 33.3333%; } + + .col-offset-50 { + margin-left: 50%; } + + .col-offset-66, .col-offset-67 { + margin-left: 66.6666%; } + + .col-offset-75 { + margin-left: 75%; } + + .col-offset-80 { + margin-left: 80%; } + + .col-offset-90 { + margin-left: 90%; } + + /* Explicit Column Percent Sizes */ + /* By default each grid column will evenly distribute */ + /* across the grid. However, you can specify individual */ + /* columns to take up a certain size of the available area */ + .col-10 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 10%; + -moz-box-flex: 0; + -moz-flex: 0 0 10%; + -ms-flex: 0 0 10%; + flex: 0 0 10%; + max-width: 10%; } + + .col-20 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 20%; + -moz-box-flex: 0; + -moz-flex: 0 0 20%; + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; } + + .col-25 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 25%; + -moz-box-flex: 0; + -moz-flex: 0 0 25%; + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; } + + .col-33, .col-34 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 33.3333%; + -moz-box-flex: 0; + -moz-flex: 0 0 33.3333%; + -ms-flex: 0 0 33.3333%; + flex: 0 0 33.3333%; + max-width: 33.3333%; } + + .col-40 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 40%; + -moz-box-flex: 0; + -moz-flex: 0 0 40%; + -ms-flex: 0 0 40%; + flex: 0 0 40%; + max-width: 40%; } + + .col-50 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 50%; + -moz-box-flex: 0; + -moz-flex: 0 0 50%; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; } + + .col-60 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 60%; + -moz-box-flex: 0; + -moz-flex: 0 0 60%; + -ms-flex: 0 0 60%; + flex: 0 0 60%; + max-width: 60%; } + + .col-66, .col-67 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 66.6666%; + -moz-box-flex: 0; + -moz-flex: 0 0 66.6666%; + -ms-flex: 0 0 66.6666%; + flex: 0 0 66.6666%; + max-width: 66.6666%; } + + .col-75 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 75%; + -moz-box-flex: 0; + -moz-flex: 0 0 75%; + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; } + + .col-80 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 80%; + -moz-box-flex: 0; + -moz-flex: 0 0 80%; + -ms-flex: 0 0 80%; + flex: 0 0 80%; + max-width: 80%; } + + .col-90 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 90%; + -moz-box-flex: 0; + -moz-flex: 0 0 90%; + -ms-flex: 0 0 90%; + flex: 0 0 90%; + max-width: 90%; } + + /* Responsive Grid Classes */ + /* Adding a class of responsive-X to a row */ + /* will trigger the flex-direction to */ + /* change to column and add some margin */ + /* to any columns in the row for clearity */ + @media (max-width: 567px) { + .responsive-sm { + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } + .responsive-sm .col, .responsive-sm .col-10, .responsive-sm .col-20, .responsive-sm .col-25, .responsive-sm .col-33, .responsive-sm .col-34, .responsive-sm .col-50, .responsive-sm .col-66, .responsive-sm .col-67, .responsive-sm .col-75, .responsive-sm .col-80, .responsive-sm .col-90 { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + margin-bottom: 15px; + margin-left: 0; + max-width: 100%; + width: 100%; } } + + @media (max-width: 767px) { + .responsive-md { + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } + .responsive-md .col, .responsive-md .col-10, .responsive-md .col-20, .responsive-md .col-25, .responsive-md .col-33, .responsive-md .col-34, .responsive-md .col-50, .responsive-md .col-66, .responsive-md .col-67, .responsive-md .col-75, .responsive-md .col-80, .responsive-md .col-90 { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + margin-bottom: 15px; + margin-left: 0; + max-width: 100%; + width: 100%; } } + + @media (max-width: 1023px) { + .responsive-lg { + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } + .responsive-lg .col, .responsive-lg .col-10, .responsive-lg .col-20, .responsive-lg .col-25, .responsive-lg .col-33, .responsive-lg .col-34, .responsive-lg .col-50, .responsive-lg .col-66, .responsive-lg .col-67, .responsive-lg .col-75, .responsive-lg .col-80, .responsive-lg .col-90 { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + margin-bottom: 15px; + margin-left: 0; + max-width: 100%; + width: 100%; } } + + /** + * Utility Classes + * -------------------------------------------------- + */ + .hide { + display: none; } + + .opacity-hide { + opacity: 0; } + + .grade-b .opacity-hide, + .grade-c .opacity-hide { + opacity: 1; + display: none; } + + .show { + display: block; } + + .opacity-show { + opacity: 1; } + + .invisible { + visibility: hidden; } + + .keyboard-open .hide-on-keyboard-open { + display: none; } + + .keyboard-open .tabs.hide-on-keyboard-open + .pane .has-tabs, + .keyboard-open .bar-footer.hide-on-keyboard-open + .pane .has-footer { + bottom: 0; } + + .inline { + display: inline-block; } + + .disable-pointer-events { + pointer-events: none; } + + .enable-pointer-events { + pointer-events: auto; } + + .disable-user-behavior { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-touch-callout: none; + -webkit-tap-highlight-color: transparent; + -webkit-tap-highlight-color: transparent; + -webkit-user-drag: none; + -ms-touch-action: none; + -ms-content-zooming: none; } + + .click-block { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0; + z-index: 99999; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + overflow: hidden; } + + .click-block-hide { + -webkit-transform: translate3d(-9999px, 0, 0); + transform: translate3d(-9999px, 0, 0); } + + .no-resize { + resize: none; } + + .block { + display: block; + clear: both; } + .block:after { + display: block; + visibility: hidden; + clear: both; + height: 0; + content: "."; } + + .full-image { + width: 100%; } + + .clearfix { + *zoom: 1; } + .clearfix:before, .clearfix:after { + display: table; + content: ""; + line-height: 0; } + .clearfix:after { + clear: both; } + + /** + * Content Padding + * -------------------------------------------------- + */ + .padding, .item.large-button-bar { + padding: 10px; } + + .padding-top, + .padding-vertical { + padding-top: 10px; } + + .padding-right, .popover-share .bar-footer .button-close, + .padding-horizontal { + padding-right: 10px; } + + .padding-bottom, .popover-share .bar-footer .button-close, + .padding-vertical { + padding-bottom: 10px; } + + .padding-left, + .padding-horizontal { + padding-left: 10px; } + + /** + * Scrollable iFrames + * -------------------------------------------------- + */ + .iframe-wrapper { + position: fixed; + -webkit-overflow-scrolling: touch; + overflow: scroll; } + .iframe-wrapper iframe { + height: 100%; + width: 100%; } + + /** + * Rounded + * -------------------------------------------------- + */ + .rounded { + border-radius: 4px; } + + /** + * Utility Colors + * -------------------------------------------------- + * Utility colors are added to help set a naming convention. You'll + * notice we purposely do not use words like "red" or "blue", but + * instead have colors which represent an emotion or generic theme. + */ + .light, a.light { + color: #fff; } + + .light-bg { + background-color: #fff; } + + .light-border { + border-color: #ddd; } + + .stable, a.stable { + color: #f8f8f8; } + + .stable-bg { + background-color: #f8f8f8; } + + .stable-border { + border-color: #b2b2b2; } + + .positive, .icon-help, a.positive, a.icon-help { + color: #387ef5; } + + .positive-bg { + background-color: #387ef5; } + + .positive-border { + border-color: #0c60ee; } + + .calm, #menu .footer .icon-help, a.calm, #menu .footer a.icon-help { + color: #11c1f3; } + + .calm-bg { + background-color: #11c1f3; } + + .calm-border { + border-color: #0a9dc7; } + + .assertive, .icon-alert, a.assertive, a.icon-alert { + color: #ef473a; } + + .assertive-bg { + background-color: #ef473a; } + + .assertive-border { + border-color: #e42112; } + + .balanced, a.balanced { + color: #33cd5f; } + + .balanced-bg { + background-color: #33cd5f; } + + .balanced-border { + border-color: #28a54c; } + + .energized, a.energized { + color: #ffc900; } + + .energized-bg { + background-color: #ffc900; } + + .energized-border { + border-color: #e6b500; } + + .royal, a.royal { + color: #886aea; } + + .royal-bg { + background-color: #886aea; } + + .royal-border { + border-color: #6b46e5; } + + .dark, a.dark { + color: #444; } + + .dark-bg { + background-color: #444; } + + .dark-border { + border-color: #111; } + + [collection-repeat] { + /* Position is set by transforms */ + left: 0 !important; + top: 0 !important; + position: absolute !important; + z-index: 1; } + + .collection-repeat-container { + position: relative; + z-index: 1; } + + .collection-repeat-after-container { + z-index: 0; + display: block; + /* when scrolling horizontally, make sure the after container doesn't take up 100% width */ } + .collection-repeat-after-container.horizontal { + display: inline-block; } + + [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, + .x-ng-cloak, .ng-hide:not(.ng-hide-animate) { + display: none !important; } + + /** + * Platform + * -------------------------------------------------- + * Platform specific tweaks + */ + .platform-ios.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader) { + height: 64px; } + .platform-ios.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader).item-input-inset .item-input-wrapper { + margin-top: 19px !important; } + .platform-ios.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader) > * { + margin-top: 20px; } + + .platform-ios.platform-cordova:not(.fullscreen) .tabs-top > .tabs, + .platform-ios.platform-cordova:not(.fullscreen) .tabs.tabs-top { + top: 64px; } + + .platform-ios.platform-cordova:not(.fullscreen) .has-header, + .platform-ios.platform-cordova:not(.fullscreen) .bar-subheader { + top: 64px; } + + .platform-ios.platform-cordova:not(.fullscreen) .has-subheader { + top: 108px; } + + .platform-ios.platform-cordova:not(.fullscreen) .has-header.has-tabs-top { + top: 113px; } + + .platform-ios.platform-cordova:not(.fullscreen) .has-header.has-subheader.has-tabs-top { + top: 157px; } + + .platform-ios.platform-cordova .popover .bar-header:not(.bar-subheader) { + height: 44px; } + .platform-ios.platform-cordova .popover .bar-header:not(.bar-subheader).item-input-inset .item-input-wrapper { + margin-top: -1px; } + .platform-ios.platform-cordova .popover .bar-header:not(.bar-subheader) > * { + margin-top: 0; } + + .platform-ios.platform-cordova .popover .has-header, + .platform-ios.platform-cordova .popover .bar-subheader { + top: 44px; } + + .platform-ios.platform-cordova .popover .has-subheader { + top: 88px; } + + .platform-ios.platform-cordova.status-bar-hide { + margin-bottom: 20px; } + + @media (orientation: landscape) { + .platform-ios.platform-browser.platform-ipad { + position: fixed; } } + + .platform-c:not(.enable-transitions) * { + -webkit-transition: none !important; + transition: none !important; } + + .slide-in-up { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); } + + .slide-in-up.ng-enter, + .slide-in-up > .ng-enter { + -webkit-transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms; + transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms; } + + .slide-in-up.ng-enter-active, + .slide-in-up > .ng-enter-active { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + + .slide-in-up.ng-leave, + .slide-in-up > .ng-leave { + -webkit-transition: all ease-in-out 250ms; + transition: all ease-in-out 250ms; } + + @-webkit-keyframes scaleOut { + from { + -webkit-transform: scale(1); + opacity: 1; } + to { + -webkit-transform: scale(0.8); + opacity: 0; } } + + @keyframes scaleOut { + from { + transform: scale(1); + opacity: 1; } + to { + transform: scale(0.8); + opacity: 0; } } + + @-webkit-keyframes superScaleIn { + from { + -webkit-transform: scale(1.2); + opacity: 0; } + to { + -webkit-transform: scale(1); + opacity: 1; } } + + @keyframes superScaleIn { + from { + transform: scale(1.2); + opacity: 0; } + to { + transform: scale(1); + opacity: 1; } } + + [nav-view-transition="ios"] [nav-view="entering"], + [nav-view-transition="ios"] [nav-view="leaving"] { + -webkit-transition-duration: 500ms; + transition-duration: 500ms; + -webkit-transition-timing-function: cubic-bezier(0.36, 0.66, 0.04, 1); + transition-timing-function: cubic-bezier(0.36, 0.66, 0.04, 1); + -webkit-transition-property: opacity, -webkit-transform, box-shadow; + transition-property: opacity, transform, box-shadow; } + + [nav-view-transition="ios"][nav-view-direction="forward"], [nav-view-transition="ios"][nav-view-direction="back"] { + background-color: #000; } + + [nav-view-transition="ios"] [nav-view="active"], + [nav-view-transition="ios"][nav-view-direction="forward"] [nav-view="entering"], + [nav-view-transition="ios"][nav-view-direction="back"] [nav-view="leaving"] { + z-index: 3; } + + [nav-view-transition="ios"][nav-view-direction="back"] [nav-view="entering"], + [nav-view-transition="ios"][nav-view-direction="forward"] [nav-view="leaving"] { + z-index: 2; } + + [nav-bar-transition="ios"] .title, + [nav-bar-transition="ios"] .buttons, + [nav-bar-transition="ios"] .back-text { + -webkit-transition-duration: 500ms; + transition-duration: 500ms; + -webkit-transition-timing-function: cubic-bezier(0.36, 0.66, 0.04, 1); + transition-timing-function: cubic-bezier(0.36, 0.66, 0.04, 1); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; } + + [nav-bar-transition="ios"] [nav-bar="active"], + [nav-bar-transition="ios"] [nav-bar="entering"] { + z-index: 10; } + [nav-bar-transition="ios"] [nav-bar="active"] .bar, + [nav-bar-transition="ios"] [nav-bar="entering"] .bar { + background: transparent; } + + [nav-bar-transition="ios"] [nav-bar="cached"] { + display: block; } + [nav-bar-transition="ios"] [nav-bar="cached"] .header-item { + display: none; } + + [nav-view-transition="android"] [nav-view="entering"], + [nav-view-transition="android"] [nav-view="leaving"] { + -webkit-transition-duration: 200ms; + transition-duration: 200ms; + -webkit-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1); + -webkit-transition-property: -webkit-transform; + transition-property: transform; } + + [nav-view-transition="android"] [nav-view="active"], + [nav-view-transition="android"][nav-view-direction="forward"] [nav-view="entering"], + [nav-view-transition="android"][nav-view-direction="back"] [nav-view="leaving"] { + z-index: 3; } + + [nav-view-transition="android"][nav-view-direction="back"] [nav-view="entering"], + [nav-view-transition="android"][nav-view-direction="forward"] [nav-view="leaving"] { + z-index: 2; } + + [nav-bar-transition="android"] .title, + [nav-bar-transition="android"] .buttons { + -webkit-transition-duration: 200ms; + transition-duration: 200ms; + -webkit-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1); + -webkit-transition-property: opacity; + transition-property: opacity; } + + [nav-bar-transition="android"] [nav-bar="active"], + [nav-bar-transition="android"] [nav-bar="entering"] { + z-index: 10; } + [nav-bar-transition="android"] [nav-bar="active"] .bar, + [nav-bar-transition="android"] [nav-bar="entering"] .bar { + background: transparent; } + + [nav-bar-transition="android"] [nav-bar="cached"] { + display: block; } + [nav-bar-transition="android"] [nav-bar="cached"] .header-item { + display: none; } + + [nav-swipe="fast"] [nav-view], + [nav-swipe="fast"] .title, + [nav-swipe="fast"] .buttons, + [nav-swipe="fast"] .back-text { + -webkit-transition-duration: 50ms; + transition-duration: 50ms; + -webkit-transition-timing-function: linear; + transition-timing-function: linear; } + + [nav-swipe="slow"] [nav-view], + [nav-swipe="slow"] .title, + [nav-swipe="slow"] .buttons, + [nav-swipe="slow"] .back-text { + -webkit-transition-duration: 160ms; + transition-duration: 160ms; + -webkit-transition-timing-function: linear; + transition-timing-function: linear; } + + [nav-view="cached"], + [nav-bar="cached"] { + display: none; } + + [nav-view="stage"] { + opacity: 0; + -webkit-transition-duration: 0; + transition-duration: 0; } + + [nav-bar="stage"] .title, + [nav-bar="stage"] .buttons, + [nav-bar="stage"] .back-text { + position: absolute; + opacity: 0; + -webkit-transition-duration: 0s; + transition-duration: 0s; } + + /* BEGIN Thin */ + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Thin/RobotoDraft-Thin.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Thin/RobotoDraft-Thin.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Thin/RobotoDraft-Thin.ttf?v=1.1.0") format("truetype"); + font-weight: 100; + font-style: normal; } + + /* END Thin */ + /* BEGIN Light */ + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Light/RobotoDraft-Light.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Light/RobotoDraft-Light.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Light/RobotoDraft-Light.ttf?v=1.1.0") format("truetype"); + font-weight: 300; + font-style: normal; } + + /* END Light */ + /* BEGIN Regular */ + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Regular/RobotoDraft-Regular.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Regular/RobotoDraft-Regular.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Regular/RobotoDraft-Regular.ttf?v=1.1.0") format("truetype"); + font-weight: 400; + font-style: normal; } + + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Regular/RobotoDraft-Regular.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Regular/RobotoDraft-Regular.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Regular/RobotoDraft-Regular.ttf?v=1.1.0") format("truetype"); + font-weight: normal; + font-style: normal; } + + /* END Regular */ + /* BEGIN Italic */ + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Italic/RobotoDraft-Italic.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Italic/RobotoDraft-Italic.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Italic/RobotoDraft-Italic.ttf?v=1.1.0") format("truetype"); + font-weight: 400; + font-style: italic; } + + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Italic/RobotoDraft-Italic.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Italic/RobotoDraft-Italic.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Italic/RobotoDraft-Italic.ttf?v=1.1.0") format("truetype"); + font-weight: normal; + font-style: italic; } + + /* END Italic */ + /* BEGIN Medium */ + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Medium/RobotoDraft-Medium.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Medium/RobotoDraft-Medium.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Medium/RobotoDraft-Medium.ttf?v=1.1.0") format("truetype"); + font-weight: 500; + font-style: normal; } + + /* END Medium */ + /* BEGIN Bold */ + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Bold/RobotoDraft-Bold.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Bold/RobotoDraft-Bold.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Bold/RobotoDraft-Bold.ttf?v=1.1.0") format("truetype"); + font-weight: 700; + font-style: normal; } + + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Bold/RobotoDraft-Bold.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Bold/RobotoDraft-Bold.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Bold/RobotoDraft-Bold.ttf?v=1.1.0") format("truetype"); + font-weight: bold; + font-style: normal; } + + /* END Bold */ + /* BEGIN Bold Italic */ + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/BoldItalic/RobotoDraft-BoldItalic.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/BoldItalic/RobotoDraft-BoldItalic.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/BoldItalic/RobotoDraft-BoldItalic.ttf?v=1.1.0") format("truetype"); + font-weight: 700; + font-style: italic; } + + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/BoldItalic/RobotoDraft-BoldItalic.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/BoldItalic/RobotoDraft-BoldItalic.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/BoldItalic/RobotoDraft-BoldItalic.ttf?v=1.1.0") format("truetype"); + font-weight: bold; + font-style: italic; } + + /* END Bold Italic */ + /* BEGIN Black */ + @font-face { + font-family: RobotoDraft; + src: url("../lib/ionic/fonts/robotdraft/Black/RobotoDraft-Black.woff2?v=1.1.0") format("woff2"), url("../lib/ionic/fonts/robotdraft/Black/RobotoDraft-Black.woff?v=1.1.0") format("woff"), url("../lib/ionic/fonts/robotdraft/Black/RobotoDraft-Black.ttf?v=1.1.0") format("truetype"); + font-weight: 900; + font-style: normal; } + + /* END Black */ + /* Directives : MD Label + ==================================*/ + .item-md-label { + display: block; + background: transparent; + box-shadow: none; + margin-left: 12px; + margin-right: 12px; + padding: 30px 0 0; } + + .item-md-label .input-label { + position: absolute; + padding: 5px 0 0; + z-index: 2; + -webkit-transform: translate3d(0, -30px, 0) scale(1); + transform: translate3d(0, -30px, 0) scale(1); + -webkit-transition: all 0.2s ease; + transition: all 0.2s ease; + color: #fff; + opacity: 0.5; + filter: alpha(opacity=50); + -webkit-transform-origin: 0; + -ms-transform-origin: 0; + transform-origin: 0; } + + .item-md-label input { + background-color: rgba(0, 0, 0, 0.6); + bottom: 0; + color: #fff; + letter-spacing: 0.25rem; + padding: 20px 10px; + position: relative; + z-index: 1; } + + .item-md-label .highlight { + position: absolute; + bottom: 0; + height: 2px; + left: 0; + width: 100%; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + -webkit-transition: all 0.15s ease; + transition: all 0.15s ease; + z-index: 1; } + + .item-md-label .highlight-light { + background: #fff; } + + .item-md-label .highlight-stable { + background: #f8f8f8; } + + .item-md-label .highlight-positive { + background: #387ef5; } + + .item-md-label .highlight-calm { + background: #11c1f3; } + + .item-md-label .highlight-balanced { + background: #33cd5f; } + + .item-md-label .highlight-energized { + background: #ffc900; } + + .item-md-label .highlight-assertive { + background: #ef473a; } + + .item-md-label .highlight-royal { + background: #886aea; } + + .item-md-label .highlight-dark { + background: #444; } + + .item-md-label .input-label { + letter-spacing: 0.25rem; + padding: 0 10px; } + + .item-md-label input:focus ~ .input-label, .item-md-label input.used ~ .input-label { + font-weight: bold; + opacity: 0.7; + filter: alpha(opacity=70); + padding: 0; + text-transform: uppercase; + -webkit-transform: translate3d(0, -60px, 0) scale(0.9); + transform: translate3d(0, -60px, 0) scale(0.9); } + + .item-md-label input:focus ~ .highlight { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + + /* Bar - Header - Expanded + ==================================*/ + .expanded .bar.bar-header, + .bar.bar-header.expanded { + height: 75px; } + + .expanded.bar.bar-header .title, + .bar.bar-header.expanded .title { + bottom: 0; + top: initial; + padding-left: 16px; } + + .expanded .bar.bar-header .title.fab-left, + .bar.bar-header.expanded .title.fab-left { + bottom: 0; + left: 90px; + position: absolute; + right: initial; + top: initial; } + + .expanded .bar.bar-header .title.fab-right, + .bar.bar-header.expanded .title.fab-right { + bottom: 0; + left: 4px; + position: absolute; + top: initial; + right: initial; } + + .expanded .bar.bar-header + .button-fab, + .bar.bar-header.expanded + .button-fab { + top: 50px; } + + .expanded .bar.bar-header.push-down, + .bar.bar-header.expanded.push-down { + height: 44px; + overflow: hidden; } + + .expanded .bar.bar-header, + .bar.bar-header.expanded { + -webkit-transition: height 1s cubic-bezier(0.55, 0, 0.1, 1); + transition: height 1s cubic-bezier(0.55, 0, 0.1, 1); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + + .expanded .bar.bar-header + .button-fab, + .bar.bar-header.expanded + .button-fab { + -webkit-transition: all 1.1s cubic-bezier(0.55, 0, 0.1, 1); + transition: all 1.1s cubic-bezier(0.55, 0, 0.1, 1); + -webkit-transform: translate3d(0, 0, 0) scale(1); + transform: translate3d(0, 0, 0) scale(1); } + + .expanded .bar.bar-header.push-down + .button-fab, + .bar.bar-header.expanded.push-down + .button-fab { + top: 0; + -webkit-transform: translate3d(-100px, -100px, 0) scale(2.5); + transform: translate3d(-100px, -100px, 0) scale(2.5); } + + .expanded .bar.bar-header.push-down .title, + .bar.bar-header.expanded.push-down .title { + opacity: 0; + filter: alpha(opacity=0); + left: initial; + right: initial; } + + .expanded .bar.bar-header .title, + .bar.bar-header.expanded .title { + opacity: 1; + filter: alpha(opacity=100); + -webkit-transition: all 2s cubic-bezier(0.55, 0, 0.1, 1); + transition: all 2s cubic-bezier(0.55, 0, 0.1, 1); } + + .expanded .bar.bar-header .title, .bar.bar-header.expanded .title { + bottom: 0; + left: 42px !important; + top: initial; } + + .expanded.has-header-fab-left .bar.bar-header .title, .bar.bar-header.expanded.has-header-fab-left .title { + left: 76px !important; } + + /* Bar + ==================================*/ + .bar { + z-index: 2; + font-size: 1.3em; + width: 100%; + box-shadow: 0px 2px 5px 0 rgba(0, 0, 0, 0.26); } + + .bar .button { + min-width: 38px; + z-index: 3; } + + .bar .no-text span.back-text { + display: none; } + + .bar .title sup { + opacity: 0.7; } + + .bar.bar-header .button + .title { + text-align: left; + left: 35px; + line-height: 46px; } + + /* Button Bar + ==================================*/ + .button-bar { + box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.15); } + + .button-bar > .button { + box-shadow: none; + /* line-height: initial; */ } + + .button-bar > .button .icon:before, .button-bar > .button .icon-help:before, .button-bar > .button .icon-alert:before, .button-bar > .button #menu .footer .icon-help:before, #menu .footer .button-bar > .button .icon-help:before, + .button-bar > .button:before { + line-height: initial; } + + .bar-footer .button-fab { + position: absolute; + top: -26px; + bottom: initial; } + + .bar-footer .buttons-left .button-fab { + left: 8px; } + + .bar-footer .buttons-right .button-fab { + right: 8px; } + + .bar .button.button-clear, .bar .button.button-text { + box-shadow: none; } + + .left-buttons .button-fab { + left: 8px; + top: 16px; } + + .right-buttons .button-fab { + right: 8px; + top: 16px; } + + .fab-left.title-left, + .fab-left.title.title-left { + left: 68px; } + + /* Button : FAB + ==================================*/ + .button.button-fab, + .bar .button.button-fab { + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); + z-index: 9999; + width: 56px; + height: 56px; + max-height: initial; + max-width: initial; + border-radius: 50%; + border-radius: 50%; + overflow: hidden; + padding: 0; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + -webkit-transition: 0.3s fade-in-out; + transition: 0.3s fade-in-out; + -webkit-transition-property: -webkit-transform, box-shadow; + transition-property: transform, box-shadow; } + + .button.button-fab.button-fab-bottom-right, + .bar .button.button-fab.button-fab-bottom-right { + top: auto; + right: 16px; + bottom: 16px; + left: auto; + position: absolute; } + + .button.button-fab.button-fab-bottom-left, + .bar .button.button-fab.button-fab-bottom-left { + top: auto; + right: auto; + bottom: 16px; + left: 16px; + position: absolute; } + + .button.button-fab.button-fab-top-right, + .bar .button.button-fab.button-fab-top-right { + top: 32px; + right: 16px; + bottom: auto; + left: auto; + position: absolute; } + + .button.button-fab.button-fab-top-left, + .bar .button.button-fab.button-fab-top-left { + top: 32px; + right: auto; + bottom: auto; + left: 16px; + position: absolute; } + + .button.button-fab.button-fab-top-left.expanded, + .button.button-fab.button-fab-top-right.expanded, + .bar .button.button-fab.button-fab-top-left.expanded, + .bar .button.button-fab.button-fab-top-right.expanded { + top: 48px; } + + .button.button-fab i, + .bar .button.button-fab i { + font-size: 2.5rem; + margin-top: 0; } + + .button.button-fab.mini, + .bar .button.button-fab.mini { + width: 40px; + height: 40px; } + + .button.button-fab.mini i, + .bar .button.button-fab.mini i { + font-size: 2rem; } + + /* Motion */ + .motion { + -webkit-transition: all 0.5s ease-out; + transition: all 0.5s ease-out; } + + .fade { + opacity: 0; + filter: alpha(opacity=0); + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transition: all 0.1s ease-out !important; + transition: all 0.1s ease-out !important; } + + .spin-back { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotate(360deg) scale(0) !important; + transform: translateZ(0) rotate(360deg) scale(0) !important; + -webkit-transition: all 0.1s ease-out !important; + transition: all 0.1s ease-out !important; } + + .spiral { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotate(-360deg) scale(0) translate(-120px) !important; + transform: translateZ(0) rotate(-360deg) scale(0) translate(-120px) !important; + -webkit-transition: all 0.1s ease-out !important; + transition: all 0.1s ease-out !important; } + + .spiral-back { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotate(360deg) scale(0) translate(120px) !important; + transform: translateZ(0) rotate(360deg) scale(0) translate(120px) !important; + -webkit-transition: all 0.1s ease-out !important; + transition: all 0.1s ease-out !important; } + + .menu-open .avatar { + opacity: 1; + filter: alpha(opacity=100); + -webkit-transform: translateZ(0) rotate(0) scale(1) !important; + transform: translateZ(0) rotate(0) scale(1) !important; + -webkit-transition: all 0.3s ease-out !important; + transition: all 0.3s ease-out !important; } + + .button.button-fab.button-fab-top-left.motion { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transform: translate3d(-120px, 60px, 0); + transform: translate3d(-120px, 60px, 0); + -webkit-transition: all 0.1s ease-out; + transition: all 0.1s ease-out; } + + .button.button-fab.button-fab-top-right.motion { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transform: translate3d(120px, 60px, 0); + transform: translate3d(120px, 60px, 0); + -webkit-transition: all 0.1s ease-out; + transition: all 0.1s ease-out; } + + .button.button-fab.button-fab-bottom-left.motion { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transform: translate3d(-120px, 60px, 0); + transform: translate3d(-120px, 60px, 0); + -webkit-transition: all 0.1s ease-out; + transition: all 0.1s ease-out; } + + .button.button-fab.button-fab-bottom-right.motion { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transform: translate3d(120px, 60px, 0); + transform: translate3d(120px, 60px, 0); + -webkit-transition: all 0.1s ease-out; + transition: all 0.1s ease-out; } + + .spin { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotate(0) scale(0) !important; + transform: translateZ(0) rotate(0) scale(0) !important; + -webkit-transition: all 0.3s ease-out !important; + transition: all 0.3s ease-out !important; } + + .spin.on { + -webkit-transform: translateZ(0) rotate(-360deg) scale(1) !important; + transform: translateZ(0) rotate(-360deg) scale(1) !important; } + + .flap { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotateX(0) scale(0) translate(-120px) !important; + transform: translateZ(0) rotateX(0) scale(0) translate(-120px) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .flap.on { + -webkit-transform: translateZ(0) rotateX(-720deg) scale(1) translate(0) !important; + transform: translateZ(0) rotateX(-720deg) scale(1) translate(0) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .drop { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) scale(3) !important; + transform: translateZ(0) scale(3) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .drop.on { + -webkit-transform: translateZ(0) scale(1) !important; + transform: translateZ(0) scale(1) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .flip { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotateY(0) scale(0) !important; + transform: translateZ(0) rotateY(0) scale(0) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .flip.on { + -webkit-transform: translateZ(0) rotateY(-720deg) scale(1) !important; + transform: translateZ(0) rotateY(-720deg) scale(1) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + /* Button : Floating + ==================================*/ + .button.button-floating, .bar .button.button-floating { + display: inline-block; + color: #FFF; + position: relative; + z-index: 1; + width: 37px; + height: 37px; + line-height: 37px; + padding: 0; + border-radius: 50%; + background-clip: padding-box; + -webkit-transition: 0.3s; + transition: 0.3s; + cursor: pointer; } + + .button.button-floating i, .bar .button.button-floating i { + width: inherit; + display: inline-block; + text-align: center; + color: #FFF; + font-size: 1.6rem; + line-height: 37px; } + + .button.button-floating.button-large, .bar .button.button-floating.button-large { + width: 55.5px; + height: 55.5px; } + + .button.button-floating.button-large i, .bar .button.button-floating.button-large i { + line-height: 55.5px; } + + /* Button + ==================================*/ + .button, + .button.button-large, + .button.button-flat, + .bar .button, + .bar .button.button-large, + .bar .button.button-flat { + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); + display: inline-block; + height: 36px; + padding: 0 2rem; + border-radius: 2px; + background-clip: padding-box; + text-transform: uppercase; + border: none; + outline: 0; + -webkit-tap-highlight-color: transparent; } + + .button.disabled, + .button.disabled.button-large, + .button.button-floating.disabled, + .button.button-large.disabled, + .button.button:disabled, + .button.button-large:disabled, + .button.button-large:disabled, + .button.button-floating:disabled, + .bar .button.disabled, + .bar .button.disabled.button-large, + .bar .button.button-floating.disabled, + .bar .button.button-large.disabled, + .bar .button.button:disabled, + .bar .button.button-large:disabled, + .bar .button.button-large:disabled, + .bar .button.button-floating:disabled { + background-color: #DFDFDF; + box-shadow: none; + color: #9F9F9F; } + + .button.disabled:hover, + .button.disabled.button-large:hover, + .button.button-floating.disabled:hover, + .button.button-large.disabled:hover, + .button.button:disabled:hover, + .button.button-large:disabled:hover, + .button.button-large:disabled:hover, + .button.button-floating:disabled:hover, + .bar .button.disabled:hover, + .bar .button.disabled.button-large:hover, + .bar .button.button-floating.disabled:hover, + .bar .button.button-large.disabled:hover, + .bar .button.button:disabled:hover, + .bar .button.button-large:disabled:hover, + .bar .button.button-large:disabled:hover, + .bar .button.button-floating:disabled:hover { + background-color: #DFDFDF; + color: #9F9F9F; } + + .button i, + .button.button-large i, + .button.button-floating i, + .button.button-large i, + .button.button-flat i, + .bar .button i, + .bar .button.button-large i, + .bar .button.button-floating i, + .bar .button.button-large i, + .bar .button.button-flat i { + font-size: 1.3rem; } + + .button-bar .button { + border-radius: 0; } + + .button, + .button-large, + .bar .button, + .bar .button-large { + text-decoration: none; + text-align: center; + letter-spacing: 0.5px; + -webkit-transition: 0.2s ease-out; + transition: 0.2s ease-out; + cursor: pointer; } + + .button { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + outline: none; + margin: 0; + /* background: transparent; */ + white-space: nowrap; + text-align: center; + text-transform: uppercase; + font-weight: 500; + font-style: inherit; + font-variant: inherit; + font-size: inherit; + text-decoration: none; + cursor: pointer; + overflow: hidden; + -webkit-transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), -webkit-transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); } + + .button:focus { + outline: none; } + + .button.ng-hide { + -webkit-transition: none; + transition: none; } + + .button.cornered { + border-radius: 0; } + + .button.raised { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + + .button-outline, + .button-outline:hover, + .button-outline:active { + border-style: solid; + border-width: 1px; } + + .button.button-outline.button-assertive, + .button.button-outline.button-balanced, + .button.button-outline.button-calm, + .button.button-outline.button-dark, + .button.button-outline.button-energized, + .button.button-outline.button-light, + .button.button-outline.button-positive, + .button.button-outline.button-text, + .button.button-outline.button-royal, + .button.button-outline.button-stable, + .button.button-outline { + border-color: rgba(0, 0, 0, 0.1); } + + .button-flat, + .bar .button-flat { + box-shadow: none; + background-color: transparent; + color: #343434; + cursor: pointer; } + + .button.button-flat.disabled, + .bar .button.button-flat.disabled { + color: #b3b3b3; } + + .button.button-large i, + .bar .button.button-large i { + font-size: 1.6rem; } + + .button-pin-header.button-floating { + position: absolute; + z-index: 1000; } + + .button-pin-header.button-pin-left { + left: 24px; + top: -24px; } + + .button-pin-header.button-pin-right { + right: 24px; + top: -24px; } + + .button:not([disabled]).raised:focus, + .button:not([disabled]).raised:hover, + .button:not([disabled]).floating:focus, + .button:not([disabled]).floating:hover { + -webkit-transform: translate3d(0, -1px, 0); + transform: translate3d(0, -1px, 0); } + + .button.button-flat { + box-shadow: none; + /* background: transparent; */ + color: inherit; } + + .button.button-flat:hover { + color: inherit; } + + .button.button-flat, + .button.button-flat:hover, + .button.button-flat:active { + color: #fff; } + + .button.button-clear, .button.button-text, + .button.button-clear:hover, + .button.button-text:hover, + .button.button-clear:active, + .button.button-text:active { + background: transparent; } + + .button-full.ink, + .button-block.ink { + display: block; } + + /* Card + ==================================*/ + .card-item.item { + border: none; + padding-bottom: 4px; + padding-top: 4px; } + + .card-item.item:first-child { + padding-top: 16px; } + + .card { + box-shadow: 0px 2px 5px 0 rgba(0, 0, 0, 0.26); + display: block; + margin: 8px; + padding: 0; + position: relative; } + + .card .image { + display: block; + margin-top: 10px; + margin-bottom: 5px; } + + .card img { + box-shadow: 0px 2px 5px 0 rgba(0, 0, 0, 0.26); + display: block; + max-width: 100%; + max-height: initial; + position: static; } + + .card.card-gallery img { + border: none; + box-shadow: none; + display: block; } + + .card .card-footer { + font-size: 90%; + opacity: 0.8; + filter: alpha(opacity=80); + padding-top: 10px; } + + .card > .item { + border: none; } + + .card.card-gallery > .item { + background: inherit; } + + .card .icon + .icon, .card .icon-help + .icon, .card .icon-alert + .icon, .card #menu .footer .icon-help + .icon, #menu .footer .card .icon-help + .icon, .card .icon + .icon-help, .card .icon-help + .icon-help, .card .icon-alert + .icon-help, .card .icon + .icon-alert, .card .icon-help + .icon-alert, .card .icon-alert + .icon-alert, .card #menu .footer .icon-help + .icon-alert, #menu .footer .card .icon-help + .icon-alert, .card #menu .footer .icon + .icon-help, #menu .footer .card .icon + .icon-help, .card #menu .footer .icon-alert + .icon-help, #menu .footer .card .icon-alert + .icon-help, .card #menu .footer .icon-help + .icon-help, #menu .footer .card .icon-help + .icon-help { + padding-left: 1rem; } + + .card.animate-fade-in { + opacity: 0; + filter: alpha(opacity=0); + -webkit-transform: translate3d(-30px, 1px, 0); + -webkit-transition: all 1s ease-in-out; } + + .card.animate-fade-in.done, .animate-fade-slide-in .expanded .card.animate-fade-in.item, + .animate-fade-slide-in .card.animate-fade-in.expanded.item, + .animate-fade-slide-in-right .expanded .card.animate-fade-in.item, + .animate-fade-slide-in-right .card.animate-fade-in.expanded.item, + .animate-ripple .expanded .card.animate-fade-in.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.animate-fade-in.card-comment { + opacity: 1; + filter: alpha(opacity=100); + -webkit-transform: translate3d(0, 0, 0); } + + .card .item.item-avatar { + min-height: 88px; + padding-left: 88px; } + + /* Hero + ==================================*/ + .hero { + background-size: cover; + box-shadow: 0px 2px 5px 0 rgba(0, 0, 0, 0.26); + color: #fff; + height: 200px; + position: relative; + text-align: center; + -webkit-transition: all 1s cubic-bezier(0.55, 0, 0.1, 1); + transition: all 1s cubic-bezier(0.55, 0, 0.1, 1); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + width: 100%; } + + .hero > * { + -webkit-transition: opacity 2.5s cubic-bezier(0.55, 0, 0.1, 1); + transition: opacity 2.5s cubic-bezier(0.55, 0, 0.1, 1); + opacity: 1; + filter: alpha(opacity=100); } + + .hero + .mid-bar { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + -webkit-transition: all 1s cubic-bezier(0.55, 0, 0.1, 1); + transition: all 1s cubic-bezier(0.55, 0, 0.1, 1); + height: initial; + opacity: 1; + filter: alpha(opacity=100); } + + .hero .hero-icon { + box-shadow: 0px 0 2px 0 rgba(0, 0, 0, 0.26); + border-radius: 50%; + display: inline-block; + font-size: 65px; + height: 150px; + padding: 10px 30px; + line-height: 136px; + width: 150px; } + + .hero.no-header { + height: 244px; } + + .hero > .content { + bottom: 0; + position: absolute; + text-align: center; + width: 100%; + z-index: 1; } + + .hero > .content > .avatar { + background-position: center; + background-size: cover; + border: solid 1px rgba(255, 255, 255, 0.8); + border-radius: 50%; + display: inline-block; + height: 88px; + left: auto; + margin-bottom: 10px; + position: relative; + width: 88px; } + + .hero h1 .hero h2, .hero h3, .hero h4, .hero h5, .hero h6 { + color: #fff; + margin: 0; } + + .hero h4 { + color: rgba(255, 255, 255, 0.7); + margin: 3px 0 16px; } + + .hero h1 > a, .hero h2 > a, .hero h3 > a, .hero h4 > a, .hero h5 > a, .hero h6 > a { + text-decoration: none; } + + .hero + .button-bar { + border-radius: 0; + margin-top: 0; } + + .hero + .button-bar > .button:first-child, .hero + .button-bar > .button:last-child { + border-radius: 0; } + + .hero .hero-icon { + color: #fff; + font-size: 96px; } + + .hero .hero-icon + h1 { + color: white; + letter-spacing: 0.15rem; } + + .hero .button, .hero .button.button-large, .hero .button.button-flat { + margin: 0; } + + .hero h1.title { + color: #fff; + font-size: 23px; + margin: 0; + text-align: left; + padding-left: 80px; + line-height: 59px; } + + .hero + .mid-bar { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + -webkit-transition: all 1s cubic-bezier(0.55, 0, 0.1, 1); + transition: all 1s cubic-bezier(0.55, 0, 0.1, 1); + height: initial; + opacity: 1; + filter: alpha(opacity=100); } + + .hero > * { + -webkit-transition: opacity 2.5s cubic-bezier(0.55, 0, 0.1, 1); + transition: opacity 2.5s cubic-bezier(0.55, 0, 0.1, 1); + opacity: 1; + filter: alpha(opacity=100); } + + /* Item + ==================================*/ + .item { + font-size: 14px; + width: 100%; } + + .item-icon-left .icon, .item-icon-left .icon-help, .item-icon-left .icon-alert, .item-icon-left #menu .footer .icon-help, #menu .footer .item-icon-left .icon-help { + left: 16px; } + + .item-icon-right .icon, .item-icon-right .icon-help, .item-icon-right .icon-alert, .item-icon-right #menu .footer .icon-help, #menu .footer .item-icon-right .icon-help { + right: 16px; } + + /* + .list .item.item-icon-right { + padding-right: 60px; + } + */ + .item-thumbnail-left > img:first-child, .item-thumbnail-left .item-image, .item-thumbnail-left .item-content > img:first-child, .item-thumbnail-left .item-content .item-image { + border-radius: 50%; } + + .tab-item.activated { + height: calc(100% + 3px); + /* Stretch */ } + + /* List + ==================================*/ + .content + .list { + padding-top: 0; } + + .list .item { + border: none; + /* + padding-left: 16px; + padding-right: 16px; + */ + min-height: 48px; + text-align: left; } + + .list .item.tabs { + padding: initial; } + + .list .item.item-bg-image { + max-height: 150px; + min-height: 150px; } + + .list .item.item-bg-image > img { + height: 100%; + left: 0; + max-width: initial; + opacity: 0.65; + filter: alpha(opacity=65); + position: absolute; + top: 0; + width: 100%; + z-index: 0; } + + .list a.item { + opacity: 1; + filter: alpha(opacity=100); } + + .list .item.item-bg-image h1, .list .item.item-bg-image h2, .list .item.item-bg-image h3, .list .item.item-bg-image h4, .list .item.item-bg-image h5, .list .item.item-bg-image h6 { + color: #fff; + font-weight: bold; + position: relative; + text-shadow: 0 0 3px rgba(0, 0, 0, 0.95); + z-index: 1; } + + .list .item.item-bg-image h2 { + font-size: 24px; } + + .list .item.item-bg-image h2 { + font-size: 24px; } + + .list .item.item-bg-image p { + color: white; + font-size: 17px; + position: relative; + text-shadow: 0 0 4px rgba(0, 0, 0, 0.95); + z-index: 1; } + + .item-avatar, .item-avatar .item-content, .item-avatar-left, .item-avatar-left .item-content { + min-height: 80px; } + + /* List: Thumbnails + ==================================*/ + .item-thumbnail-left, .card > .item.item-thumbnail-left, .item-thumbnail-left .item-content { + padding-left: 106px; } + + .item-thumbnail-right, .card > .item.item-thumbnail-right, .item-thumbnail-right .item-content { + padding-right: 106px; } + + /* List: Avatar + ==================================*/ + .item-avatar > img:first-child, .item-avatar .item-image, .item-avatar .item-content > img:first-child, .item-avatar .item-content .item-image, .item-avatar-left > img:first-child, .item-avatar-left .item-image, .item-avatar-left .item-content > img:first-child, .item-avatar-left .item-content .item-image { + border-radius: 50%; + left: 16px; + max-height: 40px; + max-width: 40px; } + + /* + .item-avatar, .list .item-avatar { + padding-left: 100px; + } + */ + .avatar, .item-avatar .avatar { + background-position: center; + background-size: cover; + border-radius: 50%; + display: inline-block; + height: 56px; + left: 16px; + position: absolute; + width: 56px; } + + /* List: Gallery + ==================================*/ + .list.half { + display: inline-block; + float: left; + margin: 0; + padding: 0; + width: 50%; } + + .list.half:first-child { + padding: 16px 8px 16px 16px; } + + .list.half:last-child { + padding: 16px 16px 16px 8px; } + + .list.half:first-child .card.card-gallery { + margin-left: 0; + margin-right: 0; } + + .list.half:last-child .card.card-gallery { + margin-left: 0; + margin-right: 0; } + + .list.condensed-space > .card, .list.condensed-space > .item { + margin: 0px 0px 2px; } + + .list .card.card-gallery { + display: block; + float: left; + margin: 0 0 0 13px; + padding: 0; + width: auto; } + + .list.half .item { + width: 100%; } + + .list.half .item.card { + margin-bottom: 16px; } + + .list .card.card-gallery.item h2 { + padding: 12px; } + + .list .item.item-gallery img { + width: 100%; } + + .item.item-divider { + border-top: solid 1px rgba(0, 0, 0, 0.12); + font-size: 14px; + font-weight: bold; + height: 48px; + line-height: 48px; + color: rgba(0, 0, 0, 0.54); } + .item.item-divider:first-child { + border: none; } + + .item-avatar, .item-avatar .item-content, .item-avatar-left, .item-avatar-left .item-content, .card > .item-avatar { + padding-left: 72px; } + + .item.active, .item.activated, .item-complex.active .item-content, .item-complex.activated .item-content, .item .item-content.active, .item .item-content.activated { + background-color: transparent; } + + .list-inset { + margin: 20px 30px; + border-left: solid 1px #ccc; + border-radius: 0; + background-color: #fff; } + + .list .item.item-floating-label, + .item-floating-label { + border-bottom: solid 1px #ccc; } + + .loader { + position: relative; + margin: 0px auto; + width: 100px; + height: 100px; + zoom: 1.7; } + + .circular { + -webkit-animation: rotate 2s linear infinite; + animation: rotate 2s linear infinite; + height: 100px; + position: relative; + width: 100px; } + + .path { + stroke-dasharray: 1,200; + stroke-dashoffset: 0; + -webkit-animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite; + animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite; + stroke-linecap: round; } + + @-webkit-keyframes rotate { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + + @keyframes rotate { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + + @-webkit-keyframes dash { + 0% { + stroke-dasharray: 1,200; + stroke-dashoffset: 0; } + 50% { + stroke-dasharray: 89,200; + stroke-dashoffset: -35; } + 100% { + stroke-dasharray: 89,200; + stroke-dashoffset: -124; } } + + @keyframes dash { + 0% { + stroke-dasharray: 1,200; + stroke-dashoffset: 0; } + 50% { + stroke-dasharray: 89,200; + stroke-dashoffset: -35; } + 100% { + stroke-dasharray: 89,200; + stroke-dashoffset: -124; } } + + @-webkit-keyframes color { + 100%, 0% { + stroke: #d62d20; } + 40% { + stroke: #0057e7; } + 66% { + stroke: #008744; } + 80%, 90% { + stroke: #ffa700; } } + + @keyframes color { + 100%, 0% { + stroke: #d62d20; } + 40% { + stroke: #0057e7; } + 66% { + stroke: #008744; } + 80%, 90% { + stroke: #ffa700; } } + + /* Layouts: Login + ==================================*/ + .login { + background-position: 25% 25%; + background-size: 180% 180%; + height: 100%; + -webkit-transition: all 1.5s ease-in-out; + transition: all 1.5s ease-in-out; } + + .login .item { + margin: 0 12px; + padding-left: 0; + padding-right: 0; + width: initial; } + + .login .button-bar { + bottom: 0; + margin: 28px 12px 0; + width: initial; } + + .login .light-bg { + background-color: #fff; } + + .icon.hero-icon:before, .hero-icon.icon-help:before, .hero-icon.icon-alert:before, #menu .footer .hero-icon.icon-help:before { + line-height: 130px; } + + /* Mask + ==================================*/ + .hero.has-mask:after, .item.has-mask:after, .card.has-mask:after { + content: ''; + background: -webkit-linear-gradient(top, transparent 0%, rgba(0, 0, 0, 0.6) 100%); + height: 100%; + left: 0; + position: absolute; + top: 0; + z-index: 0; + width: 100%; } + + .hero.has-mask-reverse:after, .item.has-mask-reverse:after, .card.has-mask-reverse:after { + content: ''; + background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.6) 0%, transparent 100%); + height: 100%; + left: 0; + position: absolute; + top: 0; + z-index: 0; + width: 100%; } + + /* Menu */ + .menu-bottom { + bottom: 16px; + left: 16px; + right: 16px; + position: absolute; } + + .menu-top { + top: 16px; + left: 16px; + right: 16px; + position: absolute; } + + .menu .avatar { + top: 16px; + left: 16px; + height: 65px; + width: 65px; } + + .menu .bar.bar-header.expanded { + box-shadow: none; + min-height: 150px; + color: #fff; } + + .menu-open .bar.bar-header.expanded { + background-position: 0; + background-size: 100%; } + + .has-expanded-header { + top: 150px !important; } + + .motion { + -webkit-transition: all 0.5s ease-out; + transition: all 0.5s ease-out; } + + .fade { + opacity: 0; + filter: alpha(opacity=0); + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transition: all 0.1s ease-out !important; + transition: all 0.1s ease-out !important; } + + .spin-back { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotate(360deg) scale(0) !important; + transform: translateZ(0) rotate(360deg) scale(0) !important; + -webkit-transition: all 0.1s ease-out !important; + transition: all 0.1s ease-out !important; } + + .spiral { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotate(-360deg) scale(0) translate(-120px) !important; + transform: translateZ(0) rotate(-360deg) scale(0) translate(-120px) !important; + -webkit-transition: all 0.1s ease-out !important; + transition: all 0.1s ease-out !important; } + + .spiral-back { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotate(360deg) scale(0) translate(120px) !important; + transform: translateZ(0) rotate(360deg) scale(0) translate(120px) !important; + -webkit-transition: all 0.1s ease-out !important; + transition: all 0.1s ease-out !important; } + + .menu-open .avatar { + opacity: 1; + filter: alpha(opacity=100); + -webkit-transform: translateZ(0) rotate(0) scale(1) !important; + transform: translateZ(0) rotate(0) scale(1) !important; + -webkit-transition: all 0.3s ease-out !important; + transition: all 0.3s ease-out !important; } + + .spin { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotate(0) scale(0) !important; + transform: translateZ(0) rotate(0) scale(0) !important; + -webkit-transition: all 0.3s ease-out !important; + transition: all 0.3s ease-out !important; } + + .spin.on { + -webkit-transform: translateZ(0) rotate(-360deg) scale(1) !important; + transform: translateZ(0) rotate(-360deg) scale(1) !important; } + + .flap { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotateX(0) scale(0) translate(-120px) !important; + transform: translateZ(0) rotateX(0) scale(0) translate(-120px) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .flap.on { + -webkit-transform: translateZ(0) rotateX(-720deg) scale(1) translate(0) !important; + transform: translateZ(0) rotateX(-720deg) scale(1) translate(0) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .drop { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) scale(3) !important; + transform: translateZ(0) scale(3) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .drop.on { + -webkit-transform: translateZ(0) scale(1) !important; + transform: translateZ(0) scale(1) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .flip { + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; + -webkit-transform: translateZ(0) rotateY(0) scale(0) !important; + transform: translateZ(0) rotateY(0) scale(0) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + .flip.on { + -webkit-transform: translateZ(0) rotateY(-720deg) scale(1) !important; + transform: translateZ(0) rotateY(-720deg) scale(1) !important; + -webkit-transition: all 0.5s ease-out !important; + transition: all 0.5s ease-out !important; } + + /* Utilities + ==================================*/ + .bold { + font-weight: bold; } + + .static { + position: static; } + + .pull-left, .popover-helptip .icon.icon-left, .popover-helptip .icon-left.icon-help, .popover-helptip .icon-left.icon-alert, .popover-helptip #menu .footer .icon-left.icon-help, #menu .footer .popover-helptip .icon-left.icon-help, .popover-helptip .icon.icon-bottom-left, .popover-helptip .icon-bottom-left.icon-help, .popover-helptip .icon-bottom-left.icon-alert, .popover-helptip #menu .footer .icon-bottom-left.icon-help, #menu .footer .popover-helptip .icon-bottom-left.icon-help { + float: left; } + + .pull-right, .popover-helptip .icon.icon-right, .popover-helptip .icon-right.icon-help, .popover-helptip .icon-right.icon-alert, .popover-helptip #menu .footer .icon-right.icon-help, #menu .footer .popover-helptip .icon-right.icon-help, .popover-helptip .icon.icon-center, .popover-helptip .icon-center.icon-help, .popover-helptip .icon-center.icon-alert, .popover-helptip #menu .footer .icon-center.icon-help, #menu .footer .popover-helptip .icon-center.icon-help, .popover-helptip .icon.icon-bottom-right, .popover-helptip .icon-bottom-right.icon-help, .popover-helptip .icon-bottom-right.icon-alert, .popover-helptip #menu .footer .icon-bottom-right.icon-help, #menu .footer .popover-helptip .icon-bottom-right.icon-help, .popover-helptip .icon.icon-bottom-center, .popover-helptip .icon-bottom-center.icon-help, .popover-helptip .icon-bottom-center.icon-alert, .popover-helptip #menu .footer .icon-bottom-center.icon-help, #menu .footer .popover-helptip .icon-bottom-center.icon-help { + float: right; } + + .double-padding, .ionic-content.double-padding { + padding: 16px; } + + .double-padding-x { + padding-left: 16px; + padding-right: 16px; } + + .double-padding-y { + padding-top: 16px; + padding-bottom: 16px; } + + .outline { + border-style: solid; + border-width: 1px; } + + .border-top { + border-top: solid 1px #ccc; + padding-top: 30px; } + + .no-border { + border: none; } + + .circle { + border-radius: 50%; } + + .no-padding, .list.no-padding, .bar.no-padding, .button-bar.no-padding, .card.no-padding, .button.no-padding, .item.no-padding { + padding: 0; } + + .flat, .flat.tabs, .flat.button, .flat.button.icon, .flat.button.icon-help, .flat.button.icon-alert, #menu .footer .flat.button.icon-help, .flat.hero { + box-shadow: none; + -webkit-box-shadow: none; } + + /* Utilities : Padding + ==================================*/ + .im-wrapper, .padding, .item.large-button-bar { + padding: 16px !important; } + + .padding-bottom, .popover-share .bar-footer .button-close { + padding-bottom: 16px !important; } + + .padding-top { + padding-top: 16px !important; } + + .padding-left { + padding-left: 16px !important; } + + .padding-right, .popover-share .bar-footer .button-close { + padding-right: 16px !important; } + + .no-padding-bottom { + padding-bottom: 0 !important; } + + .no-padding-top { + padding-top: 0 !important; } + + .no-padding-left { + padding-left: 0 !important; } + + .no-padding-right { + padding-right: 0 !important; } + + /* Utilities : Depth + ==================================*/ + .z1 { + box-shadow: 0px 2px 5px 0 rgba(0, 0, 0, 0.26); } + + /* Utilities : Color + ==================================*/ + .bar.bar-positive.darker { + background-color: #164FAB; } + + /* TODO: Expand to other colors */ + .bar.bar-positive.dark-positive-bg { + background-color: #2C5CAD; } + + /* TODO: Expand to other colors */ + .muted { + color: #C3C3C3; } + + .clear-bg { + background: transparent; } + + /* Motion: Blinds + ==================================*/ + .animate-blinds .item, + .animate-blinds .item { + visibility: hidden; } + + .animate-blinds .item, + .animate-blinds .item { + -ms-transform: scale3d(0.8, 0, 1); + -webkit-transform: scale3d(0.8, 0, 1); + transform: scale3d(0.8, 0, 1); + -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); + transition: transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); } + + .animate-blinds .item-bg-image > img.background, + .animate-blinds .item-bg-image > img.background { + box-shadow: none; + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); } + + .animate-blinds .in, .animate-blinds .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded .animate-blinds .item, .animate-blinds + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-blinds .expanded.item, .animate-blinds + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded .animate-blinds .item, .animate-blinds + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-blinds .expanded.item, .animate-blinds + .animate-ripple .expanded .item, + .animate-ripple .expanded .animate-blinds .item, .animate-blinds + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds .card.card-comment, + .animate-blinds.done > *, .animate-fade-slide-in .expanded .animate-blinds.item > *, + .animate-fade-slide-in .animate-blinds.expanded.item > *, + .animate-fade-slide-in-right .expanded .animate-blinds.item > *, + .animate-fade-slide-in-right .animate-blinds.expanded.item > *, + .animate-ripple .expanded .animate-blinds.item > *, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment > *, + .animate-blinds .in, + .animate-blinds .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded + .animate-blinds .item, + .animate-blinds + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-blinds .expanded.item, + .animate-blinds + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded + .animate-blinds .item, + .animate-blinds + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-blinds .expanded.item, + .animate-blinds + .animate-ripple .expanded .item, + .animate-ripple .expanded + .animate-blinds .item, + .animate-blinds + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-blinds .card.card-comment, + .animate-blinds.done > *, .animate-fade-slide-in .expanded .animate-blinds.item > *, + .animate-fade-slide-in .animate-blinds.expanded.item > *, + .animate-fade-slide-in-right .expanded .animate-blinds.item > *, + .animate-fade-slide-in-right .animate-blinds.expanded.item > *, + .animate-ripple .expanded .animate-blinds.item > *, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment > * { + -ms-transform: translate3d(0, 0, 0); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + + .animate-blinds .in, .animate-blinds .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded .animate-blinds .item, .animate-blinds + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-blinds .expanded.item, .animate-blinds + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded .animate-blinds .item, .animate-blinds + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-blinds .expanded.item, .animate-blinds + .animate-ripple .expanded .item, + .animate-ripple .expanded .animate-blinds .item, .animate-blinds + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds .card.card-comment, + .animate-blinds.done .item, .animate-fade-slide-in .expanded .animate-blinds.item .item, + .animate-fade-slide-in .animate-blinds.expanded.item .item, + .animate-fade-slide-in-right .expanded .animate-blinds.item .item, + .animate-fade-slide-in-right .animate-blinds.expanded.item .item, + .animate-ripple .expanded .animate-blinds.item .item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .item, + .animate-blinds .in, + .animate-blinds .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded + .animate-blinds .item, + .animate-blinds + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-blinds .expanded.item, + .animate-blinds + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded + .animate-blinds .item, + .animate-blinds + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-blinds .expanded.item, + .animate-blinds + .animate-ripple .expanded .item, + .animate-ripple .expanded + .animate-blinds .item, + .animate-blinds + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-blinds .card.card-comment, + .animate-blinds.done .item, .animate-fade-slide-in .expanded .animate-blinds.item .item, + .animate-fade-slide-in .animate-blinds.expanded.item .item, + .animate-fade-slide-in-right .expanded .animate-blinds.item .item, + .animate-fade-slide-in-right .animate-blinds.expanded.item .item, + .animate-ripple .expanded .animate-blinds.item .item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .item { + visibility: visible; } + + .animate-blinds .item, + .animate-blinds .item { + visibility: hidden; } + + .animate-blinds .item, + .animate-blinds .item { + opacity: 0; + filter: alpha(opacity=0); } + + .animate-blinds .in, .animate-blinds .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded .animate-blinds .item, .animate-blinds + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-blinds .expanded.item, .animate-blinds + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded .animate-blinds .item, .animate-blinds + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-blinds .expanded.item, .animate-blinds + .animate-ripple .expanded .item, + .animate-ripple .expanded .animate-blinds .item, .animate-blinds + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds .card.card-comment, + .animate-blinds.done, + .animate-fade-slide-in .expanded .animate-blinds.item, + .animate-fade-slide-in .animate-blinds.expanded.item, + .animate-fade-slide-in-right .expanded .animate-blinds.item, + .animate-fade-slide-in-right .animate-blinds.expanded.item, + .animate-ripple .expanded .animate-blinds.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment, + .animate-blinds .in, + .animate-blinds .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded + .animate-blinds .item, + .animate-blinds + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-blinds .expanded.item, + .animate-blinds + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded + .animate-blinds .item, + .animate-blinds + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-blinds .expanded.item, + .animate-blinds + .animate-ripple .expanded .item, + .animate-ripple .expanded + .animate-blinds .item, + .animate-blinds + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-blinds .card.card-comment, + .animate-blinds.done, + .animate-fade-slide-in .expanded .animate-blinds.item, + .animate-fade-slide-in .animate-blinds.expanded.item, + .animate-fade-slide-in-right .expanded .animate-blinds.item, + .animate-fade-slide-in-right .animate-blinds.expanded.item, + .animate-ripple .expanded .animate-blinds.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment { + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; + opacity: 1; + filter: alpha(opacity=100); } + + .animate-blinds .in, .animate-blinds .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded .animate-blinds .item, .animate-blinds + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-blinds .expanded.item, .animate-blinds + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded .animate-blinds .item, .animate-blinds + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-blinds .expanded.item, .animate-blinds + .animate-ripple .expanded .item, + .animate-ripple .expanded .animate-blinds .item, .animate-blinds + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds .card.card-comment, + .animate-blinds.done, + .animate-fade-slide-in .expanded .animate-blinds.item, + .animate-fade-slide-in .animate-blinds.expanded.item, + .animate-fade-slide-in-right .expanded .animate-blinds.item, + .animate-fade-slide-in-right .animate-blinds.expanded.item, + .animate-ripple .expanded .animate-blinds.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment, + .animate-blinds .in, + .animate-blinds .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded + .animate-blinds .item, + .animate-blinds + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-blinds .expanded.item, + .animate-blinds + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded + .animate-blinds .item, + .animate-blinds + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-blinds .expanded.item, + .animate-blinds + .animate-ripple .expanded .item, + .animate-ripple .expanded + .animate-blinds .item, + .animate-blinds + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-blinds .card.card-comment, + .animate-blinds.done, + .animate-fade-slide-in .expanded .animate-blinds.item, + .animate-fade-slide-in .animate-blinds.expanded.item, + .animate-fade-slide-in-right .expanded .animate-blinds.item, + .animate-fade-slide-in-right .animate-blinds.expanded.item, + .animate-ripple .expanded .animate-blinds.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment { + visibility: visible; } + + .animate-blinds.done .in, .animate-fade-slide-in .expanded .animate-blinds.item .in, + .animate-fade-slide-in .animate-blinds.expanded.item .in, + .animate-fade-slide-in-right .expanded .animate-blinds.item .in, + .animate-fade-slide-in-right .animate-blinds.expanded.item .in, + .animate-ripple .expanded .animate-blinds.item .in, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .in, .animate-blinds.done .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded .animate-blinds.done .item, .animate-fade-slide-in .expanded .animate-blinds.item .item, .animate-fade-slide-in .animate-blinds.expanded.item .item, .animate-blinds.done + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-blinds.done .expanded.item, .animate-blinds.done + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded .animate-blinds.done .item, .animate-fade-slide-in-right .expanded .animate-blinds.item .item, .animate-fade-slide-in-right .animate-blinds.expanded.item .item, .animate-blinds.done + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-blinds.done .expanded.item, .animate-blinds.done + .animate-ripple .expanded .item, + .animate-ripple .expanded .animate-blinds.done .item, .animate-ripple .expanded .animate-blinds.item .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .item, .animate-blinds.done + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.done .card.card-comment, + .animate-fade-slide-in + .animate-ripple .animate-blinds.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple + .animate-fade-slide-in .animate-blinds.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-fade-slide-in-right + .animate-ripple .animate-blinds.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple + .animate-fade-slide-in-right .animate-blinds.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .animate-blinds.item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .card.card-comment, + .animate-blinds.done .in, .animate-fade-slide-in .expanded .animate-blinds.item .in, + .animate-fade-slide-in .animate-blinds.expanded.item .in, + .animate-fade-slide-in-right .expanded .animate-blinds.item .in, + .animate-fade-slide-in-right .animate-blinds.expanded.item .in, + .animate-ripple .expanded .animate-blinds.item .in, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .in, + .animate-blinds.done .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded + .animate-blinds.done .item, .animate-fade-slide-in .expanded .animate-blinds.item .item, .animate-fade-slide-in .animate-blinds.expanded.item .item, + .animate-blinds.done + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-blinds.done .expanded.item, + .animate-blinds.done + .animate-fade-slide-in-right .expanded .item, + .animate-fade-slide-in-right .expanded + .animate-blinds.done .item, .animate-fade-slide-in-right .expanded .animate-blinds.item .item, .animate-fade-slide-in-right .animate-blinds.expanded.item .item, + .animate-blinds.done + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-blinds.done .expanded.item, + .animate-blinds.done + .animate-ripple .expanded .item, + .animate-ripple .expanded + .animate-blinds.done .item, .animate-ripple .expanded .animate-blinds.item .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .item, + .animate-blinds.done + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-blinds.done .card.card-comment, + .animate-fade-slide-in + .animate-ripple .animate-blinds.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple + .animate-fade-slide-in .animate-blinds.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-fade-slide-in-right + .animate-ripple .animate-blinds.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple + .animate-fade-slide-in-right .animate-blinds.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .animate-blinds.item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .card.card-comment { + opacity: 1; + filter: alpha(opacity=100); } + + .animate-blinds .has-mask-reverse:after, + .animate-blinds .has-mask-reverse:after { + opacity: 0; + filter: alpha(opacity=0); + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; } + + .animate-blinds.done .has-mask-reverse:after, .animate-fade-slide-in .expanded .animate-blinds.item .has-mask-reverse:after, + .animate-fade-slide-in .animate-blinds.expanded.item .has-mask-reverse:after, + .animate-fade-slide-in-right .expanded .animate-blinds.item .has-mask-reverse:after, + .animate-fade-slide-in-right .animate-blinds.expanded.item .has-mask-reverse:after, + .animate-ripple .expanded .animate-blinds.item .has-mask-reverse:after, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .has-mask-reverse:after, + .animate-blinds.done .has-mask-reverse:after, .animate-fade-slide-in .expanded .animate-blinds.item .has-mask-reverse:after, + .animate-fade-slide-in .animate-blinds.expanded.item .has-mask-reverse:after, + .animate-fade-slide-in-right .expanded .animate-blinds.item .has-mask-reverse:after, + .animate-fade-slide-in-right .animate-blinds.expanded.item .has-mask-reverse:after, + .animate-ripple .expanded .animate-blinds.item .has-mask-reverse:after, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-blinds.card.card-comment .has-mask-reverse:after { + opacity: 1; + filter: alpha(opacity=100); } + + .animate-blinds .out, + .animate-blinds .out { + -ms-transform: scale3d(0, 0, 1); + -webkit-transform: scale3d(0, 0, 1); + transform: scale3d(0, 0, 1); } + + /* Motion: Pan In Left + ==================================*/ + .animate-pan-in-left, + .animate-pan-in-left { + background-position: 0% 0%; } + + /* Motion: Ripple + ==================================*/ + .animate-ripple .done, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .done, .animate-fade-slide-in .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment { + visibility: hidden; } + + .animate-ripple .done, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .done, .animate-fade-slide-in .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment { + -ms-transform: scale3d(0.8, 0, 1); + -webkit-transform: scale3d(0.8, 0, 1); + transform: scale3d(0.8, 0, 1); + -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); + transition: transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); } + + .animate-ripple .item-bg-image img.background, + .animate-ripple .item-bg-image img.background { + box-shadow: none; + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); } + + .animate-ripple .in, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple.done, .animate-fade-slide-in .expanded .animate-ripple.item, + .animate-fade-slide-in .animate-ripple.expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.item, + .animate-fade-slide-in-right .animate-ripple.expanded.item, + .animate-ripple .expanded .animate-ripple.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment, + .animate-ripple .in, .animate-fade-slide-in .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple.done, .animate-fade-slide-in .expanded .animate-ripple.item, + .animate-fade-slide-in .animate-ripple.expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.item, + .animate-fade-slide-in-right .animate-ripple.expanded.item, + .animate-ripple .expanded .animate-ripple.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment { + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); } + + .animate-ripple .in, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple.done, .animate-fade-slide-in .expanded .animate-ripple.item, + .animate-fade-slide-in .animate-ripple.expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.item, + .animate-fade-slide-in-right .animate-ripple.expanded.item, + .animate-ripple .expanded .animate-ripple.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment, + .animate-ripple .in, .animate-fade-slide-in .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple.done, .animate-fade-slide-in .expanded .animate-ripple.item, + .animate-fade-slide-in .animate-ripple.expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.item, + .animate-fade-slide-in-right .animate-ripple.expanded.item, + .animate-ripple .expanded .animate-ripple.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment { + visibility: visible; } + + .animate-ripple .item { + -ms-transform: scale3d(0, 0, 1); + -webkit-transform: scale3d(0, 0, 1); + transform: scale3d(0, 0, 1); + opacity: 0; + filter: alpha(opacity=0); } + + .animate-ripple .item.in, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .item.expanded, + .animate-fade-slide-in .animate-ripple .item.expanded, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .item.expanded, + .animate-fade-slide-in-right .animate-ripple .item.expanded, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .item.card.card-comment { + opacity: 1; + filter: alpha(opacity=100); } + + .animate-ripple .done, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment { + visibility: hidden; } + + .animate-ripple .done, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .done, .animate-fade-slide-in .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in + .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-ripple .item, + .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right + .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment { + -ms-transform: scale3d(0.8, 0, 1); + -webkit-transform: scale3d(0.8, 0, 1); + transform: scale3d(0.8, 0, 1); + -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); + transition: transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); } + + /* Uncomment if you want images to fade in after the card + + .animate-ripple .in .item-bg-image img:last-child, + .animate-ripple .in .item-bg-image img:last-child { + opacity: 0; + } + + .animate-ripple.done .item-bg-image img:last-child, + .animate-ripple.done .item-bg-image img:last-child { + opacity: 1; + -moz-transition: all 1s ease-in-out; + -o-transition: all 1s ease-in-out; + -webkit-transition: all 1s ease-in-out; + transition: all 1s ease-in-out; + } + + .animate-ripple .item-bg-image img:last-child, + .animate-ripple .item-bg-image img:last-child { + box-shadow: none; + -moz-transform: scale3d(1, 1, 1); + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + .animate-ripple .in .item-bg-image img:last-child, + .animate-ripple .in .item-bg-image img:last-child { + opacity: 0; + } + + .animate-ripple.done .item-bg-image img:last-child, + .animate-ripple.done .item-bg-image img:last-child { + opacity: 1; + -moz-transition: all 0.3s ease-in-out; + -o-transition: all 0.3s ease-in-out; + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; + } + + .animate-ripple .in, + .animate-ripple .in { + opacity: 0.6; + } + */ + .animate-ripple .in, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple.done, .animate-fade-slide-in .expanded .animate-ripple.item, + .animate-fade-slide-in .animate-ripple.expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.item, + .animate-fade-slide-in-right .animate-ripple.expanded.item, + .animate-ripple .expanded .animate-ripple.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment, .animate-ripple .in, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple.done, .animate-fade-slide-in .expanded .animate-ripple.item, + .animate-fade-slide-in .animate-ripple.expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.item, + .animate-fade-slide-in-right .animate-ripple.expanded.item, + .animate-ripple .expanded .animate-ripple.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment { + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; } + + .animate-ripple .in, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple.done, .animate-fade-slide-in .expanded .animate-ripple.item, + .animate-fade-slide-in .animate-ripple.expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.item, + .animate-fade-slide-in-right .animate-ripple.expanded.item, + .animate-ripple .expanded .animate-ripple.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment, .animate-ripple .in, .animate-fade-slide-in .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple .item, .animate-ripple + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple .expanded.item, .animate-ripple .expanded .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple.done, .animate-fade-slide-in .expanded .animate-ripple.item, + .animate-fade-slide-in .animate-ripple.expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.item, + .animate-fade-slide-in-right .animate-ripple.expanded.item, + .animate-ripple .expanded .animate-ripple.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment { + visibility: visible; } + + .animate-ripple.done .in, .animate-fade-slide-in .expanded .animate-ripple.item .in, + .animate-fade-slide-in .animate-ripple.expanded.item .in, + .animate-fade-slide-in-right .expanded .animate-ripple.item .in, + .animate-fade-slide-in-right .animate-ripple.expanded.item .in, + .animate-ripple .expanded .animate-ripple.item .in, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment .in, .animate-fade-slide-in .expanded .animate-ripple.done .item, .animate-fade-slide-in .expanded .animate-ripple.item .item, .animate-fade-slide-in .animate-ripple.expanded.item .item, .animate-ripple.done + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple.done .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.done .item, .animate-fade-slide-in-right .expanded .animate-ripple.item .item, .animate-fade-slide-in-right .animate-ripple.expanded.item .item, .animate-ripple.done + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple.done .expanded.item, .animate-ripple.done .expanded .item, .animate-ripple .expanded .animate-ripple.item .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment .item, .animate-ripple.done .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-fade-slide-in .animate-ripple.expanded.item .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-fade-slide-in-right .animate-ripple.expanded.item .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .animate-ripple.item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment .card.card-comment, .animate-ripple.done .in, .animate-fade-slide-in .expanded .animate-ripple.item .in, + .animate-fade-slide-in .animate-ripple.expanded.item .in, + .animate-fade-slide-in-right .expanded .animate-ripple.item .in, + .animate-fade-slide-in-right .animate-ripple.expanded.item .in, + .animate-ripple .expanded .animate-ripple.item .in, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment .in, .animate-fade-slide-in .expanded .animate-ripple.done .item, .animate-fade-slide-in .expanded .animate-ripple.item .item, .animate-fade-slide-in .animate-ripple.expanded.item .item, .animate-ripple.done + .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in .animate-ripple.done .expanded.item, + .animate-fade-slide-in-right .expanded .animate-ripple.done .item, .animate-fade-slide-in-right .expanded .animate-ripple.item .item, .animate-fade-slide-in-right .animate-ripple.expanded.item .item, .animate-ripple.done + .animate-fade-slide-in-right .expanded.item, + .animate-fade-slide-in-right .animate-ripple.done .expanded.item, .animate-ripple.done .expanded .item, .animate-ripple .expanded .animate-ripple.item .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment .item, .animate-ripple.done .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-fade-slide-in .animate-ripple.expanded.item .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-fade-slide-in-right .animate-ripple.expanded.item .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .animate-ripple.item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment .card.card-comment { + opacity: 1; + filter: alpha(opacity=100); } + + .animate-ripple .has-mask-reverse:after, .animate-ripple .has-mask-reverse:after { + opacity: 0; + filter: alpha(opacity=0); + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; } + + .animate-ripple.done .has-mask-reverse:after, .animate-fade-slide-in .expanded .animate-ripple.item .has-mask-reverse:after, + .animate-fade-slide-in .animate-ripple.expanded.item .has-mask-reverse:after, + .animate-fade-slide-in-right .expanded .animate-ripple.item .has-mask-reverse:after, + .animate-fade-slide-in-right .animate-ripple.expanded.item .has-mask-reverse:after, + .animate-ripple .expanded .animate-ripple.item .has-mask-reverse:after, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment .has-mask-reverse:after, .animate-ripple.done .has-mask-reverse:after, .animate-fade-slide-in .expanded .animate-ripple.item .has-mask-reverse:after, + .animate-fade-slide-in .animate-ripple.expanded.item .has-mask-reverse:after, + .animate-fade-slide-in-right .expanded .animate-ripple.item .has-mask-reverse:after, + .animate-fade-slide-in-right .animate-ripple.expanded.item .has-mask-reverse:after, + .animate-ripple .expanded .animate-ripple.item .has-mask-reverse:after, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-ripple.card.card-comment .has-mask-reverse:after { + opacity: 1; + filter: alpha(opacity=100); } + + .animate-ripple .out, .animate-ripple .out { + -ms-transform: scale3d(0, 0, 1); + -webkit-transform: scale3d(0, 0, 1); + transform: scale3d(0, 0, 1); } + + /* Motion: Slide / Fade In + ==================================*/ + .animate-fade-slide-in .item, + .animate-fade-slide-in .item { + visibility: hidden; } + + .animate-fade-slide-in .item, + .animate-fade-slide-in .item { + -ms-transform: scale3d(0.8, 0, 1); + -webkit-transform: scale3d(0.8, 0, 1); + transform: scale3d(0.8, 0, 1); + -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); + transition: transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); } + + .animate-fade-slide-in .item-bg-image img.background, + .animate-fade-slide-in .item-bg-image img.background { + box-shadow: none; + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); } + + .animate-fade-slide-in .in, .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in .item, + .animate-ripple .expanded .animate-fade-slide-in .item, .animate-fade-slide-in + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in .card.card-comment, + .animate-fade-slide-in.done .item, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .item, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item .item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .item, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .item, + .animate-ripple .expanded .animate-fade-slide-in.item .item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .item, + .animate-fade-slide-in .in, .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-fade-slide-in .item, + .animate-ripple .expanded + .animate-fade-slide-in .item, + .animate-fade-slide-in + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in .card.card-comment, + .animate-fade-slide-in.done .item, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .item, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item .item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .item, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .item, + .animate-ripple .expanded .animate-fade-slide-in.item .item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .item { + -ms-transform: translate3d(0, 0, 0); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + + .animate-fade-slide-in .in, .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in .item, + .animate-ripple .expanded .animate-fade-slide-in .item, .animate-fade-slide-in + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in .card.card-comment, + .animate-fade-slide-in.done .item, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .item, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item .item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .item, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .item, + .animate-ripple .expanded .animate-fade-slide-in.item .item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .item, + .animate-fade-slide-in .in, .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-fade-slide-in .item, + .animate-ripple .expanded + .animate-fade-slide-in .item, + .animate-fade-slide-in + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in .card.card-comment, + .animate-fade-slide-in.done .item, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .item, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item .item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .item, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .item, + .animate-ripple .expanded .animate-fade-slide-in.item .item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .item { + visibility: visible; } + + .list .item.item-bg-image, + .list .item.item-bg-image { + max-height: 150px; } + + .animate-fade-slide-in .item, + .animate-fade-slide-in .item { + visibility: hidden; } + + .animate-fade-slide-in .item, + .animate-fade-slide-in .item { + -ms-transform: translate3d(-250px, 250px, 0); + -webkit-transform: translate3d(-250px, 250px, 0); + transform: translate3d(-250px, 250px, 0); + -webkit-transition: -webkit-transform 0.5s cubic-bezier(0.55, 0, 0.1, 1); + transition: transform 0.5s cubic-bezier(0.55, 0, 0.1, 1); + opacity: 0; + filter: alpha(opacity=0); } + + .animate-fade-slide-in .in, .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in .item, + .animate-ripple .expanded .animate-fade-slide-in .item, .animate-fade-slide-in + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in .card.card-comment, + .animate-fade-slide-in.done, + .animate-fade-slide-in .expanded .animate-fade-slide-in.item, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item, + .animate-ripple .expanded .animate-fade-slide-in.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment, + .animate-fade-slide-in .in, .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-fade-slide-in .item, + .animate-ripple .expanded + .animate-fade-slide-in .item, + .animate-fade-slide-in + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in .card.card-comment, + .animate-fade-slide-in.done, + .animate-fade-slide-in .expanded .animate-fade-slide-in.item, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item, + .animate-ripple .expanded .animate-fade-slide-in.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment { + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + -webkit-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; + opacity: 1; + filter: alpha(opacity=100); } + + .animate-fade-slide-in .in, .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in .item, + .animate-ripple .expanded .animate-fade-slide-in .item, .animate-fade-slide-in + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in .card.card-comment, + .animate-fade-slide-in.done, + .animate-fade-slide-in .expanded .animate-fade-slide-in.item, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item, + .animate-ripple .expanded .animate-fade-slide-in.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment, + .animate-fade-slide-in .in, .animate-fade-slide-in .expanded .item, .animate-fade-slide-in .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-fade-slide-in .item, + .animate-ripple .expanded + .animate-fade-slide-in .item, + .animate-fade-slide-in + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in .card.card-comment, + .animate-fade-slide-in.done, + .animate-fade-slide-in .expanded .animate-fade-slide-in.item, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item, + .animate-ripple .expanded .animate-fade-slide-in.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment { + visibility: visible; } + + .animate-fade-slide-in.done .in, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .in, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item .in, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .in, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .in, + .animate-ripple .expanded .animate-fade-slide-in.item .in, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .in, .animate-fade-slide-in.done .expanded .item, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .item, .animate-fade-slide-in .animate-fade-slide-in.expanded.item .item, .animate-fade-slide-in.done .expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.done .item, .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .item, .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .item, + .animate-ripple .expanded .animate-fade-slide-in.done .item, .animate-ripple .expanded .animate-fade-slide-in.item .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .item, .animate-fade-slide-in.done + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.done .card.card-comment, + .animate-ripple .animate-fade-slide-in.expanded.item .animate-fade-slide-in.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .animate-fade-slide-in.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.expanded.item .card.card-comment, + .animate-fade-slide-in-right + .animate-ripple .animate-fade-slide-in.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .animate-fade-slide-in.item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .card.card-comment, + .animate-fade-slide-in.done .in, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .in, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item .in, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .in, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .in, + .animate-ripple .expanded .animate-fade-slide-in.item .in, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .in, .animate-fade-slide-in.done .expanded .item, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .item, .animate-fade-slide-in .animate-fade-slide-in.expanded.item .item, .animate-fade-slide-in.done .expanded.item, + .animate-fade-slide-in-right .expanded + .animate-fade-slide-in.done .item, .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .item, .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .item, + .animate-ripple .expanded + .animate-fade-slide-in.done .item, .animate-ripple .expanded .animate-fade-slide-in.item .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .item, + .animate-fade-slide-in.done + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in.done .card.card-comment, + .animate-ripple .animate-fade-slide-in.expanded.item .animate-fade-slide-in.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .animate-fade-slide-in.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.expanded.item .card.card-comment, + .animate-fade-slide-in-right + .animate-ripple .animate-fade-slide-in.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .animate-fade-slide-in.item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .card.card-comment { + opacity: 1; + filter: alpha(opacity=100); } + + .animate-fade-slide-in .has-mask-reverse:after, + .animate-fade-slide-in .has-mask-reverse:after { + opacity: 0; + filter: alpha(opacity=0); + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; } + + .animate-fade-slide-in.done .has-mask-reverse:after, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .has-mask-reverse:after, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item .has-mask-reverse:after, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .has-mask-reverse:after, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .has-mask-reverse:after, + .animate-ripple .expanded .animate-fade-slide-in.item .has-mask-reverse:after, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .has-mask-reverse:after, + .animate-fade-slide-in.done .has-mask-reverse:after, .animate-fade-slide-in .expanded .animate-fade-slide-in.item .has-mask-reverse:after, + .animate-fade-slide-in .animate-fade-slide-in.expanded.item .has-mask-reverse:after, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in.item .has-mask-reverse:after, + .animate-fade-slide-in-right .animate-fade-slide-in.expanded.item .has-mask-reverse:after, + .animate-ripple .expanded .animate-fade-slide-in.item .has-mask-reverse:after, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in.card.card-comment .has-mask-reverse:after { + opacity: 1; + filter: alpha(opacity=100); } + + .animate-fade-slide-in .out, + .animate-fade-slide-in .out { + -ms-transform: scale3d(0, 0, 1); + -webkit-transform: scale3d(0, 0, 1); + transform: scale3d(0, 0, 1); } + + /* Motion: Slide In Right + ==================================*/ + .animate-fade-slide-in-right .item, + .animate-fade-slide-in-right .item { + visibility: hidden; } + + .animate-fade-slide-in-right .item, + .animate-fade-slide-in-right .item { + -ms-transform: scale3d(0.8, 0, 1); + -webkit-transform: scale3d(0.8, 0, 1); + transform: scale3d(0.8, 0, 1); + -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); + transition: transform 0.3s cubic-bezier(0.55, 0, 0.1, 1); } + + .animate-fade-slide-in-right .item-bg-image > img.background, + .animate-fade-slide-in-right .item-bg-image > img.background { + box-shadow: none; + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); } + + .animate-fade-slide-in-right .in, .animate-fade-slide-in .expanded .animate-fade-slide-in-right .item, .animate-fade-slide-in-right .expanded .item, .animate-fade-slide-in-right .expanded.item, + .animate-ripple .expanded .animate-fade-slide-in-right .item, .animate-fade-slide-in-right + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right .card.card-comment, + .animate-fade-slide-in-right.done > *, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item > *, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item > *, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item > *, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item > *, + .animate-ripple .expanded .animate-fade-slide-in-right.item > *, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment > *, + .animate-fade-slide-in-right .in, .animate-fade-slide-in .expanded + .animate-fade-slide-in-right .item, .animate-fade-slide-in-right .expanded .item, .animate-fade-slide-in-right .expanded.item, + .animate-ripple .expanded + .animate-fade-slide-in-right .item, + .animate-fade-slide-in-right + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in-right .card.card-comment, + .animate-fade-slide-in-right.done > *, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item > *, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item > *, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item > *, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item > *, + .animate-ripple .expanded .animate-fade-slide-in-right.item > *, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment > * { + -ms-transform: translate3d(0, 0, 0); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + + .animate-fade-slide-in-right .in, .animate-fade-slide-in .expanded .animate-fade-slide-in-right .item, .animate-fade-slide-in-right .expanded .item, .animate-fade-slide-in-right .expanded.item, + .animate-ripple .expanded .animate-fade-slide-in-right .item, .animate-fade-slide-in-right + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right .card.card-comment, + .animate-fade-slide-in-right.done .item, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item .item, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item .item, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item .item, + .animate-ripple .expanded .animate-fade-slide-in-right.item .item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .item, + .animate-fade-slide-in-right .in, .animate-fade-slide-in .expanded + .animate-fade-slide-in-right .item, .animate-fade-slide-in-right .expanded .item, .animate-fade-slide-in-right .expanded.item, + .animate-ripple .expanded + .animate-fade-slide-in-right .item, + .animate-fade-slide-in-right + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in-right .card.card-comment, + .animate-fade-slide-in-right.done .item, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item .item, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item .item, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item .item, + .animate-ripple .expanded .animate-fade-slide-in-right.item .item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .item { + visibility: visible; } + + .animate-fade-slide-in-right .item, + .animate-fade-slide-in-right .item { + visibility: hidden; } + + .animate-fade-slide-in-right .item, + .animate-fade-slide-in-right .item { + -ms-transform: translate3d(250px, 250px, 0); + -webkit-transform: translate3d(250px, 250px, 0); + transform: translate3d(250px, 250px, 0); + -webkit-transition: -webkit-transform 0.5s cubic-bezier(0.55, 0, 0.1, 1); + transition: transform 0.5s cubic-bezier(0.55, 0, 0.1, 1); + opacity: 0; + filter: alpha(opacity=0); } + + .animate-fade-slide-in-right .in, .animate-fade-slide-in .expanded .animate-fade-slide-in-right .item, .animate-fade-slide-in-right .expanded .item, .animate-fade-slide-in-right .expanded.item, + .animate-ripple .expanded .animate-fade-slide-in-right .item, .animate-fade-slide-in-right + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right .card.card-comment, + .animate-fade-slide-in-right.done, + .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item, + .animate-ripple .expanded .animate-fade-slide-in-right.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment, + .animate-fade-slide-in-right .in, .animate-fade-slide-in .expanded + .animate-fade-slide-in-right .item, .animate-fade-slide-in-right .expanded .item, .animate-fade-slide-in-right .expanded.item, + .animate-ripple .expanded + .animate-fade-slide-in-right .item, + .animate-fade-slide-in-right + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in-right .card.card-comment, + .animate-fade-slide-in-right.done, + .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item, + .animate-ripple .expanded .animate-fade-slide-in-right.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment { + -ms-transform: scale3d(1, 1, 1); + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; + opacity: 1; + filter: alpha(opacity=100); } + + .animate-fade-slide-in-right .in, .animate-fade-slide-in .expanded .animate-fade-slide-in-right .item, .animate-fade-slide-in-right .expanded .item, .animate-fade-slide-in-right .expanded.item, + .animate-ripple .expanded .animate-fade-slide-in-right .item, .animate-fade-slide-in-right + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right .card.card-comment, + .animate-fade-slide-in-right.done, + .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item, + .animate-ripple .expanded .animate-fade-slide-in-right.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment, + .animate-fade-slide-in-right .in, .animate-fade-slide-in .expanded + .animate-fade-slide-in-right .item, .animate-fade-slide-in-right .expanded .item, .animate-fade-slide-in-right .expanded.item, + .animate-ripple .expanded + .animate-fade-slide-in-right .item, + .animate-fade-slide-in-right + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in-right .card.card-comment, + .animate-fade-slide-in-right.done, + .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item, + .animate-ripple .expanded .animate-fade-slide-in-right.item, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment { + visibility: visible; } + + .animate-fade-slide-in-right.done .in, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item .in, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .in, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item .in, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item .in, + .animate-ripple .expanded .animate-fade-slide-in-right.item .in, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .in, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.done .item, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item .item, .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .item, .animate-fade-slide-in-right.done .expanded .item, .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item .item, .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item .item, .animate-fade-slide-in-right.done .expanded.item, + .animate-ripple .expanded .animate-fade-slide-in-right.done .item, .animate-ripple .expanded .animate-fade-slide-in-right.item .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .item, .animate-fade-slide-in-right.done + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.done .card.card-comment, + .animate-fade-slide-in + .animate-ripple .animate-fade-slide-in-right.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .animate-fade-slide-in-right.expanded.item .animate-fade-slide-in-right.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .animate-fade-slide-in-right.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.expanded.item .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .animate-fade-slide-in-right.item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .card.card-comment, + .animate-fade-slide-in-right.done .in, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item .in, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .in, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item .in, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item .in, + .animate-ripple .expanded .animate-fade-slide-in-right.item .in, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .in, .animate-fade-slide-in .expanded + .animate-fade-slide-in-right.done .item, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item .item, .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .item, .animate-fade-slide-in-right.done .expanded .item, .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item .item, .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item .item, .animate-fade-slide-in-right.done .expanded.item, + .animate-ripple .expanded + .animate-fade-slide-in-right.done .item, .animate-ripple .expanded .animate-fade-slide-in-right.item .item, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .item, + .animate-fade-slide-in-right.done + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded + .animate-fade-slide-in-right.done .card.card-comment, + .animate-fade-slide-in + .animate-ripple .animate-fade-slide-in-right.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .animate-fade-slide-in-right.expanded.item .animate-fade-slide-in-right.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, + .animate-ripple .animate-fade-slide-in-right.expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.expanded.item .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .animate-fade-slide-in-right.item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .card.card-comment, .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .card.card-comment { + opacity: 1; + filter: alpha(opacity=100); } + + .animate-fade-slide-in-right .has-mask-reverse:after, + .animate-fade-slide-in-right .has-mask-reverse:after { + opacity: 0; + filter: alpha(opacity=0); + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; } + + .animate-fade-slide-in-right.done .has-mask-reverse:after, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item .has-mask-reverse:after, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .has-mask-reverse:after, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item .has-mask-reverse:after, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item .has-mask-reverse:after, + .animate-ripple .expanded .animate-fade-slide-in-right.item .has-mask-reverse:after, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .has-mask-reverse:after, + .animate-fade-slide-in-right.done .has-mask-reverse:after, .animate-fade-slide-in .expanded .animate-fade-slide-in-right.item .has-mask-reverse:after, + .animate-fade-slide-in .animate-fade-slide-in-right.expanded.item .has-mask-reverse:after, + .animate-fade-slide-in-right .expanded .animate-fade-slide-in-right.item .has-mask-reverse:after, + .animate-fade-slide-in-right .animate-fade-slide-in-right.expanded.item .has-mask-reverse:after, + .animate-ripple .expanded .animate-fade-slide-in-right.item .has-mask-reverse:after, + .animate-ripple .expanded.item .card-avatar-small.expanded .item .card-avatar-small .expanded .item .card-avatar-small.expanded .card.card-comment .card-avatar-small .expanded .animate-fade-slide-in-right.card.card-comment .has-mask-reverse:after { + opacity: 1; + filter: alpha(opacity=100); } + + .animate-fade-slide-in-right .out, + .animate-fade-slide-in-right .out { + -ms-transform: scale3d(0, 0, 1); + -webkit-transform: scale3d(0, 0, 1); + transform: scale3d(0, 0, 1); } + + /* Motion: Slide Up + ==================================*/ + .slide-up, + .slide-up, + .hero.slide-up { + height: 100%; + overflow: hidden; + text-align: center; } + + .slide-up { + -webkit-transition: all 1s cubic-bezier(0.55, 0, 0.1, 1); + transition: all 1s cubic-bezier(0.55, 0, 0.1, 1); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + + .slide-up *, + .slide-up *, + .hero.slide-up * { + opacity: 0; + filter: alpha(opacity=0); } + + .hero.slide-up + .mid-bar, + .slide-up + .mid-bar, + .slide-up + .mid-bar { + height: 100%; + opacity: 0.7; + filter: alpha(opacity=70); + -webkit-transform: translate3d(100%, -240px, 0); + transform: translate3d(100%, -240px, 0); } + + /*! + * Waves v0.5.4 + * http://fian.my.id/Waves + * + * Copyright 2014 Alfiana E. Sibuea and other contributors + * Forked by Zach Fitzgerald and other contributors for Ionic Material + * + * Released under the MIT license + * https://github.com/fians/Waves/blob/master/LICENSE + * + */ + .ink, .button-fab, .button-flat, .button-raised, .button-clear, .button-text, .popup .button { + position: relative; + cursor: pointer; + /*display: inline-block;*/ + overflow: hidden; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-tap-highlight-color: transparent; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; } + + .ink-ripple { + position: absolute; + border-radius: 50%; + width: 100px; + height: 100px; + margin-top: -50px; + margin-left: -50px; + opacity: 0; + background-color: rgba(255, 255, 255, 0.4); + -webkit-transition: all 0.5s ease-out; + -moz-transition: all 0.5s ease-out; + -o-transition: all 0.5s ease-out; + transition: all 0.5s ease-out; + -webkit-transition-property: -webkit-transform, opacity; + -moz-transition-property: -moz-transform, opacity; + -o-transition-property: -o-transform, opacity; + transition-property: transform, opacity; + -webkit-transform: scale(0); + -moz-transform: scale(0); + -ms-transform: scale(0); + -o-transform: scale(0); + transform: scale(0); + pointer-events: none; } + + .ink-notransition { + -webkit-transition: none !important; + -moz-transition: none !important; + -o-transition: none !important; + transition: none !important; } + + .button-fab, + .button-flat, + .button-clear, + .button-text, + .button-raised, + .ink-button, + .ink-circle { + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -ms-transform: translateZ(0); + -o-transform: translateZ(0); + transform: translateZ(0); } + + .button-fab.activated, + .button-flat.activated, + .button-raised.activated, + .button-clear.activated, + .activated.button-text, + .ink-button.activated, + .ink.activated, + .ink-circle.activated, + .popup .button.activated, + .button-fab:active, + .button-flat:active, + .button-raised:active, + .button-clear:active, + .button-text:active, + .ink-button:active, + .ink:active, + .ink-circle:active, + .popup .button:active { + -webkit-mask-image: -webkit-radial-gradient(circle, #ffffff 100%, #000000 100%); } + + .ink-button, + .ink-button:visited, + .ink-button:link, + .button-fab, + .button-fab:visited, + .button-fab:link, + .button-flat, + .button-flat:visited, + .button-flat:link, + .button-raised, + .button-raised:visited, + .button-raised:link, + .button-clear, + .button-text, + .button-clear:visited, + .button-text:visited, + .button-clear:link, + .button-text:link { + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + border: none; + outline: none; + /* color: inherit; */ + /* background-color: rgba(0, 0, 0, 0); */ + font-size: 14px; + text-align: center; + text-decoration: none; + z-index: 1; } + + + /* Ionic Overrides + ==================================*/ + * { + font-family: "RobotoDraft","Roboto","Helvetica Neue", "Segoe UI", sans-serif; } + + .rounded { + border-radius: 4px; } + + a { + cursor: pointer; } + + .has-header.expanded { + /* Expanded modifier */ + top: 76px; } + + /* Bar Overrides + ==================================*/ + .bar { + border-bottom: none; + padding: 0; } + + .bar .button { + min-height: 44px; + min-width: 44px; + max-width: 48px; + margin-bottom: 0; + max-height: 44px; + width: 48px; } + + .bar .title + .buttons.buttons-right { + right: 0; + top: 0; } + + /* Title Overrides + ==================================*/ + .title-left, + .title.title-left { + left: 48px; } + + .title-right, + .title.title-right { + left: 48px; } + + /* Background Colors + ==================================*/ + .positive-bg, + .button-positive, + .button-text, + .bar .button-positive, + .bar .button-text, + .header-positive, + .button-bar-positive, + .bar-positive, + .positive-border, + .positive-bg:hover, + .bar .button-positive:hover, + .bar .button-text:hover, + .button-positive:hover, + .button-text:hover, + .header-positive:hover, + .button-bar-positive:hover, + .bar-positive:hover, + .positive-border:hover, + .positive-bg:active, + .bar .button-positive:active, + .bar .button-text:active, + .button-positive:active, + .button-text:active, + .header-positive:active, + .button-bar-positive:active, + .bar-positive:active, + .positive-border:active, + .positive-bg.activated, + .bar .button-positive.activated, + .bar .activated.button-text, + .button-positive.activated, + .activated.button-text, + .header-positive.activated, + .button-bar-positive.activated, + .bar-positive.activated, + .positive-border.activated { + background-color: #3F51B5; + color: #fff; } + + .positive-900-bg, + .button-positive-900, + .bar .button-positive-900, + .header-positive-900, + .button-bar-positive-900, + .bar-positive-900, + .positive-900-border, + .positive-900-bg:hover, + .button-positive-900:hover, + .bar .button-positive-900:hover, + .header-positive-900:hover, + .button-bar-positive-900:hover, + .bar-positive-900:hover, + .positive-900-border:hover, + .positive-900-bg:active, + .bar .button-positive-900:active, + .button-positive-900:active, + .header-positive-900:active, + .button-bar-positive-900:active, + .bar-positive-900:active, + .positive-900-border:active, + .positive-900-bg.activated, + .button-positive-900.activated, + .bar .button-positive-900.activated, + .header-positive-900.activated, + .button-bar-positive-900.activated, + .bar-positive-900.activated, + .positive-900-border.activated { + background-color: #1A237E; + color: #fff; } + + .positive-100-bg, + .button-positive-100, + .bar .button-positive-100, + .header-positive-100, + .button-bar-positive-100, + .bar-positive-100, + .positive-100-border, + .positive-100-bg:hover, + .button-positive-100:hover, + .bar .button-positive-100:hover, + .header-positive-100:hover, + .button-bar-positive-100:hover, + .bar-positive-100:hover, + .positive-100-border:hover, + .positive-100-bg:active, + .button-positive-100:active, + .bar .button-positive-100:active, + .header-positive-100:active, + .button-bar-positive-100:active, + .bar-positive-100:active, + .positive-100-border:active, + .positive-100-bg.activated, + .button-positive-100.activated, + .bar .button-positive-100.activated, + .header-positive-100.activated, + .button-bar-positive-100.activated, + .bar-positive-100.activated, + .positive-100-border.activated { + background-color: #C5CAE9; + color: #fff; } + + .calm-bg, + .button-calm, + .bar .button-calm, + .header-calm, + .button-bar-calm, + .bar-calm, + .calm-border, + .calm-bg:hover, + .button-calm:hover, + .bar .button-calm:hover, + .header-calm:hover, + .button-bar-calm:hover, + .bar-calm:hover, + .calm-border:hover, + .calm-bg:active, + .button-calm:active, + .bar .button-calm:active, + .header-calm:active, + .button-bar-calm:active, + .bar-calm:active, + .calm-border:active, + .calm-bg.activated, + .button-calm.activated, + .bar .button-calm.activated, + .header-calm.activated, + .button-bar-calm.activated, + .bar-calm.activated, + .calm-border.activated { + background-color: #2196F3; + color: #fff; } + + .calm-900-bg, + .button-calm-900, + .bar .button-calm-900, + .header-calm-900, + .button-bar-calm-900, + .bar-calm-900, + .calm-900-border, + .calm-900-bg:hover, + .button-calm-900:hover, + .bar .button-calm-900:hover, + .header-calm-900:hover, + .button-bar-calm-900:hover, + .bar-calm-900:hover, + .calm-900-border:hover, + .calm-900-bg:active, + .button-calm-900:active, + .bar .button-calm-900:active, + .header-calm-900:active, + .button-bar-calm-900:active, + .bar-calm-900:active, + .calm-900-border:active, + .calm-900-bg.activated, + .button-calm-900.activated, + .bar .button-calm-900.activated, + .header-calm-900.activated, + .button-bar-calm-900.activated, + .bar-calm-900.activated, + .calm-900-border.activated { + background-color: #0D47A1; + color: #fff; } + + .calm-100-bg, + .button-calm-100, + .bar .button-calm-100, + .header-calm-100, + .button-bar-calm-100, + .bar-calm-100, + .calm-100-border, + .calm-100-bg:hover, + .button-calm-100:hover, + .bar .button-calm-100:hover, + .header-calm-100:hover, + .button-bar-calm-100:hover, + .bar-calm-100:hover, + .calm-100-border:hover, + .calm-100-bg:active, + .button-calm-100:active, + .bar .button-calm-100:active, + .header-calm-100:active, + .button-bar-calm-100:active, + .bar-calm-100:active, + .calm-100-border:active, + .calm-100-bg.activated, + .button-calm-100.activated, + .bar .button-calm-100.activated, + .header-calm-100.activated, + .button-bar-calm-100.activated, + .bar-calm-100.activated, + .calm-100-border.activated { + background-color: #BBDEFB; + color: #fff; } + + .royal-bg, + .button-royal, + .bar .button-royal, + .header-royal, + .button-bar-royal, + .bar-royal, + .royal-border, + .royal-bg:hover, + .button-royal:hover, + .bar .button-royal:hover, + .header-royal:hover, + .button-bar-royal:hover, + .bar-royal:hover, + .royal-border:hover, + .royal-bg:active, + .button-royal:active, + .bar .button-royal:active, + .header-royal:active, + .button-bar-royal:active, + .bar-royal:active, + .royal-border:active, + .royal-bg.activated, + .button-royal.activated, + .bar .button-royal.activated, + .header-royal.activated, + .button-bar-royal.activated, + .bar-royal.activated, + .royal-border.activated { + background-color: #673AB7; + color: #fff; } + + .royal-900-bg, + .button-royal-900, + .bar .button-royal-900, + .header-royal-900, + .button-bar-royal-900, + .bar-royal-900, + .royal-900-border, + .royal-900-bg:hover, + .button-royal-900:hover, + .bar .button-royal-900:hover, + .header-royal-900:hover, + .button-bar-royal-900:hover, + .bar-royal-900:hover, + .royal-900-border:hover, + .royal-900-bg:active, + .button-royal-900:active, + .bar .button-royal-900:active, + .header-royal-900:active, + .button-bar-royal-900:active, + .bar-royal-900:active, + .royal-900-border:active, + .royal-900-bg.activated, + .button-royal-900.activated, + .bar .button-royal-900.activated, + .header-royal-900.activated, + .button-bar-royal-900.activated, + .bar-royal-900.activated, + .royal-900-border.activated { + background-color: #311B92; + color: #fff; } + + .royal-100-bg, + .button-royal-100, + .bar .button-royal-100, + .header-royal-100, + .button-bar-royal-100, + .bar-royal-100, + .royal-100-border, + .royal-100-bg:hover, + .button-royal-100:hover, + .bar .button-royal-100:hover, + .header-royal-100:hover, + .button-bar-royal-100:hover, + .bar-royal-100:hover, + .royal-100-border:hover, + .royal-100-bg:active, + .button-royal-100:active, + .bar .button-royal-100:active, + .header-royal-100:active, + .button-bar-royal-100:active, + .bar-royal-100:active, + .royal-100-border:active, + .royal-100-bg.activated, + .button-royal-100.activated, + .bar .button-royal-100.activated, + .header-royal-100.activated, + .button-bar-royal-100.activated, + .bar-royal-100.activated, + .royal-100-border.activated { + background-color: #D1C4E9; + color: #fff; } + + .balanced-bg, + .button-balanced, + .bar .button-balanced, + .header-balanced, + .button-bar-balanced, + .bar-balanced, + .balanced-border, + .balanced-bg:hover, + .button-balanced:hover, + .bar .button-balanced:hover, + .header-balanced:hover, + .button-bar-balanced:hover, + .bar-balanced:hover, + .balanced-border:hover, + .balanced-bg:active, + .button-balanced:active, + .bar .button-balanced:active, + .header-balanced:active, + .button-bar-balanced:active, + .bar-balanced:active, + .balanced-border:active, + .balanced-bg.activated, + .button-balanced.activated, + .bar .button-balanced.activated, + .header-balanced.activated, + .button-bar-balanced.activated, + .bar-balanced.activated, + .balanced-border.activated { + background-color: #4CAF50; + color: #fff; } + + .balanced-900-bg, + .button-balanced-900, + .bar .button-balanced-900, + .header-balanced-900, + .button-bar-balanced-900, + .bar-balanced-900, + .balanced-900-border, + .balanced-900-bg:hover, + .button-balanced-900:hover, + .bar .button-balanced-900:hover, + .header-balanced-900:hover, + .button-bar-balanced-900:hover, + .bar-balanced-900:hover, + .balanced-900-border:hover, + .balanced-900-bg:active, + .button-balanced-900:active, + .bar .button-balanced-900:active, + .header-balanced-900:active, + .button-bar-balanced-900:active, + .bar-balanced-900:active, + .balanced-900-border:active, + .balanced-900-bg.activated, + .button-balanced-900.activated, + .bar .button-balanced-900.activated, + .header-balanced-900.activated, + .button-bar-balanced-900.activated, + .bar-balanced-900.activated, + .balanced-900-border.activated { + background-color: #1B5E20; + color: #fff; } + + .balanced-100-bg, + .button-balanced-100, + .bar .button-balanced-100, + .header-balanced-100, + .button-bar-balanced-100, + .bar-balanced-100, + .balanced-100-border, + .balanced-100-bg:hover, + .button-balanced-100:hover, + .bar .balanced-100-bg:hover, + .header-balanced-100:hover, + .button-bar-balanced-100:hover, + .bar-balanced-100:hover, + .balanced-100-border:hover, + .balanced-100-bg:active, + .button-balanced-100:active, + .bar .button-balanced-100:active, + .header-balanced-100:active, + .button-bar-balanced-100:active, + .bar-balanced-100:active, + .balanced-100-border:active, + .balanced-100-bg.activated, + .button-balanced-100.activated, + .bar .button-balanced-100.activated, + .header-balanced-100.activated, + .button-bar-balanced-100.activated, + .bar-balanced-100.activated, + .balanced-100-border.activated { + background-color: #C8E6C9; + color: #fff; } + + .energized-bg, + .button-energized, + .bar .button-energized, + .header-energized, + .button-bar-energized, + .bar-energized, + .energized-border, + .energized-bg:hover, + .button-energized:hover, + .bar .button-energized:hover, + .header-energized:hover, + .button-bar-energized:hover, + .bar-energized:hover, + .energized-border:hover, + .energized-bg:active, + .button-energized:active, + .bar .button-energized:active, + .header-energized:active, + .button-bar-energized:active, + .bar-energized:active, + .energized-border:active, + .energized-bg.activated, + .button-energized.activated, + .bar .button-energized.activated, + .header-energized.activated, + .button-bar-energized.activated, + .bar-energized.activated, + .energized-border.activated { + background-color: #FF9800; + color: #fff; } + + .energized-900-bg, + .button-energized-900, + .bar .button-energized-900, + .header-energized-900, + .button-bar-energized-900, + .bar-energized-900, + .energized-900-border, + .energized-900-bg:hover, + .button-energized-900:hover, + .bar .button-energized-900:hover, + .header-energized-900:hover, + .button-bar-energized-900:hover, + .bar-energized-900:hover, + .energized-900-border:hover, + .energized-900-bg:active, + .button-energized-900:active, + .bar .button-energized-900:active, + .header-energized-900:active, + .button-bar-energized-900:active, + .bar-energized-900:active, + .energized-900-border:active, + .energized-900-bg.activated, + .button-energized-900.activated, + .bar .button-energized-900.activated, + .header-energized-900.activated, + .button-bar-energized-900.activated, + .bar-energized-900.activated, + .energized-900-border.activated { + background-color: #E65100; + color: #fff; } + + .energized-100-bg, + .button-energized-100, + .bar .button-energized-100, + .header-energized-100, + .button-bar-energized-100, + .bar-energized-100, + .energized-100-border, + .energized-100-bg:hover, + .button-energized-100:hover, + .bar .button-energized-100:hover, + .header-energized-100:hover, + .button-bar-energized-100:hover, + .bar-energized-100:hover, + .energized-100-border:hover, + .energized-100-bg:active, + .button-energized-100:active, + .bar .button-energized-100:active, + .header-energized-100:active, + .button-bar-energized-100:active, + .bar-energized-100:active, + .energized-100-border:active, + .energized-100-bg.activated, + .button-energized-100.activated, + .bar .button-energized-100.activated, + .header-energized-100.activated, + .button-bar-energized-100.activated, + .bar-energized-100.activated, + .energized-100-border.activated { + background-color: #FFE0B2; } + + .assertive-bg, + .button-assertive, + .bar .button-assertive, + .header-assertive, + .button-bar-assertive, + .bar-assertive, + .assertive-border, + .assertive-bg:hover, + .button-assertive:hover, + .bar .button-assertive:hover, + .header-assertive:hover, + .button-bar-assertive:hover, + .bar-assertive:hover, + .assertive-border:hover, + .assertive-bg:active, + .button-assertive:active, + .bar .button-assertive:active, + .header-assertive:active, + .button-bar-assertive:active, + .bar-assertive:active, + .assertive-border:active, + .assertive-bg.activated, + .button-assertive.activated, + .bar .button-assertive.activated, + .header-assertive.activated, + .button-bar-assertive.activated, + .bar-assertive.activated, + .assertive-border.activated { + background-color: #F44336; + color: #fff; } + + .assertive-900-bg, + .button-assertive-900, + .bar .button-assertive-900, + .header-assertive-900, + .button-bar-assertive-900, + .bar-assertive-900, + .assertive-900-border, + .assertive-900-bg:hover, + .button-assertive-900:hover, + .bar .button-assertive-900:hover, + .header-assertive-900:hover, + .button-bar-assertive-900:hover, + .bar-assertive-900:hover, + .assertive-900-border:hover, + .assertive-900-bg:active, + .button-assertive-900:active, + .bar .button-assertive-900:active, + .header-assertive-900:active, + .button-bar-assertive-900:active, + .bar-assertive-900:active, + .assertive-900-border:active, + .assertive-900-bg.activated, + .button-assertive-900.activated, + .bar .button-assertive-900.activated, + .header-assertive-900.activated, + .button-bar-assertive-900.activated, + .bar-assertive-900.activated, + .assertive-900-border.activated { + background-color: #B71C1C; + color: #fff; } + + .assertive-100-bg, + .button-assertive-100, + .bar .button-assertive-100, + .header-assertive-100, + .button-bar-assertive-100, + .bar-assertive-100, + .assertive-100-border, + .assertive-100-bg:hover, + .button-assertive-100:hover, + .bar .button-assertive-100:hover, + .header-assertive-100:hover, + .button-bar-assertive-100:hover, + .bar-assertive-100:hover, + .assertive-100-border:hover, + .assertive-100-bg:active, + .button-assertive-100:active, + .bar .button-assertive-100:active, + .header-assertive-100:active, + .button-bar-assertive-100:active, + .bar-assertive-100:active, + .assertive-100-border:active, + .assertive-100-bg.activated, + .bar .button-assertive-100.activated, + .button-assertive-100.activated, + .header-assertive-100.activated, + .button-bar-assertive-100.activated, + .bar-assertive-100.activated, + .assertive-100-border.activated { + background-color: #FFCDD2; + color: #fff; } + + .stable-bg, + .button-stable, + .bar .button-stable, + .header-stable, + .button-bar-stable, + .bar-stable, + .stable-border, + .stable-bg:hover, + .button-stable:hover, + .bar .button-stable:hover, + .header-stable:hover, + .button-bar-stable:hover, + .bar-stable:hover, + .stable-border:hover, + .stable-bg:active, + .button-stable:active, + .bar .button-stable:active, + .header-stable:active, + .button-bar-stable:active, + .bar-stable:active, + .stable-border:active, + .stable-bg.activated, + .button-stable.activated, + .bar .button-stable.activated, + .header-stable.activated, + .button-bar-stable.activated, + .bar-stable.activated, + .stable-border.activated { + background-color: #E0E0E0; + color: #fff; } + + /* Text Colors + ==================================*/ + .positive, .icon-help, + .positive *, .icon-help *, + *.positive, + *.icon-help, + .positive:hover, + .icon-help:hover, + .positive:hover *, .icon-help:hover *, + *.positive:hover, + *.icon-help:hover, + .positive:active, + .icon-help:active, + .positive:active *, .icon-help:active *, + *.positive:active, + *.icon-help:active { + color: #3F51B5; } + + .positive-900, + .positive-900 *, + *.positive-900, + .positive-900:hover, + .positive-900:hover *, + *.positive-900:hover, + .positive-900:active, + .positive-900:active *, + *.positive-900:active { + color: #3F51B5; } + + .positive-100, + .positive-100 *, + *.positive-100, + .positive-100:hover, + .positive-100:hover *, + *.positive-100:hover, + .positive-100:active, + .positive-100:active *, + *.positive-100:active { + color: #C5CAE9; } + + .calm-100, + .calm-100 *, + *.calm-100, + .calm-100:hover, + .calm-100:hover *, + *.calm-100:hover, + .calm-100:active, + .calm-100:active *, + *.calm-100:active { + color: #2196F3; } + + .calm-900, + .calm-900 *, + *.calm-900, + .calm-900:hover, + .calm-900:hover *, + *.calm-900:hover, + .calm-900:active, + .calm-900:active *, + *.calm-900:active { + color: #0D47A1; } + + .calm-100, + .calm-100 *, + *.calm-100, + .calm-100:hover, + .calm-100:hover *, + *.calm-100:hover, + .calm-100:active, + .calm-100:active *, + *.calm-100:active { + color: #BBDEFB; } + + .royal, + .royal *, + *.royal, + .royal:hover, + .royal:hover *, + *.royal:hover, + .royal:active, + .royal:active *, + *.royal:active { + color: #673AB7; } + + .royal-900, + .royal-900 *, + *.royal-900, + .royal-900:hover, + .royal-900:hover *, + *.royal-900:hover, + .royal-900:active, + .royal-900:active *, + *.royal-900:active { + color: #311B92; } + + .royal-100, + .royal-100 *, + *.royal-100, + .royal-100:hover, + .royal-100:hover *, + *.royal-100:hover, + .royal-100:active, + .royal-100:active *, + *.royal-100:active { + color: #D1C4E9; } + + .balanced, + .balanced *, + *.balanced, + .balanced:hover, + .balanced:hover *, + *.balanced:hover, + .balanced:active, + .balanced:active *, + *.balanced:active { + color: #4CAF50; } + + .balanced-900, + .balanced-900 *, + *.balanced-900, + .balanced-900:hover, + .balanced-900:hover *, + *.balanced-900:hover, + .balanced-900:active, + .balanced-900:active *, + *.balanced-900:active { + color: #1B5E20; } + + .balanced-100, + .balanced-100 *, + *.balanced-100, + .balanced-100:hover, + .balanced-100:hover *, + *.balanced-100:hover, + .balanced-100:active, + .balanced-100:active *, + *.balanced-100:active { + color: #C8E6C9; } + + .energized, + .energized *, + *.energized, + .energized:hover, + .energized:hover *, + *.energized:hover, + .energized:active, + .energized:active *, + *.energized:active { + color: #FF9800; } + + .energized-900, + .energized-900 *, + *.energized-900, + .energized-900:hover, + .energized-900:hover *, + *.energized-900:hover, + .energized-900:active, + .energized-900:active *, + *.energized-900:active { + color: #E65100; } + + .energized-100, + .energized-100 *, + *.energized-100, + .energized-100:hover, + .energized-100:hover *, + *.energized-100:hover, + .energized-100:active, + .energized-100:active *, + *.energized-100:active { + color: #FFE0B2; } + + .assertive, .icon-alert, + .assertive *, .icon-alert *, + *.assertive, + *.icon-alert, + .assertive:hover, + .icon-alert:hover, + .assertive:hover *, .icon-alert:hover *, + *.assertive:hover, + *.icon-alert:hover, + .assertive:active, + .icon-alert:active, + .assertive:active *, .icon-alert:active *, + *.assertive:active, + *.icon-alert:active { + color: #F44336; } + + .assertive-900, + .assertive-900 *, + *.assertive-900, + .assertive-900:hover, + .assertive-900:hover *, + *.assertive-900:hover, + .assertive-900:active, + .assertive-900:active *, + *.assertive-900:active { + color: #B71C1C; } + + .assertive-100, + .assertive-100 *, + *.assertive-100, + .assertive-100:hover, + .assertive-100:hover *, + *.assertive-100:hover, + .assertive-100:active, + .assertive-100:active *, + *.assertive-100:active { + color: #FFCDD2; } + + .stable, + .stable *, + *.stable, + .stable:hover, + .stable:hover *, + *.stable:hover, + .stable:active, + .stable:active *, + *.stable:active { + color: #E0E0E0; } + + .light, + .light *, + *.light, + .light:hover, + .light:hover *, + *.light:hover, + .light:active, + .light:active *, + *.light:active { + color: #fff; } + + .dark, + .dark *, + *.dark, + .dark:hover, + .dark:hover *, + *.dark:hover, + .dark:active, + .dark:active *, + *.dark:active { + color: #444; } + + .light-border { + border-color: #ddd; } + + .navbar-default .navbar-nav > li > a { + margin: 0; + padding-right: 26px; + padding-left: 26px; + border-top: 3px solid transparent; + color: #BFD5C9; + opacity: 1; } + + /* Mid-Bar + ==================================*/ + .mid-bar { + padding: 16px; } + + .mid-bar h1, + .mid-bar h2, + .mid-bar h3, + .mid-bar h4, + .mid-bar h5, + .mid-bar h6 { + color: #fff; + margin-bottom: 5px; } + + .mid-bar p { + color: rgba(255, 255, 255, 0.5); + margin-bottom: 0; } + + /* Item + ==================================*/ + .item-avatar, + .item-avatar .item-content, + .item-avatar-left, + .item-avatar-left .item-content, + .card > .item-avatar { + padding-left: 95px; } + + .item, + .item-complex .item-content, + .item-radio .item-content { + background-color: transparent; } + + .dark-bg h2, + .item.dark-bg h2 { + color: #fff; } + + .tabs-striped .tabs { + box-shadow: 0px 2px 5px 0 rgba(0, 0, 0, 0.26); } + + .bar .button.button-clear, .bar .button.button-text { + color: #fff; } + + .bar .button.button-icon .icon:before, .bar .button.button-icon .icon-help:before, .bar .button.button-icon .icon-alert:before, .bar .button.button-icon #menu .footer .icon-help:before, #menu .footer .bar .button.button-icon .icon-help:before, + .bar .button.button-icon.icon-left:before, + .bar .button.button-icon.icon-right:before, + .bar .button.button-icon:before { + vertical-align: top; + font-size: 24px; } + + .button-icon.button.active, + .button-icon.button.activated { + opacity: initial; } + + /* Button + ==================================*/ + .button { + overflow: hidden !important; } + + @font-face { + font-family: "Cesiumicons"; + src: url("../fonts/cesiumicons.eot?v=1.2"); + src: url("../fonts/cesiumicons.eot?v=1.2#iefix") format("embedded-opentype"), url("../fonts/cesiumicons.ttf?v=1.2") format("truetype"), url("../fonts/cesiumicons.woff?v=1.2") format("woff"), url("../fonts/cesiumicons.woff") format("woff"), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiID4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8bWV0YWRhdGE+R2VuZXJhdGVkIGJ5IEljb01vb248L21ldGFkYXRhPgo8ZGVmcz4KPGZvbnQgaWQ9ImNlc2l1bWljb25zIiBob3Jpei1hZHYteD0iMTAyNCI+Cjxmb250LWZhY2UgdW5pdHMtcGVyLWVtPSIxMDI0IiBhc2NlbnQ9Ijk2MCIgZGVzY2VudD0iLTY0IiAvPgo8bWlzc2luZy1nbHlwaCBob3Jpei1hZHYteD0iMTAyNCIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDIwOyIgaG9yaXotYWR2LXg9IjUxMiIgZD0iIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTkwMDsiIGQ9Ik03MDQuNjMxIDU3MS4xMjhjLTg4LjYxMy0xNDEuNDA5LTIyMC40MDMtMjYzLjQwOC0zODUuNTIxLTMwNS40NzMtNjcuMjUyLTE4LjQ5My0xMzcuMTEyLTI1LjgyMi0yMDYuNzA1LTI3LjAyMiA4NS41NDktMTYzLjA5NSAyNzUuODEtMjYyLjI3MiA0NTguNTQ1LTIzNy45NSAxODEuMTY2IDE5LjA3NiAzNDEuNjYyIDE1Ny4yMTUgMzg4LjMzOCAzMzMuMTYyLTU0LjYwMSAxMDMuOTI0LTE0MS40OSAxOTcuODc0LTI1NC42NTYgMjM3LjI4M3oiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTAxOyIgZD0iTTcwNS45MzcgNTcyLjA4OGMtMTYuNzU2LTExMS44MTUtODUuMDg2LTIwNy4yLTEwNy4yNjctMzE3LjIyMS05LjE4OC01MS41NDEgMjYuNzg2LTExMC42NDItMTQuNTc5LTE1NS41MTQtNDYuMjEtNTIuNDAyLTExOC45MDctNjUuMzc5LTE4MS45MzgtODcuNDY2IDE3Ny43My00Ny45MSAzNzkuNjYgMjQuMjE1IDQ4NS45ODIgMTc0Ljc4IDUwLjU1IDY5LjExNiA4MC45OTIgMTUyLjY4OSA4Ni42OTYgMjM4LjEyNS00Ni4wODUgOS40ODMtNjkuNDM2IDU1LjAyMC0xMTAuNTU2IDc0LjIwMS00OS45MTcgMjkuOTkyLTEwMy41NzEgNTMuNTE0LTE1OC4zMzkgNzMuMDk1eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU5MDI7IiBkPSJNNzA0LjQyMiA1NjMuNGMtMjMuNzg2LTUxLjQwOC0yNi40MzYtMTA5Ljc1Ny01NC4wODQtMTU5LjcyNi03LjIxMS0zMi45MDktNDEuMDkxLTg0LjI4OC0yOS40OTgtMTA2LjQ4OSAxMDEuNTktMTYuNTQyIDIwMy4xODEtMzMuMDg1IDMwNC43NzEtNDkuNjI3IDE4LjI3OCAzNS42NDkgMzEuODQ1IDczLjcxMSA0MC4yMDEgMTEyLjg5NC03My44NjggNzkuMjY5LTE1MC40NzEgMTYzLjQyNi0yNTUuMzU4IDIwMC42MzVsLTYuMDMyIDIuMzE0eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU5MDM7IiBkPSJNNjY4LjYxNiA0NDUuNzk0Yy0yMC45ODMtMzEuNjc5LTI3LjI0NS03MC40MDgtNDQuMTA0LTEwNC40MjYtMTYuMjIxLTM1LjY4OS01MS40MTUtMTE5LjQ3MiAxOS42ODQtMTA5Ljg5IDUwLjQ1OSAyNC42NTQgOTUuMDUwLTEzLjM3OSAxNDUuODE5LTE2LjkyOSA0MC4zMTctNS41NjEgODIuMTM3LTQuNjY1IDEyMS4yOTUgNy4yMDEgMTQuOTgzIDMxLjcxNiA1MC42ODYgODIuNTk0IDM4LjcyNiAxMDguMzA1LTQ4LjU2MyA5Ljg2Ny05OS40NzMgMTMuODc5LTE0NS4yMTUgMzMuNjkgMTkuMjczIDQ1LjU5NS01NC45NzQgNTUuNDY1LTg5Ljk3NiA2OC44NC0xNS4zNDEgNC42MzctMzAuNzY1IDguOTk4LTQ2LjIyOSAxMy4yMDh6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTkwNDsiIGQ9Ik02MDcuNzE0IDE2MC44NzNjLTMwLjE4My04NS4wMDItMTIzLjE4Ni0xMTkuOTQ4LTIwMS44MzItMTQ1Ljk0MyA1LjAyMC0xMS4xODYgNzEuMTg2LTE2LjMyNSAxMDAuNzg3LTE3LjMyNiAxMTcuMTE1LTMuMDY3IDIzNC41NDIgNDEuMDg2IDMyMC40OCAxMjAuNzUyLTc0LjgzMSAyLjgzNC0xNDkuNTQ5IDE0Ljc4NC0yMTkuNDM1IDQyLjUxN3oiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTA1OyIgZD0iTTU5OC40ODUgMjY4LjUzNGMtNC4xNzQtNDIuNzY0LTI1LjE4OC0xMTUuOTM2IDM0LjAyOC0xMjguNDk0IDU4LjUzNy0xNC41ODEgMTE5LjQzNC0xOC41MTEgMTc3LjA2Ny0zNy4wMjAgNDUuMjAxIDM3LjQ0NyA4My4xNjcgODMuNTk5IDExMS4xMiAxMzUuMjE3LTEwNy45OC0xLjY4MS0yMTkuNDMxLTEwLjIwNC0zMjIuMjE1IDMwLjI5N3oiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTA2OyIgZD0iTTYwNy4yMSA2MDAuNzhjMTguOTU5IDIuMjkgMzUuMjM0IDEuODk2IDI4LjI4OC0yMS43MiA1LjkzNS0xNC42NDQtMzYuNjE0LTE0LjYwNy0yOC4yODggMS44NDEgMCA2LjYyNiAwIDEzLjI1MiAwIDE5Ljg3OXoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTA3OyIgZD0iTTQ0NC41NDEgNzAyLjk2MmMyMS4wODggMy45NTggMzIuNjU0LTEuNjA0IDI2Ljk1NC0yNC40MzUtNS42NzMtMTEuMDcxLTM3LjY5Ny03LjY1LTI2Ljk1NCAxNC4wMzYgMCAzLjQ2NiAwIDYuOTMzIDAgMTAuMzk5eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU5MDg7IiBkPSJNNTA0LjUzMiA2ODEuNzhjMTMuNDc4LTMuMjk4IDQzLjIzNiA5LjY4MiAzNi43NTUtMTMuNTc1IDYuMjU0LTIzLjAzMC03LjA1Ny0yNi40OTYtMjcuMTUtMjMuMTgtMTguNTY3LTUuNDk2LTUuODcxIDI2LjUyNy05LjYwNSAzNi43NTV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTkwOTsiIGQ9Ik01MDIuNTM5IDQxNy40MjZjMTguNzg2IDAgMzcuNTcyIDAgNTYuMzU4IDAgMC0xOC43ODYgMC0zNy41NzIgMC01Ni4zNTgtMTguNzg2IDAtMzcuNTcyIDAtNTYuMzU4IDAgMCAxOC43ODYgMCAzNy41NzIgMCA1Ni4zNTh6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTkwYTsiIGQ9Ik01MDguODU2IDYzMC4xNTdjMTMuNDc4LTMuMjk4IDQzLjIzNiA5LjY4MiAzNi43NTUtMTMuNTc1IDYuMjU0LTIzLjAzMC03LjA1Ny0yNi40OTYtMjcuMTUtMjMuMTgtMTguNTY3LTUuNDk2LTUuODcxIDI2LjUyNy05LjYwNSAzNi43NTV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTkwYjsiIGQ9Ik01NjkuMTAzIDQ3NC4xNGMxOC45NyAxLjkyOSAzNi40OTIgMi40MDkgMjkuNDA0LTIxLjcyIDYuODk0LTE1LjkzMi0zNy4yMzUtMTUuODMzLTI5LjQwNCAwLjcyNSAwIDYuOTk4IDAgMTMuOTk2IDAgMjAuOTk0eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU5MGM7IiBkPSJNNjI3LjA4NyA1MzEuNDAzYzE5LjM1IDcuODY5IDI5LjQwOC05LjU4MiAxOS4zMzgtMjIuMDUzLTIxLjU4My00LjE0Ny0yMC44MDEgMy4zODctMTkuMzM4IDIyLjA1M3oiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTBkOyIgZD0iTTU0Ny42MjcgNTI1LjIzMWMxMy40NzgtMy4yOTggNDMuMjM2IDkuNjgyIDM2Ljc1NS0xMy41NzUgNi4yNTQtMjMuMDMwLTcuMDU3LTI2LjQ5Ni0yNy4xNS0yMy4xOC0xOC41NjctNS40OTYtNS44NzEgMjYuNTI3LTkuNjA1IDM2Ljc1NXoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTBlOyIgZD0iTTQwMy44MDIgMzM1LjAyNGMxNC40MjYtMS45OTggMzYuNzMgMy44ODIgNDYuNTU2LTIuNzE1LTIuMDIwLTE0LjMxNSAzLjkxMy0zNi41ODQtMi43MTUtNDYuMjkyLTEyLjg3OSAzLjU0NS00MC4wMTctNy4xNjktNDMuODQxIDUuNDMgMCAxNC41MjYgMCAyOS4wNTEgMCA0My41Nzd6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTkwZjsiIGQ9Ik00NDcuOTA3IDQwNi4wODRjMTYuODM2LTAuMTE3IDM5LjY3NyA1Ljc3IDMxLjg1NC0xOS4wMDUgNy44Mi0yNC4zNTUtMTYuMDgwLTE2Ljk5LTMxLjg1NC0xNy43NSAwIDEyLjI1MiAwIDI0LjUwMyAwIDM2Ljc1NXoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTEwOyIgZD0iTTUxNS4yOTEgNDY4LjU2N2MtMTguOTcxIDEuODk0LTM2LjYxMiAyLjQ1OS0yOS41MS0yMS43Mi0yLjUzOC0xMi45OSAzOS42MjctMTMuMzc0IDI5LjUxIDUuODkxIDAgNS4yNzYgMCAxMC41NTMgMCAxNS44Mjl6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTkxMTsiIGQ9Ik01NzguNDg2IDU3Mi44NjZjMjEuMjMyIDQuOTIgMjkuNDY5LTMuMTU2IDI0LjUwMy0yNC40MzUtMTMuMTA0LTguNTMyLTMyLjk1NS0yLjEwNi0yNC41MDMgMTkuMjAxdjUuMjM0eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU5MTI7IiBkPSJNNjAxLjQ3MSA2NDEuNjg5Yy0xOC45NzEgMS44OTQtMzYuNjEyIDIuNDU5LTI5LjUxLTIxLjcyLTIuNTM4LTEyLjk5IDM5LjYyNy0xMy4zNzQgMjkuNTEgNS44OTEgMCA1LjI3NiAwIDEwLjU1MyAwIDE1LjgyOXoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTE1OyIgZ2x5cGgtbmFtZT0iZGlhc3BvcmEiIGhvcml6LWFkdi14PSIxMDY0IiBkPSJNNjcwLjEgMjIuMTA5Yy0yOC42OTIgNDAuMDQ2LTczLjQ1OSAxMDIuNTcxLTk5LjQ4MiAxMzguOTQ1LTI2LjU3OSAzNy4xNTEtNDguMjAyIDY2LjE0Ni00OS4zNCA2Ni4xNjEtMS4xNjkgMC4wMTUtNDIuOTg2LTU2LjE5Ni05OC45MTItMTMyLjk2MS01My4yODgtNzMuMTQzLTk3LjMzLTEzMi45ODctOTcuODcyLTEzMi45ODctMS41MTYgMC0xOTIuMTE0IDEzNC4yNS0xOTIuNjA1IDEzNS42NjMtMC4yMzcgMC42ODQgNDIuODUgNjMuOTM1IDk1Ljc1MSAxNDAuNTU5czk2LjE4MiAxNDAuNTIzIDk2LjE4MiAxNDEuOTk5YzAgMi4zOC0xNy4xNDIgOC4zOTgtMTUxLjYwNSA1My4yMjYtODMuMzgzIDI3Ljc5OC0xNTIuNDIyIDUwLjg2MS0xNTMuNDIgNTEuMjUxLTEuMzg4IDAuNTQyIDYuNTUgMjcuMTAzIDMzLjc4MyAxMTMuMDMyIDE5LjU3OCA2MS43NzggMzYuMDQwIDExMi44MjggMzYuNTgxIDExMy40NDRzNzMuMDExLTIyLjU3NCAxNjEuMDQzLTUxLjUzNGM4OC4wMzMtMjguOTYgMTYwLjc5Ni01Mi42NTQgMTYxLjY5Ni01Mi42NTNzMS45MTkgMS4zNDggMi4yNjMgMi45OTRjMC4zNDQgMS42NDYgMS4xMDQgNzYuNjAxIDEuNjg4IDE2Ni41NjZzMS41NDYgMTY0LjMyMiAyLjEzNyAxNjUuMjM2YzAuODQ3IDEuMzA5IDI1LjU3NiAxLjY1OCAxMTYuMzY0IDEuNjQyIDYzLjQwOC0wLjAxMSAxMTUuOTQ4LTAuNDYgMTE2Ljc1Ni0wLjk5NyAxLjAxOC0wLjY3NyAyLjc1Ny01MC4xMzggNS42Ny0xNjEuMjI2IDQuNzgzLTE4Mi40MDggNC44ODYtMTg0Ljg1MiA3Ljc5NS0xODQuODUyIDEuMTI4IDAgNzAuODk2IDIzLjM1MyAxNTUuMDQxIDUxLjg5NnMxNTMuNCA1MS40MzMgMTUzLjkwMSA1MC44NjhjMS43LTEuOTE4IDcwLjcxNS0yMjYuNjAyIDY5Ljg2NS0yMjcuNDUxLTAuNDY0LTAuNDY0LTcwLjY5LTI0LjUxNC0xNTYuMDU2LTUzLjQ0NC0xMTcuNDMyLTM5Ljc5Ny0xNTUuMzE1LTUzLjE0My0xNTUuNjMzLTU0LjgyNy0wLjIzNS0xLjI0NCA0MC4xNDktNjEuNTk0IDkxLjQ5OS0xMzYuNzM3IDUwLjU1NS03My45ODEgOTEuNzMzLTEzNS4wNjIgOTEuNTA3LTEzNS43MzctMC41MjEtMS41NDktMTg5LjY4MS0xNDAuODg0LTE5MS4yNjMtMTQwLjg4NC0wLjY0MiAwLTI0LjY0MyAzMi43NjUtNTMuMzM1IDcyLjgxeiIgLz4KPC9mb250PjwvZGVmcz48L3N2Zz4=) format("svg"); + font-weight: normal; + font-style: normal; } + + .cion, .cesiumicons, + .ion-social-duniter:before, + .ion-social-diaspora:before, + .ion-office:before, + .ion-library:before { + display: inline-block; + font-family: "Cesiumicons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + text-rendering: auto; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } + + .ion-social-duniter:before { + content: ""; } + + .ion-social-diaspora:before { + content: ""; } + + .ion-office:before { + content: ""; } + + .ion-library:before { + content: ""; } + + @media screen and (max-width: 400px) { + @-ms-viewport { + width: 320px; } + .item .badge { + right: 16px; } } + + @media screen and (max-width: 767px) { + .hidden-xs { + display: none !important; + visibility: hidden !important; } + .badge { + text-overflow: ellipsis !important; + white-space: nowrap; + overflow: hidden !important; + max-width: 300px !important; + display: block !important; } + .badge:empty { + display: none !important; } + .item .badge { + right: 16px; } + .padding-top-xs { + padding-top: 10px; } } + + @media screen and (min-width: 768px) { + .hidden-xs { + display: inherit; + visibility: visible; } + .row.hidden-xs { + display: flex !important; } + .button.hidden-xs { + display: inline-block; } + .item-toggle .toggle { + right: 32px; } } + + @media screen and (max-width: 767px) { + .visible-xs { + display: inherit !important; + visibility: visible !important; } } + + @media screen and (min-width: 768px) { + .visible-xs { + display: none !important; + visibility: hidden !important; } } + + @media screen and (max-width: 767px) { + .padding-xs { + padding: 16px !important; } } + + @media screen and (min-width: 768px) { + .padding-xs { + padding: inherit; } } + + @media screen and (max-width: 767px) { + .no-padding-xs { + padding: 0px !important; } } + + @media screen and (min-width: 768px) { + .no-padding-xs { + padding: inherit; } } + + @media screen and (max-width: 767px) { + .no-margin-xs { + margin: 0px !important; } } + + @media screen and (min-width: 768px) { + .no-margin-xs { + margin: inherit; } } + + @media screen and (max-width: 991px) and (min-width: 768px) { + .hidden-sm, .row-header.hidden-sm { + display: none !important; + visibility: hidden !important; } + .badge { + text-overflow: ellipsis !important; + white-space: nowrap; + overflow: hidden !important; + max-width: 400px !important; + display: block !important; } + .badge:empty { + display: none !important; } } + + @media screen and (min-width: 992px) { + .hidden-sm { + display: inherit; + visibility: visible; } + .row.hidden-sm { + display: flex !important; } + .button.hidden-sm { + display: inline-block; } } + + @media screen and (max-width: 767px) { + .hidden-sm { + display: inherit; + visibility: visible; } } + + @media screen and (max-width: 991px) { + .visible-sm { + display: inherit !important; + visibility: visible !important; } } + + @media screen and (min-width: 992px) { + .visible-sm { + display: none; + visibility: hidden; } } + + @media screen and (max-width: 767px) { + .visible-sm { + display: none; + visibility: hidden; } } + + @media screen and (max-width: 991px) { + body { + cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAEbSURBVDiNndMxK4ZRGMbx3zmRMrwvM2XCQFFik/IJpCw+hJLPgfIhLBY+gEEGJQPFwGZg9TIoBrfhOfSQHl7XeM7/fw3nvk+KCPWklEawgGlMlOMrnOMoIm6/8B8FKaWMFazhGQ94LFwbg+jHDvYi4u2zIKWUsIk5XNfE72ljHKfYiIjI5WIZMzhrkJW7s8IuQ8IwdnGDpwa5nhbGsJqxiNcuZIV9xWJWvXY3cr1kOmMSnX8UdDCZEb+RDYmMS9WMu80gLrNqw1r/KGjhPOMQvaol+Wva6MFhjoh7bGEUuVGrkgu7HRH3H8IBTjCLgQZ5oDAnxfnymRKWsI4X1Zw7NbGFPmxjP4qYfvjOQ5jHlGpHqCZ1geOIuKvz76QSW1T3cwmnAAAAAElFTkSuQmCC), auto; } } + + @media screen and (min-width: 992px) { + body { + cursor: inherit; } } + + @media screen and (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + visibility: hidden !important; } + .badge { + text-overflow: ellipsis !important; + white-space: nowrap; + overflow: hidden !important; + max-width: 400px !important; + display: block !important; } + .badge:empty { + display: none !important; } + /* + see issue # + html{ + -webkit-user-selectuser-select: all !important; + -moz-user-select: all !important; + -ms-user-select: all !important; + user-select: all !important; + }*/ } + + @media screen and (min-width: 1200px) { + .hidden-md { + display: inherit; + visibility: visible; } } + + @media screen and (max-width: 991px) { + .hidden-md { + display: inherit; + visibility: visible; } } + + @media screen and (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: inherit !important; + visibility: visible !important; } } + + @media screen and (min-width: 1200px) { + .visible-md { + display: none; + visibility: hidden; } } + + @media screen and (max-width: 991px) { + .visible-md { + display: none; + visibility: hidden; } } + + @media screen and (min-width: 1200px) { + .hidden-lg { + display: none !important; + visibility: hidden !important; } + .visible-lg { + display: inherit !important; + visibility: visible !important; } + .badge { + text-overflow: ellipsis !important; + white-space: nowrap; + overflow: hidden !important; + max-width: 450px !important; + display: block !important; } + .badge:empty { + display: none !important; } + /*html{ + -webkit-user-select: all !important; + -moz-user-select: all !important; + -ms-user-select: all !important; + user-select: all !important; + }*/ } + + @media screen and (max-width: 1199px) { + .hidden-lg { + display: inherit; + visibility: visible; } } + + @media screen and (max-width: 1199px) { + .visible-lg { + display: none; + visibility: hidden; } } + + @media screen and (max-width: 768px) { + .no-padding-xs { + padding: inherit; } } + + @media screen and (max-width: 767px) { + .no-margin-xs { + margin: 0px !important; } } + + /********** + Notifications view + **********/ + .view-notification .item.unread { + background-color: #ecf0f7 !important; + border-color: #dddfe2 !important; } + + .view-notification ion-item h4 i.icon, .view-notification ion-item h4 i.icon-help, .view-notification ion-item h4 i.icon-alert, .view-notification ion-item h4 #menu .footer i.icon-help, #menu .footer .view-notification ion-item h4 i.icon-help { + font-size: 18px !important; + line-height: 12px !important; + vertical-align: middle !important; } + + /* ============ + Buttons + =============== */ + .bar.bar-header .button.button-clear.button-icon.ion-android-more-vertical, .bar.bar-header .button.button-icon.ion-android-more-vertical.button-text, + .bar.bar-header .button.button-clear.button-icon i.ion-android-more-vertical, + .bar.bar-header .button.button-icon.button-text i.ion-android-more-vertical { + padding-left: 8px; } + + .bar.bar-header .buttons .secondary-buttons > + .button.button-clear.button-icon.ion-android-more-vertical:first-child, .bar.bar-header .buttons .secondary-buttons > + .button.button-icon.ion-android-more-vertical.button-text:first-child { + padding-left: 0px !important; } + + .bar .buttons.pull-right, .bar .popover-helptip .buttons.icon.icon-right, .popover-helptip .bar .buttons.icon.icon-right, .bar .popover-helptip .buttons.icon-right.icon-help, .popover-helptip .bar .buttons.icon-right.icon-help, .bar .popover-helptip .buttons.icon-right.icon-alert, .popover-helptip .bar .buttons.icon-right.icon-alert, .bar .popover-helptip #menu .footer .buttons.icon-right.icon-help, .popover-helptip #menu .footer .bar .buttons.icon-right.icon-help, .bar #menu .footer .popover-helptip .buttons.icon-right.icon-help, #menu .footer .popover-helptip .bar .buttons.icon-right.icon-help, .bar .popover-helptip .buttons.icon.icon-center, .popover-helptip .bar .buttons.icon.icon-center, .bar .popover-helptip .buttons.icon-center.icon-help, .popover-helptip .bar .buttons.icon-center.icon-help, .bar .popover-helptip .buttons.icon-center.icon-alert, .popover-helptip .bar .buttons.icon-center.icon-alert, .bar .popover-helptip #menu .footer .buttons.icon-center.icon-help, .popover-helptip #menu .footer .bar .buttons.icon-center.icon-help, .bar #menu .footer .popover-helptip .buttons.icon-center.icon-help, #menu .footer .popover-helptip .bar .buttons.icon-center.icon-help, .bar .popover-helptip .buttons.icon.icon-bottom-right, .popover-helptip .bar .buttons.icon.icon-bottom-right, .bar .popover-helptip .buttons.icon-bottom-right.icon-help, .popover-helptip .bar .buttons.icon-bottom-right.icon-help, .bar .popover-helptip .buttons.icon-bottom-right.icon-alert, .popover-helptip .bar .buttons.icon-bottom-right.icon-alert, .bar .popover-helptip #menu .footer .buttons.icon-bottom-right.icon-help, .popover-helptip #menu .footer .bar .buttons.icon-bottom-right.icon-help, .bar #menu .footer .popover-helptip .buttons.icon-bottom-right.icon-help, #menu .footer .popover-helptip .bar .buttons.icon-bottom-right.icon-help, .bar .popover-helptip .buttons.icon.icon-bottom-center, .popover-helptip .bar .buttons.icon.icon-bottom-center, .bar .popover-helptip .buttons.icon-bottom-center.icon-help, .popover-helptip .bar .buttons.icon-bottom-center.icon-help, .bar .popover-helptip .buttons.icon-bottom-center.icon-alert, .popover-helptip .bar .buttons.icon-bottom-center.icon-alert, .bar .popover-helptip #menu .footer .buttons.icon-bottom-center.icon-help, .popover-helptip #menu .footer .bar .buttons.icon-bottom-center.icon-help, .bar #menu .footer .popover-helptip .buttons.icon-bottom-center.icon-help, #menu .footer .popover-helptip .bar .buttons.icon-bottom-center.icon-help, .bar .title + .button:last-child, .bar .title + .buttons, .bar > .button + .button:last-child, .bar > .button.pull-right, .popover-helptip .bar > .button.icon.icon-right, .popover-helptip .bar > .button.icon-right.icon-help, .popover-helptip .bar > .button.icon-right.icon-alert, .popover-helptip #menu .footer .bar > .button.icon-right.icon-help, #menu .footer .popover-helptip .bar > .button.icon-right.icon-help, .popover-helptip .bar > .button.icon.icon-center, .popover-helptip .bar > .button.icon-center.icon-help, .popover-helptip .bar > .button.icon-center.icon-alert, .popover-helptip #menu .footer .bar > .button.icon-center.icon-help, #menu .footer .popover-helptip .bar > .button.icon-center.icon-help, .popover-helptip .bar > .button.icon.icon-bottom-right, .popover-helptip .bar > .button.icon-bottom-right.icon-help, .popover-helptip .bar > .button.icon-bottom-right.icon-alert, .popover-helptip #menu .footer .bar > .button.icon-bottom-right.icon-help, #menu .footer .popover-helptip .bar > .button.icon-bottom-right.icon-help, .popover-helptip .bar > .button.icon.icon-bottom-center, .popover-helptip .bar > .button.icon-bottom-center.icon-help, .popover-helptip .bar > .button.icon-bottom-center.icon-alert, .popover-helptip #menu .footer .bar > .button.icon-bottom-center.icon-help, #menu .footer .popover-helptip .bar > .button.icon-bottom-center.icon-help { + top: 0px !important; } + + .bar.bar-header { + padding-right: 5px !important; } + .bar.bar-header .buttons-right span { + margin-left: 0px !important; } + + .bar .title + .buttons.buttons-right { + right: 5px; } + + .button-icon { + border-color: transparent; + box-shadow: none !important; } + + .button-small-padding { + padding: 0 7px !important; } + + .button-text { + color: grey !important; + font-size: 12px; } + + .button-text.button-small { + padding: 5px 2px; + font-size: 12px !important; } + + .button-text-positive { + color: #387ef5 !important; } + + .button-text-stable { + color: #b2b2b2 !important; } + + + .gray, .popover-share .bar-header span, .popover-share .bar-footer .button-close, .popover-helptip .button-close { + color: grey !important; } + .gray b, .popover-share .bar-header span b, .popover-share .bar-footer .button-close b, .popover-helptip .button-close b { + color: grey !important; } + + .gray a, .popover-share .bar-header span a, .popover-share .bar-footer .button-close a, .popover-helptip .button-close a, .positive a, .icon-help a { + color: inherit; } + + .gray a:hover, .popover-share .bar-header span a:hover, .popover-share .bar-footer .button-close a:hover, .popover-helptip .button-close a:hover, .positive a:hover, .icon-help a:hover { + color: inherit; } + + .gray a:visited, .popover-share .bar-header span a:visited, .popover-share .bar-footer .button-close a:visited, .popover-helptip .button-close a:visited, .positive a:visited, .icon-help a:visited { + color: inherit; } + + .item a { + text-decoration: none; } + + .no-padding { + padding: 0px !important; } + + .avatar-member { + background-image: url(data:image/png;base64,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); } + + .avatar.disable { + opacity: 0.7; } + + .avatar-wallet { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAQAAABpN6lAAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfgBA0JMBOJU4OdAAAB2klEQVR42u3au0ocUQCH8e+IxFRKUohrkG0Eu4BiLrCFDxDBNtjoI1gYTJnGQrRInc4HyBuopNHgBVZIwCJFsHBXLURtQiIyKYyFN3B3zJyd3e/X7e7MmXP+e26zOyBJkiRJkiRJkiRJkiRJkppVSF9E0sk0r+jKuOYnrLMQTqMHkHSzQTHS17fLy3CYroi21JWYj9Z8KDIfvwdUKAC7bGfc+CH6gGrojTyJJBemMr/u+4sLpy2njRZnAAZgAK2t/YHKGUzeZlzz5w2yFU6/EKVsQHAIGIABGIABGIABRN4ILbOVcc1fM9IQCfp7gHOAARiAAbgMXpuhH/GJ0brK/sG78OVfKR0cXPnsQ/iYkwAYY6LOM4eZpXR5q3/t77bH+RkCO5HObZQeEL4nQ7ypcwh8boIAIJQpuwoYQMsugwBJ/73L/h1+3vr+OYtXXn/Lzz7gCV8ZqOH4LUrhz4155IzJvA6B0VqaDwzHu7f/PwEsc1zT8RXWmmoOCJWkl9L95wBWbw6AvO8DfrHkMmgABmAABtDw0j8gUaWHeA9K7odC7GVwhXGgGOmB2ZX4PaDAJs8i9d89XoRq5AAgecoMg3Rm3PhTysyFIyRJkiRJkiRJkiRJkiRJku7wFyuiadmIs5Q9AAAAAElFTkSuQmCC); } + + .item.item-icon-left > i.avatar:first-child { + position: absolute; + display: flex; + height: 100%; + align-items: center; + font-size: 16px; + left: 16px; + top: 8px; + max-height: 32px; + max-width: 32px; } + + .item.item-checkbox.item-avatar > i.avatar:first-child, + .item.item-checkbox.item-avatar > i.item-image:first-child, + .item.item-checkbox.item-avatar .item-content > i.avatar:first-child, + .item.item-checkbox.item-avatar .item-content > i.item-image:first-child, + .item.item-checkbox.item-avatar * > i.avatar:first-child, + .item.item-checkbox.item-avatar * > i.item-image:first-child, + .item.item-checkbox.item-avatar * .item-content > i.avatar:first-child, + .item.item-checkbox.item-avatar * .item-content > i.item-image:first-child { + left: 65px; } + + .item.item-checkbox.item-avatar .item-content, + .item.item-checkbox .item-content .item-avatar { + padding-left: 65px; } + + .card .card-header, + .card .card-header { + font-size: 90%; + opacity: 0.8; + filter: alpha(opacity=80); } + + .card.stable-900-bg, + .card .stable-900-bg, + .item.stable-900-bg, + .item .stable-900-bg, + .item-complex .item-content .stable-900-bg, + .item-radio .item-content .stable-900-bg { + background-color: #e0e0e0 !important; } + + .card .item { + background: inherit; } + + .card.stable-bg, + .card .stable-bg, + .item.stable-bg, + .item .stable-bg, + .item-complex .item-content .stable-bg, + .item-radio .item-content .stable-bg { + background-color: #f8f8f8 !important; } + + .card .card-header { + padding-top: 5px !important; + padding-bottom: 0px !important; + min-height: 25px; } + + .card .item .card-footer { + margin-bottom: 5px; } + + .card .card-avatar .avatar, + .card.card-avatar .avatar { + box-shadow: 0px 3px 4px 0 rgba(0, 0, 0, 0.26); + top: 7px; + background-color: #D9D9D9; } + + .card .card-avatar img.avatar, + .card.card-avatar img.avatar { + border: 0; + min-height: 54px; + min-width: 54px; } + + .card .card-avatar .item.item-avatar, + .card.card-avatar .item.item-avatar { + padding-top: 10px; + padding-bottom: 2px; + min-height: 45px !important; } + + .card .card-avatar .card-footer, + .card.card-avatar .card-footer { + padding-left: 88px; } + .card .card-avatar .card-footer .pull-right a, .card .card-avatar .card-footer .popover-helptip .icon.icon-right a, .popover-helptip .card .card-avatar .card-footer .icon.icon-right a, .card .card-avatar .card-footer .popover-helptip .icon-right.icon-help a, .popover-helptip .card .card-avatar .card-footer .icon-right.icon-help a, .card .card-avatar .card-footer .popover-helptip .icon-right.icon-alert a, .popover-helptip .card .card-avatar .card-footer .icon-right.icon-alert a, .card .card-avatar .card-footer .popover-helptip #menu .footer .icon-right.icon-help a, .popover-helptip #menu .footer .card .card-avatar .card-footer .icon-right.icon-help a, .card .card-avatar .card-footer #menu .footer .popover-helptip .icon-right.icon-help a, #menu .footer .popover-helptip .card .card-avatar .card-footer .icon-right.icon-help a, .card .card-avatar .card-footer .popover-helptip .icon.icon-center a, .popover-helptip .card .card-avatar .card-footer .icon.icon-center a, .card .card-avatar .card-footer .popover-helptip .icon-center.icon-help a, .popover-helptip .card .card-avatar .card-footer .icon-center.icon-help a, .card .card-avatar .card-footer .popover-helptip .icon-center.icon-alert a, .popover-helptip .card .card-avatar .card-footer .icon-center.icon-alert a, .card .card-avatar .card-footer .popover-helptip #menu .footer .icon-center.icon-help a, .popover-helptip #menu .footer .card .card-avatar .card-footer .icon-center.icon-help a, .card .card-avatar .card-footer #menu .footer .popover-helptip .icon-center.icon-help a, #menu .footer .popover-helptip .card .card-avatar .card-footer .icon-center.icon-help a, .card .card-avatar .card-footer .popover-helptip .icon.icon-bottom-right a, .popover-helptip .card .card-avatar .card-footer .icon.icon-bottom-right a, .card .card-avatar .card-footer .popover-helptip .icon-bottom-right.icon-help a, .popover-helptip .card .card-avatar .card-footer .icon-bottom-right.icon-help a, .card .card-avatar .card-footer .popover-helptip .icon-bottom-right.icon-alert a, .popover-helptip .card .card-avatar .card-footer .icon-bottom-right.icon-alert a, .card .card-avatar .card-footer .popover-helptip #menu .footer .icon-bottom-right.icon-help a, .popover-helptip #menu .footer .card .card-avatar .card-footer .icon-bottom-right.icon-help a, .card .card-avatar .card-footer #menu .footer .popover-helptip .icon-bottom-right.icon-help a, #menu .footer .popover-helptip .card .card-avatar .card-footer .icon-bottom-right.icon-help a, .card .card-avatar .card-footer .popover-helptip .icon.icon-bottom-center a, .popover-helptip .card .card-avatar .card-footer .icon.icon-bottom-center a, .card .card-avatar .card-footer .popover-helptip .icon-bottom-center.icon-help a, .popover-helptip .card .card-avatar .card-footer .icon-bottom-center.icon-help a, .card .card-avatar .card-footer .popover-helptip .icon-bottom-center.icon-alert a, .popover-helptip .card .card-avatar .card-footer .icon-bottom-center.icon-alert a, .card .card-avatar .card-footer .popover-helptip #menu .footer .icon-bottom-center.icon-help a, .popover-helptip #menu .footer .card .card-avatar .card-footer .icon-bottom-center.icon-help a, .card .card-avatar .card-footer #menu .footer .popover-helptip .icon-bottom-center.icon-help a, #menu .footer .popover-helptip .card .card-avatar .card-footer .icon-bottom-center.icon-help a, + .card.card-avatar .card-footer .pull-right a, + .card.card-avatar .card-footer .popover-helptip .icon.icon-right a, .popover-helptip + .card.card-avatar .card-footer .icon.icon-right a, + .card.card-avatar .card-footer .popover-helptip .icon-right.icon-help a, .popover-helptip + .card.card-avatar .card-footer .icon-right.icon-help a, + .card.card-avatar .card-footer .popover-helptip .icon-right.icon-alert a, .popover-helptip + .card.card-avatar .card-footer .icon-right.icon-alert a, + .card.card-avatar .card-footer .popover-helptip #menu .footer .icon-right.icon-help a, .popover-helptip #menu .footer + .card.card-avatar .card-footer .icon-right.icon-help a, + .card.card-avatar .card-footer #menu .footer .popover-helptip .icon-right.icon-help a, #menu .footer .popover-helptip + .card.card-avatar .card-footer .icon-right.icon-help a, + .card.card-avatar .card-footer .popover-helptip .icon.icon-center a, .popover-helptip + .card.card-avatar .card-footer .icon.icon-center a, + .card.card-avatar .card-footer .popover-helptip .icon-center.icon-help a, .popover-helptip + .card.card-avatar .card-footer .icon-center.icon-help a, + .card.card-avatar .card-footer .popover-helptip .icon-center.icon-alert a, .popover-helptip + .card.card-avatar .card-footer .icon-center.icon-alert a, + .card.card-avatar .card-footer .popover-helptip #menu .footer .icon-center.icon-help a, .popover-helptip #menu .footer + .card.card-avatar .card-footer .icon-center.icon-help a, + .card.card-avatar .card-footer #menu .footer .popover-helptip .icon-center.icon-help a, #menu .footer .popover-helptip + .card.card-avatar .card-footer .icon-center.icon-help a, + .card.card-avatar .card-footer .popover-helptip .icon.icon-bottom-right a, .popover-helptip + .card.card-avatar .card-footer .icon.icon-bottom-right a, + .card.card-avatar .card-footer .popover-helptip .icon-bottom-right.icon-help a, .popover-helptip + .card.card-avatar .card-footer .icon-bottom-right.icon-help a, + .card.card-avatar .card-footer .popover-helptip .icon-bottom-right.icon-alert a, .popover-helptip + .card.card-avatar .card-footer .icon-bottom-right.icon-alert a, + .card.card-avatar .card-footer .popover-helptip #menu .footer .icon-bottom-right.icon-help a, .popover-helptip #menu .footer + .card.card-avatar .card-footer .icon-bottom-right.icon-help a, + .card.card-avatar .card-footer #menu .footer .popover-helptip .icon-bottom-right.icon-help a, #menu .footer .popover-helptip + .card.card-avatar .card-footer .icon-bottom-right.icon-help a, + .card.card-avatar .card-footer .popover-helptip .icon.icon-bottom-center a, .popover-helptip + .card.card-avatar .card-footer .icon.icon-bottom-center a, + .card.card-avatar .card-footer .popover-helptip .icon-bottom-center.icon-help a, .popover-helptip + .card.card-avatar .card-footer .icon-bottom-center.icon-help a, + .card.card-avatar .card-footer .popover-helptip .icon-bottom-center.icon-alert a, .popover-helptip + .card.card-avatar .card-footer .icon-bottom-center.icon-alert a, + .card.card-avatar .card-footer .popover-helptip #menu .footer .icon-bottom-center.icon-help a, .popover-helptip #menu .footer + .card.card-avatar .card-footer .icon-bottom-center.icon-help a, + .card.card-avatar .card-footer #menu .footer .popover-helptip .icon-bottom-center.icon-help a, #menu .footer .popover-helptip + .card.card-avatar .card-footer .icon-bottom-center.icon-help a { + margin-right: 8px; } + + a.underline:focus, + .underline a:focus, + .a.underline:active, + .underline a:active, + a.underline:hover, + .underline a:hover { + outline: 1px !important; + text-decoration: underline !important; } + + .card-avatar-small.card, + .card-avatar-small .card, + .card-avatar-small .card.card-avatar, + .card-avatar-small .card .card-avatar { + min-height: 45px; } + .card-avatar-small.card .avatar, + .card-avatar-small.card .item-avatar .avatar, + .card-avatar-small .card .avatar, + .card-avatar-small .card .item-avatar .avatar, + .card-avatar-small .card.card-avatar .avatar, + .card-avatar-small .card.card-avatar .item-avatar .avatar, + .card-avatar-small .card .card-avatar .avatar, + .card-avatar-small .card .card-avatar .item-avatar .avatar { + box-shadow: 0px 2px 2px 0 rgba(0, 0, 0, 0.26); + height: 30px !important; + width: 30px !important; + left: 5px !important; } + .card-avatar-small.card .item.item-avatar, + .card-avatar-small .card .item.item-avatar, + .card-avatar-small .card.card-avatar .item.item-avatar, + .card-avatar-small .card .card-avatar .item.item-avatar { + min-height: 25px !important; + padding-left: 42px !important; } + .card-avatar-small.card .card-footer, + .card-avatar-small .card .card-footer, + .card-avatar-small .card.card-avatar .card-footer, + .card-avatar-small .card .card-avatar .card-footer { + padding-top: 0px; + padding-left: 42px !important; } + + .list .item.text-left { + text-align: left !important; } + + .list .item.text-center, .list .item.large-button-bar { + text-align: center !important; } + + .list .item.text-right { + text-align: right !important; } + + .list .item-divider.item-divider-top-border { + border-top: solid 1px rgba(0, 0, 0, 0.12); } + + /********** + Item > Avatar + **********/ + .item-avatar { + min-height: 80px !important; } + + .item-avatar > i:first-child, + .item-avatar > img:first-child, + .item-avatar i.item-image:first-child, + .item-avatar img.item-image:first-child, + .item-avatar .item-content > i:first-child, + .item-avatar .item-content > img:first-child, + .item-avatar .item-content i.item-image:first-child, + .item-avatar .item-content img.item-image:first-child, + .item-avatar-left > i:first-child, + .item-avatar-left > img:first-child, + .item-avatar-left i.item-image:first-child, + .item-avatar-left img.item-image:first-child, + .item-avatar-left .item-content > i:first-child, + .item-avatar-left .item-content > img:first-child, + .item-avatar-left .item-content i.item-image:first-child, + .item-avatar-left .item-content img.item-image:first-child { + color: #D9D9D9; + background-color: #f8f8f8; + border: solid 1px #D9D9D9; + overflow: hidden !important; + font-size: 45px !important; + /*padding-left: 0px; + padding-top: 0px; + text-align: center; + vertical-align: middle;*/ + line-height: 56px; + width: 100% !important; + /*display: block !important;*/ + max-height: 56px !important; + max-width: 56px !important; + top: 12px !important; } + + .item-avatar > .icon:first-child:before, .item-avatar > .icon-help:first-child:before, .item-avatar > .icon-alert:first-child:before, #menu .footer .item-avatar > .icon-help:first-child:before, + .item-avatar .icon.item-image:first-child:before, + .item-avatar .item-image.icon-help:first-child:before, + .item-avatar .item-image.icon-alert:first-child:before, + .item-avatar #menu .footer .item-image.icon-help:first-child:before, #menu .footer + .item-avatar .item-image.icon-help:first-child:before, + .item-avatar .item-content > .icon:first-child:before, + .item-avatar .item-content > .icon-help:first-child:before, + .item-avatar .item-content > .icon-alert:first-child:before, + .item-avatar #menu .footer .item-content > .icon-help:first-child:before, #menu .footer + .item-avatar .item-content > .icon-help:first-child:before, + .item-avatar.item-icon-right .icon:first-child:before, + .item-avatar.item-icon-right .icon-help:first-child:before, + .item-avatar.item-icon-right .icon-alert:first-child:before, + .item-avatar.item-icon-right #menu .footer .icon-help:first-child:before, #menu .footer + .item-avatar.item-icon-right .icon-help:first-child:before, + .item-avatar.item-icon-right .icon-help:first-child:before, + .item-avatar.item-icon-right .icon-alert:first-child:before, + .item-avatar.item-icon-right #menu .footer .icon-help:first-child:before, + #menu .footer .item-avatar.item-icon-right .icon-help:first-child:before { + width: 56px !important; } + + .item-avatar.item-icon-right .icon:last-child, .item-avatar.item-icon-right .icon-help:last-child, .item-avatar.item-icon-right .icon-alert:last-child, .item-avatar.item-icon-right #menu .footer .icon-help:last-child, #menu .footer .item-avatar.item-icon-right .icon-help:last-child, + .item-avatar.item-icon-right .icon-help:last-child, + .item-avatar.item-icon-right .icon-alert:last-child, + .item-avatar.item-icon-right #menu .footer .icon-help:last-child, + #menu .footer .item-avatar.item-icon-right .icon-help:last-child { + left: auto; } + + /********** + Item > Other + **********/ + .item em { + font-weight: bold !important; } + + @media screen and (min-width: 992px) { + .list .item.item-border-large { + border-bottom: solid 1px #ccc !important; } + .list.item-border-large .item { + border-bottom: solid 1px #ccc !important; + margin: 0px; } + .list.item-border-large .item-divider { + border-top: 0; } } + + .list .item.item-border { + border-bottom: solid 1px #ccc !important; } + + .list .item.item-small-height { + padding-top: 2px; + padding-bottom: 0px; + min-height: 24px; } + .list .item.item-small-height .badge { + padding-top: 0px !important; + top: inherit; } + .list .item.item-small-height .badge.badge-balanced, + .list .item.item-small-height .badge.badge-positive, + .list .item.item-small-height .badge.badge-assertive, + .list .item.item-small-height .badge.badge-editable:hover, + .list .item.item-small-height .badge.badge-royal, + .list .item.item-small-height .badge.badge-calm, + .list .item.item-small-height .badge.badge-energized { + top: 1px !important; + padding-top: 3px !important; + padding-bottom: 2px !important; } + + /* + * Badge + */ + .item.item-icon-right .badge, + .item.item-button-right .badge { + right: 43px; } + + .badge-editable:hover { + cursor: pointer; } + + .badge-editable:hover:before { + content: " "; } + + .badge-button { + position: absolute !important; + margin: 0 !important; + padding: 0px 4px !important; + font-size: 10px; + top: 5px !important; + right: 3px !important; } + + /********** + Item buttons + **********/ + .item-button-right > .button, + .item-button-right .item-content > .button, + .item-button-right > .buttons, + .item-button-right .item-content > .buttons { + top: 16px; } + + .item-button-right > .button.button-small, + .item-button-right .item-content > .button.button-small, + .item-button-right > .buttons .button-small, + .item-button-right .item-content > .buttons .button-small { + font-size: 14px; } + + .item.large-button-bar { + margin-bottom: 10px; } + + /********** + Item avatar + **********/ + .item-avatar-left-padding { + padding-left: 95px; } + + /********** + Item thumbnail + **********/ + .item-thumbnail-left-padding { + padding-left: 106px; } + + .item.item-thumbnail-left, .item-thumbnail-left { + min-height: 100px !important; } + + .item-thumbnail-left > i:first-child, + .item-thumbnail-left i.item-image, + .item-thumbnail-left .item-content > i:first-child, + .item-thumbnail-left .item-content i.item-image { + color: #D9D9D9; + background-color: #f8f8f8; + overflow: hidden !important; + font-size: 50px !important; + line-height: 80px; + padding: 0 15px; + background-position: center; + background-size: cover; + display: inline-block; } + + @media screen and (max-width: 400px) { + .card > .item.item-thumbnail-left, + .item-thumbnail-left, + .item-thumbnail-left .item-content { + padding-left: 84px !important; } + .item-thumbnail-left > img:first-child, + .item-thumbnail-left img.item-image, + .item-thumbnail-left .item-content > img:first-child, + .item-thumbnail-left .item-content img.item-image { + max-width: 70px; + max-height: 70px; } + .item h2 { + font-size: 13px !important; } } + + /********** + Item icons + **********/ + .item-icon-left-padding { + padding-left: 40px; } + + .item-icon-right-padding { + padding-right: 40px; } + + .text-keep-lines { + white-space: pre-line !important; } + + .text-italic { + font-style: italic !important; } + + /********** + Help + **********/ + .icon-help { + font-size: 38px; + vertical-align: middle; } + + .icon-alert { + font-size: 38px; + vertical-align: middle; } + + .bar-header .button-icon .avatar { + height: 35px; + width: 35px; + position: relative; + left: 0px; + top: 4px; + border: solid 1px #D9D9D9; } + + .bar-header .button-icon .avatar.active { + background-color: #e0e0e0; } + + .bar-header .button-icon .avatar { + height: 31px; + width: 31px; + position: relative; + left: 0px; + top: 6px; } + + .badge.badge-secondary, + .badge .badge-secondary { + font-size: 12px; + font-style: italic; + top: 37px !important; + font-weight: normal !important; + margin-right: 0px; + padding-right: 0px; } + + .ion-es-user-api:before { + content: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMzBweCIgaGVpZ2h0PSIzMHB4IiB2aWV3Qm94PSIwIDAgNTAwIDUwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpieD0iaHR0cHM6Ly9ib3h5LXN2Zy5jb20iPgogIDxwYXRoIGQ9Ik0gMzkwLjk5MiAxMjIuMjc2IEMgNDE4LjIwOSAxNTcuMTgzIDQzNC45MjQgMjAwLjI3OCA0NDEuMjAyIDI0OC4yNCBDIDQ0MS4xODcgMjc2LjcxMSA0MzUuNzEgMzA1LjI5MiA0MjUuMzA4IDMzMy4yODIgQyAzNzEuMTAxIDQxNi43MjcgMjc0Ljk1MSA0NDkuMjEzIDE2Ny42NjkgNDM0LjI3OSBDIDEzNi40MDYgNDE2LjAzNiAxMDkuMDA5IDM5MC4wNzYgODYuMjcyIDM1OC4wMTYgQyA2Ny43NzggMzIzLjc5NCA1Ny45NDIgMjg0LjQgNTYuNDg5IDI0Mi4wNjIgQyA2Mi4yMDYgMTk5Ljc2NiA3OS42MTcgMTYxLjkxMiAxMDYuMzAxIDEyOS42MTcgQyAxNjIuNTI0IDg1LjQzOSAyMzkuMDMgNzAuMTgxIDMyMS45NjggODIuNTIgQyAzNDUuNTA4IDkyLjUzNSAzNjguNjU3IDEwNS44ODMgMzkwLjk5MiAxMjIuMjc2IFoiIHN0eWxlPSJmaWxsOiByZ2IoMjU1LCAyNTUsIDI1NSk7IiBieDpvcmlnaW49IjAgMCIvPgogIDxnIHRyYW5zZm9ybT0ibWF0cml4KDAuNTE3ODQ4LCAwLCAwLCAwLjUxNzg0OCwgLTUzLjMwNjYyNSwgLTU5OS45MzEyMTMpIiBzdHlsZT0ib3BhY2l0eTogMTsiPgogICAgPGcgaWQ9ImctMTQiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IG9wYWNpdHk6IDAuNTsiIHRyYW5zZm9ybT0ibWF0cml4KDEsIDAsIDAsIDEsIDE0NC41NzA3MjQsIDEwMDcuMDk5NDI2KSI+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOiNmZmQwODY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjFweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiBkPSJNIDU4NS4xNjk5Miw1MjQuOTEyMTEgQyA0NDcuNDE3NDUsNzM4Ljg0MDE1IDI4NS45MzA5Myw3OTcuNjgxNDIgOTMuMzQ3NjU2LDgwMS4wMzcxMSAxNTguNjY0NTIsOTIxLjg0MDgzIDI4Ny4yMDAzOCwxMDAzLjE2OTggNDM0LjAzOTA2LDEwMDEuMjU1OSA2MDcuNTY4NTEsOTk4Ljk5NDQ2IDc1Mi41MTMxNyw4ODEuMTg0ODggNzk2LjY1MjM0LDcyMS45NjY4IGMgLTIuNjg2NCwtNi41Nzc2NCAtNi4yMDEwNiwtMTMuNjIwMzcgLTEwLjgxNjQsLTIxLjEzNDc3IEMgNzY4LjY4OTg3LDY3Ny4wMzg3OCA3MDkuMTA0NzgsNTY4LjQ3NzIxIDU4NS4xNjk5Miw1MjQuOTEyMTEgWiIgaWQ9InBhdGgtMTAyIi8+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOiMyNzBiMGI7ZmlsbC1vcGFjaXR5OjAuOTkzOTM5Mzk7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjFweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiBkPSJNIDU4Ni4yNTQgNTI0LjExNSBDIDU2NC42ODIgNjUwLjQ1MyA0NzcuOTc0IDc1NC40NzIgNDk4LjU4NCA4MzUuNjAyIEMgNTI0LjY0OCA5MzguMTk5IDQxOS40NTggOTYxLjUxNSAzMzMuOTczIDk4OS4zNDIgQyAzNjUuOTIzIDk5Ny41NDUgMzk5LjQ3NSAxMDAxLjcwNiA0MzQuMDM5IDEwMDEuMjU2IEMgNjM0LjA1MiA5OTguNjQ5IDc5Ni4wOTMgODQyLjUzNiA4MDkuNTYxIDY0Ni40MzkgQyA3OTMuMTk3IDY0MS43NzcgNzc3LjQyNSA2MzQuNjg5IDc2Ni43MjMgNjIyLjc0NiBDIDczNC4wMzUgNTg2LjI3MiA2NTAuMTE3IDU0Ni41NjQgNTg2LjI1NCA1MjQuMTE1IFoiIGlkPSJwYXRoLTEwMyIgYng6b3JpZ2luPSIwLjUgMC41Ii8+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IHJnYigyMDMsIDEzNywgMyk7IGZpbGwtb3BhY2l0eTogMC45OTM5Mzk7IGZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1saW5lam9pbjogbWl0ZXI7IHN0cm9rZS1vcGFjaXR5OiAxOyIgZD0iTSA1ODYuMjU0IDUyNC4xMTUgQyA1NjQuNjgyIDY1MC40NTMgNDc3Ljk3NCA3NTQuNDcyIDQ5OC41ODQgODM1LjYwMiBDIDUyNC42NDggOTM4LjE5OSA0MTkuNDU4IDk2MS41MTUgMzMzLjk3MyA5ODkuMzQyIEMgMzY1LjkyMyA5OTcuNTQ1IDM5OS40NzUgMTAwMS43MDYgNDM0LjAzOSAxMDAxLjI1NiBDIDYzNC4wNTIgOTk4LjY0OSA3OTYuMDkzIDg0Mi41MzYgODA5LjU2MSA2NDYuNDM5IEMgNzkzLjE5NyA2NDEuNzc3IDc3Ny40MjUgNjM0LjY4OSA3NjYuNzIzIDYyMi43NDYgQyA3MzQuMDM1IDU4Ni4yNzIgNjUwLjExNyA1NDYuNTY0IDU4Ni4yNTQgNTI0LjExNSBaIiBpZD0icGF0aC0xMDQiIGJ4Om9yaWdpbj0iMC41IDAuNSIvPgogICAgPC9nPgogICAgPGcgaWQ9ImctMTUiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IG9wYWNpdHk6IDAuNTsiIHRyYW5zZm9ybT0ibWF0cml4KDEsIDAsIDAsIDEsIDE0NC41NzA3MjQsIDEwMDcuMDk5NDI2KSI+CiAgICAgIDxyZWN0IHg9IjUwNC4yNjUiIHk9IjUwMC4yODciIHdpZHRoPSIyMy40OTIiIGhlaWdodD0iMjUuNTI3IiBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6I2ZhYmIzNztmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzQuOTAwMDAxNTM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eTowLjk5NjA3ODQzIiBpZD0icGF0aC0xMDUiLz4KICAgICAgPHJlY3QgeD0iMzY5LjE3NCIgeT0iNDE1LjQyOSIgd2lkdGg9IjIyLjM4NCIgaGVpZ2h0PSIyNC40MTkiIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojZmZkMDg2O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozNC45MDAwMDE1MztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjAuOTk2MDc4NDMiIGlkPSJwYXRoLTEwNiIvPgogICAgICA8cmVjdCB4PSI0MTguOTk1IiB5PSI0MzMuMDE5IiB3aWR0aD0iMzAuNTI0IiBoZWlnaHQ9IjMwLjUyNCIgc3R5bGU9ImRpc3BsYXk6aW5saW5lO29wYWNpdHk6MTtmaWxsOiNmYWJiMzc7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM0LjkwMDAwMTUzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MC45OTYwNzg0MyIgaWQ9InBhdGgtMTA3Ii8+CiAgICAgIDxyZWN0IHg9IjQxNy4zNCIgeT0iNjUyLjU1NiIgd2lkdGg9IjQ2LjgwMyIgaGVpZ2h0PSI0Ni44MDMiIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojZmJjMTRjO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozNC45MDAwMDE1MztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjAuOTk2MDc4NDMiIGlkPSJwYXRoLTEwOCIvPgogICAgICA8cmVjdCB4PSI0MjIuNTg2IiB5PSI0NzUuODkxIiB3aWR0aD0iMzAuNTI0IiBoZWlnaHQ9IjMwLjUyNCIgc3R5bGU9ImRpc3BsYXk6aW5saW5lO29wYWNpdHk6MTtmaWxsOiNmYWJiMzc7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM0LjkwMDAwMTUzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MC45OTYwNzg0MyIgaWQ9InBhdGgtMTA5Ii8+CiAgICAgIDxyZWN0IHg9IjQ3Mi42MTgiIHk9IjYwNS40NTciIHdpZHRoPSIyNC40MTkiIGhlaWdodD0iMjYuNDU0IiBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6I2NjODkwMjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzQuOTAwMDAxNTM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eTowLjk5NjA3ODQzIiBpZD0icGF0aC0xMTAiLz4KICAgICAgPHJlY3QgeD0iNTIwLjc3MiIgeT0iNTU3LjkwMiIgd2lkdGg9IjE4LjMxNCIgaGVpZ2h0PSIxOC4zMTQiIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojZmFiYjM3O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozNC45MDAwMDE1MztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjAuOTk2MDc4NDMiIGlkPSJwYXRoLTExMSIvPgogICAgICA8cmVjdCB4PSI0NTQuNzg0IiB5PSI1NjMuMDI4IiB3aWR0aD0iMzAuNTI0IiBoZWlnaHQ9IjMwLjUyNCIgc3R5bGU9ImRpc3BsYXk6aW5saW5lO29wYWNpdHk6MTtmaWxsOiNmYWJiMzc7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM0LjkwMDAwMTUzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MC45OTYwNzg0MyIgaWQ9InBhdGgtMTEyIi8+CiAgICAgIDxyZWN0IHg9IjMzNS4zNDIiIHk9IjcyMC45ODciIHdpZHRoPSIzOC42NjMiIGhlaWdodD0iNDAuNjk4IiBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6I2ZiYzE0YztmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzQuOTAwMDAxNTM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eTowLjk5NjA3ODQzIiBpZD0icGF0aC0xMTMiLz4KICAgICAgPHJlY3QgeD0iMzcxLjk3IiB5PSI2NjEuOTc1IiB3aWR0aD0iMjYuNDU0IiBoZWlnaHQ9IjMwLjUyNCIgc3R5bGU9ImRpc3BsYXk6aW5saW5lO29wYWNpdHk6MTtmaWxsOiNmYmMxNGM7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM0LjkwMDAwMTUzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MC45OTYwNzg0MyIgaWQ9InBhdGgtMTE0Ii8+CiAgICAgIDxyZWN0IHg9Ii00MjcuOTMiIHk9IjYxMC4wODUiIHdpZHRoPSIyNC41MDciIGhlaWdodD0iMjQuNDE5IiBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6I2NjODkwMjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzQuOTAwMDAxNTM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eTowLjk5NjA3ODQzIiBpZD0icGF0aC0xMTUiIHRyYW5zZm9ybT0ic2NhbGUoLTEsMSkiLz4KICAgICAgPHJlY3QgeD0iNDgwLjQxMSIgeT0iNTIzLjQ2OSIgd2lkdGg9IjIwLjM0OSIgaGVpZ2h0PSIyMi4zODQiIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojZmZkMDg2O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozNC45MDAwMDE1MztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjAuOTk2MDc4NDMiIGlkPSJwYXRoLTExNiIvPgogICAgICA8cmVjdCB4PSItNDk5LjUiIHk9IjQ2Ni4zMTQiIHdpZHRoPSIyNC41MDciIGhlaWdodD0iMjQuNDE5IiBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6I2NjODkwMjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzQuOTAwMDAxNTM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eTowLjk5NjA3ODQzIiBpZD0icGF0aC0xMTciIHRyYW5zZm9ybT0ic2NhbGUoLTEsMSkiLz4KICAgIDwvZz4KICAgIDxnIGlkPSJnLTE2IiBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBvcGFjaXR5OiAxOyIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMDAwNzAwMDIwNDk1LCAwLCAwLCAxLjAwMDAwMDA3MDAwMjA0OTUsIDE0NC41NzA3MjM5MTA3OTYxMiwgMTAwNy4wOTk0Mzk4NzE1OTk0KSI+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IG5vbmU7IGZpbGwtb3BhY2l0eTogMTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IHJnYigyNTUsIDEyMiwgMCk7IHN0cm9rZS13aWR0aDogMi4zNDg4ODsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1saW5lam9pbjogbWl0ZXI7IHN0cm9rZS1vcGFjaXR5OiAxOyIgZD0iTSA1ODUuMTY5OTIsNTI0LjkxMjExIEMgNDQ3LjQxNzQ1LDczOC44NDAxNSAyODUuOTMwOTMsNzk3LjY4MTQyIDkzLjM0NzY1Niw4MDEuMDM3MTEgMTU4LjY2NDUyLDkyMS44NDA4MyAyODcuMjAwMzgsMTAwMy4xNjk4IDQzNC4wMzkwNiwxMDAxLjI1NTkgNjA3LjU2ODUxLDk5OC45OTQ0NiA3NTIuNTEzMTcsODgxLjE4NDg4IDc5Ni42NTIzNCw3MjEuOTY2OCBjIC0yLjY4NjQsLTYuNTc3NjQgLTYuMjAxMDYsLTEzLjYyMDM3IC0xMC44MTY0LC0yMS4xMzQ3NyBDIDc2OC42ODk4Nyw2NzcuMDM4NzggNzA5LjEwNDc4LDU2OC40NzcyMSA1ODUuMTY5OTIsNTI0LjkxMjExIFoiIGlkPSJwYXRoLTExOCIvPgogICAgICA8cGF0aCBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBmaWxsOiBub25lOyBmaWxsLW9wYWNpdHk6IDAuOTkzOTM5OyBmaWxsLXJ1bGU6IGV2ZW5vZGQ7IHN0cm9rZTogcmdiKDI1NSwgMTIyLCAwKTsgc3Ryb2tlLXdpZHRoOiAyLjM0ODg4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IiBkPSJNIDU4Ni4yNTQgNTI0LjExNSBDIDU2NC42ODIgNjUwLjQ1MyA0NzcuOTc0IDc1NC40NzIgNDk4LjU4NCA4MzUuNjAyIEMgNTI0LjY0OCA5MzguMTk5IDQxOS40NTggOTYxLjUxNSAzMzMuOTczIDk4OS4zNDIgQyAzNjUuOTIzIDk5Ny41NDUgMzk5LjQ3NSAxMDAxLjcwNiA0MzQuMDM5IDEwMDEuMjU2IEMgNjM0LjA1MiA5OTguNjQ5IDc5Ni4wOTMgODQyLjUzNiA4MDkuNTYxIDY0Ni40MzkgQyA3OTMuMTk3IDY0MS43NzcgNzc3LjQyNSA2MzQuNjg5IDc2Ni43MjMgNjIyLjc0NiBDIDczNC4wMzUgNTg2LjI3MiA2NTAuMTE3IDU0Ni41NjQgNTg2LjI1NCA1MjQuMTE1IFoiIGlkPSJwYXRoLTExOSIgYng6b3JpZ2luPSIwLjUgMC41Ii8+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IG5vbmU7IGZpbGwtb3BhY2l0eTogMC45OTM5Mzk7IGZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiByZ2IoMjU1LCAxMjIsIDApOyBzdHJva2Utd2lkdGg6IDIuMzQ4ODg7IHN0cm9rZS1saW5lY2FwOiBidXR0OyBzdHJva2UtbGluZWpvaW46IG1pdGVyOyBzdHJva2Utb3BhY2l0eTogMTsiIGQ9Ik0gNTg2LjI1NCA1MjQuMTE1IEMgNTY0LjY4MiA2NTAuNDUzIDQ3Ny45NzQgNzU0LjQ3MiA0OTguNTg0IDgzNS42MDIgQyA1MjQuNjQ4IDkzOC4xOTkgNDE5LjQ1OCA5NjEuNTE1IDMzMy45NzMgOTg5LjM0MiBDIDM2NS45MjMgOTk3LjU0NSAzOTkuNDc1IDEwMDEuNzA2IDQzNC4wMzkgMTAwMS4yNTYgQyA2MzQuMDUyIDk5OC42NDkgNzk2LjA5MyA4NDIuNTM2IDgwOS41NjEgNjQ2LjQzOSBDIDc5My4xOTcgNjQxLjc3NyA3NzcuNDI1IDYzNC42ODkgNzY2LjcyMyA2MjIuNzQ2IEMgNzM0LjAzNSA1ODYuMjcyIDY1MC4xMTcgNTQ2LjU2NCA1ODYuMjU0IDUyNC4xMTUgWiIgaWQ9InBhdGgtMTIwIiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgIDwvZz4KICA8L2c+CiAgPGcgdHJhbnNmb3JtPSJtYXRyaXgoMC42MDgyNjEsIDAsIDAsIDAuNjA4MjYxLCAtMjAuMDg0OTc2LCAzLjI1NTczNikiPgogICAgPGc+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IHJnYig2NCwgMTc4LCAyNTUpOyBmaWxsLW9wYWNpdHk6IDE7IGZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1saW5lam9pbjogbWl0ZXI7IHN0cm9rZS1vcGFjaXR5OiAxOyBvcGFjaXR5OiAwLjc4OyIgaWQ9InBhdGgtMTAiIGQ9Ik0gNDE5LjEzMyA4NS43MzggQyA0MTcuMjk1IDg1LjczOSA0MTUuNDU1IDg1Ljc1NCA0MTMuNjExIDg1Ljc3OCBDIDM1NC44NTIgODYuNTYxIDI5OS4wMjMgOTkuMTc0IDI0OC4zNTggMTIxLjMyIEMgNTg0LjEyMSAxMy4yMDYgNzk2LjE3NSAyMTEuMjYgODMxLjcgNTA4Ljc3MyBMIDg0Ni4zODMgNTA3LjEyNCBDIDgxNS41ODYgMjM1LjgwMSA2NTIuNDc3IDg1LjU4OCA0MTkuMTMzIDg1LjczOCBaIiB0cmFuc2Zvcm09Im1hdHJpeCgwLjk2MzczLCAwLjI2Njg3OCwgLTAuMjY2ODc4LCAwLjk2MzczLCA4OS41MDUyMzEsIC0xMzYuNjE1MDYxKSIgYng6b3JpZ2luPSIwLjUgMC41Ii8+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IHJnYig2NCwgMTc4LCAyNTUpOyBmaWxsLW9wYWNpdHk6IDE7IGZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1saW5lam9pbjogbWl0ZXI7IHN0cm9rZS1vcGFjaXR5OiAxOyBvcGFjaXR5OiAxOyIgaWQ9InBhdGgtMyIgZD0iTSAxNDYuMDM3IDE5NC4wNjUgQyAxNDQuMjAxIDE5NC4wNjYgMTQyLjM2MSAxOTQuMDgxIDE0MC41MTcgMTk0LjEwNCBDIDgxLjc2IDE5NC44ODggMjUuOTMxIDIwNy41MDMgLTI0LjczNiAyMjkuNjQ4IEMgMzExLjAyOSAxMjEuNTMxIDUyMy4wODMgMzE5LjU4MyA1NTguNjA0IDYxNy4wOTMgTCA1NzMuMjg0IDYxNS40NDMgQyA1NDIuNDkgMzQ0LjEyMiAzNzkuMzg1IDE5My45MTMgMTQ2LjAzNyAxOTQuMDY1IFoiIHRyYW5zZm9ybT0ibWF0cml4KC0wLjE4MDk4OCwgLTAuOTgzNDg1LCAwLjk4MzQ4NSwgLTAuMTgwOTg4LCAtMzkuMjk4NTgxLCA3MDUuODk3NTQ0KSIgYng6b3JpZ2luPSIwLjUgMC41Ii8+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IHJnYig2NCwgMTc4LCAyNTUpOyBmaWxsLW9wYWNpdHk6IDE7IGZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1saW5lam9pbjogbWl0ZXI7IHN0cm9rZS1vcGFjaXR5OiAxOyBvcGFjaXR5OiAwLjQ7IiBpZD0icGF0aC0xMSIgZD0iTSA0ODcuNzQ0IDE5My4wODQgQyA0ODUuOTA2IDE5My4wODUgNDg0LjA2NyAxOTMuMSA0ODIuMjIzIDE5My4xMjMgQyA0MjMuNDY0IDE5My45MDcgMzY3LjYzNSAyMDYuNTIgMzE2Ljk3NSAyMjguNjY4IEMgNjUyLjcyNiAxMjAuNTUyIDg2NC43NzUgMzE4LjYwNSA5MDAuMjk5IDYxNi4xMDkgTCA5MTQuOTc5IDYxNC40NiBDIDg4NC4xODQgMzQzLjE0NCA3MjEuMDgxIDE5Mi45MzUgNDg3Ljc0NCAxOTMuMDg0IFoiIHRyYW5zZm9ybT0ibWF0cml4KDAuNjE5OTk3LCAwLjc4NDYwNSwgLTAuNzg0NjA1LCAwLjYxOTk5NywgNTIzLjA2NzIzMSwgLTM0My4zMzE1MzkpIiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogcmdiKDY0LCAxNzgsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IG9wYWNpdHk6IDAuODQ7IiBpZD0icGF0aC0xMiIgZD0iTSAyOTUuOTY5IDQzMi43NTcgQyAyOTQuMTMxIDQzMi43NTggMjkyLjI5MyA0MzIuNzczIDI5MC40NDkgNDMyLjc5NyBDIDIzMS42ODggNDMzLjU4IDE3NS44NiA0NDYuMTk0IDEyNS4xOTggNDY4LjM0MSBDIDQ2MC45NTcgMzYwLjIyNiA2NzMuMDA1IDU1OC4yOCA3MDguNTI2IDg1NS43ODYgTCA3MjMuMjA3IDg1NC4xMzkgQyA2OTIuNDEyIDU4Mi44MTkgNTI5LjMxIDQzMi42MDkgMjk1Ljk2OSA0MzIuNzU3IFoiIHRyYW5zZm9ybT0ibWF0cml4KC0wLjk3ODg0OSwgMC4yMDQ1ODQsIC0wLjIwNDU4NCwgLTAuOTc4ODQ5LCA5NjMuODIwNzk2LCAxMTE2LjM2NzI5MykiIGJ4Om9yaWdpbj0iMC41IDAuNSIvPgogICAgICA8cGF0aCBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBmaWxsOiByZ2IoNjQsIDE3OCwgMjU1KTsgZmlsbC1vcGFjaXR5OiAxOyBmaWxsLXJ1bGU6IGV2ZW5vZGQ7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAxcHg7IHN0cm9rZS1saW5lY2FwOiBidXR0OyBzdHJva2UtbGluZWpvaW46IG1pdGVyOyBzdHJva2Utb3BhY2l0eTogMTsgb3BhY2l0eTogMC40OyIgaWQ9InBhdGgtMTMiIGQ9Ik0gMTU4LjAzNiAxNDguODMgQyAxNTYuMiAxNDguODMzIDE1NC4zNiAxNDguODQ2IDE1Mi41MTYgMTQ4Ljg3MiBDIDkzLjc1OSAxNDkuNjUzIDM3LjkzIDE2Mi4yNjcgLTEyLjczNCAxODQuNDExIEMgMzIzLjAyMiA3Ni4zMDEgNTM1LjA3NiAyNzQuMzUyIDU3MC42MDQgNTcxLjg1NyBMIDU4NS4yODYgNTcwLjIwOCBDIDU1NC40ODMgMjk4Ljg5MSAzOTEuMzggMTQ4LjY4MyAxNTguMDM2IDE0OC44MyBaIiB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzODYxNCwgLTAuOTQwOTI2LCAwLjk0MDkyNiwgMC4zMzg2MTQsIC0xMTUuNTk1MTU4LCA0ODMuNzA1OTg0KSIgYng6b3JpZ2luPSIwLjUgMC41Ii8+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IHJnYig2NCwgMTc4LCAyNTUpOyBmaWxsLW9wYWNpdHk6IDE7IGZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1saW5lam9pbjogbWl0ZXI7IHN0cm9rZS1vcGFjaXR5OiAxOyBvcGFjaXR5OiAxOyIgaWQ9InBhdGgtMTQiIGQ9Ik0gNTAxLjAxOSAyODguMjkyIEMgNDk5LjE4MSAyODguMjkzIDQ5Ny4zNCAyODguMzA4IDQ5NS40OTYgMjg4LjMzMSBDIDQzNi43MzYgMjg5LjExNSAzODAuOTA4IDMwMS43MjYgMzMwLjI0MyAzMjMuODc0IEMgNjY2LjAwNCAyMTUuNzU3IDg3OC4wNjIgNDEzLjgxMiA5MTMuNTg2IDcxMS4zMjIgTCA5MjguMjY4IDcwOS42NzMgQyA4OTcuNDY4IDQzOC4zNTIgNzM0LjM2MSAyODguMTQxIDUwMS4wMTkgMjg4LjI5MiBaIiB0cmFuc2Zvcm09Im1hdHJpeCgwLjE2NDY1NiwgMC45ODYzNTEsIC0wLjk4NjM1MSwgMC4xNjQ2NTYsIDk4Mi44NTcyNjYsIC0yMzMuNDUyMDYzKSIgYng6b3JpZ2luPSIwLjUgMC41Ii8+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IHJnYig2NCwgMTc4LCAyNTUpOyBmaWxsLW9wYWNpdHk6IDE7IGZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1saW5lam9pbjogbWl0ZXI7IHN0cm9rZS1vcGFjaXR5OiAxOyBvcGFjaXR5OiAwLjQ7IiBpZD0icGF0aC0xNSIgZD0iTSAxOTIuOTU0IDM3Ni41MjEgQyAxOTEuMTE1IDM3Ni41MjIgMTg5LjI3NyAzNzYuNTM3IDE4Ny40MzMgMzc2LjU2MSBDIDEyOC42NzQgMzc3LjM0NCA3Mi44NDUgMzg5Ljk1OCAyMi4xODEgNDEyLjEwMyBDIDM1Ny45NCAzMDMuOTg5IDU2OS45ODcgNTAyLjA0NSA2MDUuNTA1IDc5OS41NTMgTCA2MjAuMTg4IDc5Ny45MDUgQyA1ODkuMzkyIDUyNi41ODQgNDI2LjI5NSAzNzYuMzY5IDE5Mi45NTQgMzc2LjUyMSBaIiB0cmFuc2Zvcm09Im1hdHJpeCgtMC45MzE0MDQsIC0wLjM2Mzk4OCwgMC4zNjM5ODgsIC0wLjkzMTQwNCwgNDE5LjQ5OTAwNiwgMTE4Mi41OTk4MDkpIiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogcmdiKDY0LCAxNzgsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IG9wYWNpdHk6IDE7IiBpZD0icGF0aC0xNiIgZD0iTSAyMjEuNjE0IDYzLjk3MyBDIDIxOS43NzcgNjMuOTc2IDIxNy45MzggNjMuOTkgMjE2LjA5NCA2NC4wMTUgQyAxNTcuMzM0IDY0Ljc5NSAxMDEuNTA2IDc3LjQwOSA1MC44NDEgOTkuNTU0IEMgMzg2LjU5OCAtOC41NTkgNTk4LjY1MSAxODkuNDk3IDYzNC4xNzMgNDg3LjAwMSBMIDY0OC44NTQgNDg1LjM1NCBDIDYxOC4wNTggMjE0LjAzNyA0NTQuOTU0IDYzLjgyNCAyMjEuNjE0IDYzLjk3MyBaIiB0cmFuc2Zvcm09Im1hdHJpeCgwLjc1MDQ1MiwgLTAuNjYwOTI1LCAwLjY2MDkyNSwgMC43NTA0NTIsIC03MC44MDMzMjIsIDI5MC45MjAyNzMpIiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogcmdiKDY0LCAxNzgsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IG9wYWNpdHk6IDAuNDsiIGlkPSJwYXRoLTE3IiBkPSJNIDQ0MS44ODggMzQyLjA5OCBDIDQ0MC4wNDcgMzQyLjA5OCA0MzguMjA3IDM0Mi4xMTQgNDM2LjM2MiAzNDIuMTM4IEMgMzc3LjYwMSAzNDIuOTIyIDMyMS43NjUgMzU1LjUzNSAyNzEuMTAzIDM3Ny42ODEgQyA2MDYuODg2IDI2OS41NjcgODE4Ljk0NCA0NjcuNjE1IDg1NC40NjIgNzY1LjEzMyBMIDg2OS4xNDIgNzYzLjQ4MyBDIDgzOC4zNTQgNDkyLjE1NCA2NzUuMjQyIDM0MS45NDggNDQxLjg4OCAzNDIuMDk4IFoiIHRyYW5zZm9ybT0ibWF0cml4KC0wLjM1NjU4MiwgMC45MzQyNjQsIC0wLjkzNDI2NCwgLTAuMzU2NTgyLCAxMjU2Ljc1OTQ5MywgMTY5LjE4MjU1MikiIGJ4Om9yaWdpbj0iMC41IDAuNSIvPgogICAgICA8ZyB0cmFuc2Zvcm09Im1hdHJpeCgwLjc2MjQ5MywgMCwgMCwgMC43NjI0OTMsIDE5LjI5NDY0NywgLTcxNi4zMjI4MTUpIj4KICAgICAgICA8cGF0aCBkPSJNIDU2Ni40NjYgMTA4OS4xMzcgTCA1NjYuNDY2IDExNDguMjIyIEMgNTY1Ljg2NyAxMTQ4LjIxOSA1NjUuMjY3IDExNDguMjE3IDU2NC42NjcgMTE0OC4yMTcgQyA1NjEuNDgxIDExNDguMjE3IDU1OC4zMSAxMTQ4LjI1OSA1NTUuMTU0IDExNDguMzQxIEwgNTU1LjE1NCAxMDg5LjEzNyBaIE0gOTA4LjI5IDE0NzcuMTQ2IEwgOTU2Ljk4NyAxNDc3LjE0NiBMIDk1Ni45ODcgMTQ4OC40NTggTCA5MDguNTY5IDE0ODguNDU4IEMgOTA4LjUzOSAxNDg0LjY5MyA5MDguNDQ3IDE0ODAuOTIyIDkwOC4yOSAxNDc3LjE0NiBaIE0gNTY2LjQ2NiAxODM1LjAxMyBMIDU2Ni40NjYgMTg3Ni40NjcgTCA1NTUuMTU0IDE4NzYuNDY3IEwgNTU1LjE1NCAxODM0Ljg4NiBDIDU1OC4zMTggMTgzNC45NzMgNTYxLjQ5IDE4MzUuMDE3IDU2NC42NjcgMTgzNS4wMTcgQyA1NjUuMjY3IDE4MzUuMDE3IDU2NS44NjcgMTgzNS4wMTYgNTY2LjQ2NiAxODM1LjAxMyBaIE0gMjIwLjc3NSAxNDg4LjQ1OCBMIDE2OS42NTcgMTQ4OC40NTggTCAxNjkuNjU3IDE0NzcuMTQ2IEwgMjIxLjA4OSAxNDc3LjE0NiBDIDIyMC45MjEgMTQ4MC45MDkgMjIwLjgxNiAxNDg0LjY4IDIyMC43NzUgMTQ4OC40NTggWiIgc3R5bGU9ImZpbGw6IHJnYig2NCwgNDAsIDApOyBzdHJva2U6IHJnYig2NCwgNDAsIDApOyBzdHJva2Utd2lkdGg6IDEwLjc4MDY7IiBieDpvcmlnaW49IjAgMCIvPgogICAgICAgIDxwYXRoIGQ9Ik0gNzYwLjEyMSAxMTQzLjMxMSBMIDcxNy4zMzYgMTIxNy40MTcgQyA3MTUuNzIgMTIxNi41MTggNzE0LjA5NiAxMjE1LjYzMiA3MTIuNDY1IDEyMTQuNzYxIEwgNzU1LjMxOCAxMTQwLjUzNyBaIE0gODMwLjEyMiAxMzI0LjIwMyBMIDkwMC40MjQgMTI4My42MTQgTCA5MDMuMTk4IDEyODguNDE3IEwgODMzLjA0IDEzMjguOTIzIEMgODMyLjA4IDEzMjcuMzM5IDgzMS4xMDcgMTMyNS43NjYgODMwLjEyMiAxMzI0LjIwMyBaIE0gODQwLjU5OSAxNjQxLjEzNyBMIDkwMy4xOTcgMTY3Ny4yNzggTCA5MDAuNDI0IDE2ODIuMDgyIEwgODM3LjkxMSAxNjQ1Ljk5IEMgODM4LjgyMSAxNjQ0LjM4IDgzOS43MTcgMTY0Mi43NjIgODQwLjU5OSAxNjQxLjEzNyBaIE0gNzI1LjE2OCAxNzYxLjg0MyBMIDc2MC4xMjIgMTgyMi4zODUgTCA3NTUuMzE4IDE4MjUuMTU4IEwgNzIwLjM3OSAxNzY0LjY0MSBDIDcyMS45ODUgMTc2My43MjIgNzIzLjU4MiAxNzYyLjc4OSA3MjUuMTY4IDE3NjEuODQzIFogTSA0MDMuNTM4IDE3NjAuOTMyIEwgMzY2LjQ1NiAxODI1LjE1OSBMIDM2MS42NTMgMTgyMi4zODYgTCAzOTguODAyIDE3NTguMDQyIEMgNDAwLjM3MiAxNzU5LjAxOSA0MDEuOTUxIDE3NTkuOTgyIDQwMy41MzggMTc2MC45MzIgWiBNIDI4OS41OCAxNjQyLjY4OSBMIDIyMS4zNSAxNjgyLjA4MiBMIDIxOC41NzcgMTY3Ny4yNzkgTCAyODYuOTQ0IDE2MzcuODA3IEMgMjg3LjgwNyAxNjM5LjQzNyAyODguNjg1IDE2NDEuMDY1IDI4OS41OCAxNjQyLjY4OSBaIE0gMjk0LjM1NCAxMzMyLjE2OCBMIDIxOC41NzYgMTI4OC40MTcgTCAyMjEuMzUgMTI4My42MTQgTCAyOTcuMjEzIDEzMjcuNDE0IEMgMjk2LjI0NiAxMzI4Ljk5IDI5NS4yOTMgMTMzMC41NzUgMjk0LjM1NCAxMzMyLjE2OCBaIE0gNDA2LjA3OSAxMjIwLjI1OSBMIDM2MS42NTMgMTE0My4zMTEgTCAzNjYuNDU3IDExNDAuNTM3IEwgNDEwLjg4OSAxMjE3LjQ5NSBDIDQwOS4yNzYgMTIxOC40MDMgNDA3LjY3MyAxMjE5LjMyNCA0MDYuMDc5IDEyMjAuMjU5IFoiIHN0eWxlPSJmaWxsOiByZ2IoNjQsIDQwLCAwKTsgc3Ryb2tlOiByZ2IoNjQsIDQwLCAwKTsgc3Ryb2tlLXdpZHRoOiAxMC43ODA2OyIgYng6b3JpZ2luPSIwIDAiLz4KICAgICAgPC9nPgogICAgPC9nPgogICAgPHJlY3QgeD0iNDI5LjM2NyIgeT0iNDI1Ljk3OSIgd2lkdGg9IjIwLjAwMyIgaGVpZ2h0PSIyMS43MzUiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IG9wYWNpdHk6IDE7IGZpbGw6IHJnYig4MCwgMTUwLCAyMDApOyBmaWxsLW9wYWNpdHk6IDE7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAzNC45OyBzdHJva2UtbWl0ZXJsaW1pdDogNDsgc3Ryb2tlLWRhc2hhcnJheTogbm9uZTsgc3Ryb2tlLWRhc2hvZmZzZXQ6IDA7IHN0cm9rZS1vcGFjaXR5OiAwLjk5NjA3ODsiIGlkPSJwYXRoLTkxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLCAwLCAwLCAwLjk5OTk5OSwgLTMwMS4zNzcwNzUsIC0yMTkuNDk4NDM0KSIvPgogICAgPHJlY3QgeD0iNDQ2Ljg1MyIgeT0iMjUuNDYyIiB3aWR0aD0iMjUuOTkiIGhlaWdodD0iMjUuOTkiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IG9wYWNpdHk6IDE7IGZpbGw6IHJnYig4MCwgMTUwLCAyMDApOyBmaWxsLW9wYWNpdHk6IDE7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAzNC45OyBzdHJva2UtbWl0ZXJsaW1pdDogNDsgc3Ryb2tlLWRhc2hhcnJheTogbm9uZTsgc3Ryb2tlLWRhc2hvZmZzZXQ6IDA7IHN0cm9rZS1vcGFjaXR5OiAwLjk5NjA3ODsiIGlkPSJwYXRoLTkzIi8+CiAgICA8cmVjdCB4PSItMTM1Ljk1NiIgeT0iNjA1LjE0MSIgd2lkdGg9IjM5Ljg1MSIgaGVpZ2h0PSIzOS44NTEiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IG9wYWNpdHk6IDE7IGZpbGw6IHJnYig4MCwgMTUwLCAyMDApOyBmaWxsLW9wYWNpdHk6IDE7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAzNC45OyBzdHJva2UtbWl0ZXJsaW1pdDogNDsgc3Ryb2tlLWRhc2hhcnJheTogbm9uZTsgc3Ryb2tlLWRhc2hvZmZzZXQ6IDA7IHN0cm9rZS1vcGFjaXR5OiAwLjk5NjA3ODsiIGlkPSJwYXRoLTk0IiB0cmFuc2Zvcm09Im1hdHJpeCgwLjk5OTk5OSwgMCwgMCwgMSwgODQ2LjE3Njc1NiwgLTM5NC45NTYwMjQpIi8+CiAgICA8cmVjdCB4PSIyMjUuNzc5IiB5PSI2ODkuODM2IiB3aWR0aD0iMjUuOTkiIGhlaWdodD0iMjUuOTkiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IG9wYWNpdHk6IDE7IGZpbGw6IHJnYig4MCwgMTUwLCAyMDApOyBmaWxsLW9wYWNpdHk6IDE7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAzNC45OyBzdHJva2UtbWl0ZXJsaW1pdDogNDsgc3Ryb2tlLWRhc2hhcnJheTogbm9uZTsgc3Ryb2tlLWRhc2hvZmZzZXQ6IDA7IHN0cm9rZS1vcGFjaXR5OiAwLjk5NjA3ODsiIGlkPSJwYXRoLTk1Ii8+CiAgICA8cmVjdCB4PSI1OTQuMDEzIiB5PSI3MzcuMTQyIiB3aWR0aD0iMjAuNzkyIiBoZWlnaHQ9IjIyLjUyNSIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMTsgZmlsbDogcmdiKDgwLCAxNTAsIDIwMCk7IGZpbGwtb3BhY2l0eTogMTsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDM0Ljk7IHN0cm9rZS1taXRlcmxpbWl0OiA0OyBzdHJva2UtZGFzaGFycmF5OiBub25lOyBzdHJva2UtZGFzaG9mZnNldDogMDsgc3Ryb2tlLW9wYWNpdHk6IDAuOTk2MDc4OyIgaWQ9InBhdGgtOTYiLz4KICAgIDxyZWN0IHg9IjM4Ny4yMzUiIHk9IjQ3OS4zOTciIHdpZHRoPSIyNS45OSIgaGVpZ2h0PSIyNS45OSIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMTsgZmlsbDogcmdiKDgwLCAxNTAsIDIwMCk7IGZpbGwtb3BhY2l0eTogMTsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDM0Ljk7IHN0cm9rZS1taXRlcmxpbWl0OiA0OyBzdHJva2UtZGFzaGFycmF5OiBub25lOyBzdHJva2UtZGFzaG9mZnNldDogMDsgc3Ryb2tlLW9wYWNpdHk6IDAuOTk2MDc4OyIgaWQ9InBhdGgtOTgiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDAwMDAxLCAwLCAwLCAwLjk5OTk5OSwgMzY1LjI3NDk2NiwgNzkuMjk1MjQxKSIvPgogICAgPHJlY3QgeD0iNDIxLjk2MiIgeT0iNzc1LjkzNyIgd2lkdGg9IjMyLjkyIiBoZWlnaHQ9IjM0LjY1MyIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMTsgZmlsbDogcmdiKDgwLCAxNTAsIDIwMCk7IGZpbGwtb3BhY2l0eTogMTsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDM0Ljk7IHN0cm9rZS1taXRlcmxpbWl0OiA0OyBzdHJva2UtZGFzaGFycmF5OiBub25lOyBzdHJva2UtZGFzaG9mZnNldDogMDsgc3Ryb2tlLW9wYWNpdHk6IDAuOTk2MDc4OyIgaWQ9InBhdGgtOTkiLz4KICAgIDxyZWN0IHg9Ii02Ni45MzkiIHk9Ii01NjguOTc4IiB3aWR0aD0iMjAuODY3IiBoZWlnaHQ9IjIwLjc5MiIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMTsgZmlsbDogcmdiKDgwLCAxNTAsIDIwMCk7IGZpbGwtb3BhY2l0eTogMTsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDM0Ljk7IHN0cm9rZS1taXRlcmxpbWl0OiA0OyBzdHJva2UtZGFzaGFycmF5OiBub25lOyBzdHJva2UtZGFzaG9mZnNldDogMDsgc3Ryb2tlLW9wYWNpdHk6IDAuOTk2MDc4OyIgaWQ9InBhdGgtMTAxIiB0cmFuc2Zvcm09Im1hdHJpeCgtMSwgMCwgMCwgMC45OTk5OTcsIDMxLjM1NjkyOCwgOTg0LjczNjMwNikiLz4KICA8L2c+CiAgPHBhdGggZD0iTSAyMTMuOTAzIDE4Ni43NzIgQyAxOTUuODU2IDE4Ni43NzIgMTgxLjYxIDE5Mi43ODIgMTcxLjE2MyAyMDQuODAyIEMgMTYwLjcyMyAyMTYuODE1IDE1NS41MDMgMjMzLjI2OSAxNTUuNTAzIDI1NC4xNjIgQyAxNTUuNTAzIDI3NS42NDkgMTYwLjUzNiAyOTIuMjQ5IDE3MC42MDMgMzAzLjk2MiBDIDE4MC42NzYgMzE1LjY4MiAxOTUuMDMzIDMyMS41NDIgMjEzLjY3MyAzMjEuNTQyIEMgMjI1LjEyNiAzMjEuNTQyIDIzOC4xOTMgMzE5LjQ4MiAyNTIuODczIDMxNS4zNjIgTCAyNTIuODczIDMzMi4wOTIgQyAyNDEuNDkzIDMzNi4zNjUgMjI3LjQ1MyAzMzguNTAyIDIxMC43NTMgMzM4LjUwMiBDIDE4Ni41NzMgMzM4LjUwMiAxNjcuOTEzIDMzMS4xNjIgMTU0Ljc3MyAzMTYuNDgyIEMgMTQxLjYzMyAzMDEuODA5IDEzNS4wNjMgMjgwLjk1OSAxMzUuMDYzIDI1My45MzIgQyAxMzUuMDYzIDIzNy4wMTIgMTM4LjIyNiAyMjIuMTg5IDE0NC41NTMgMjA5LjQ2MiBDIDE1MC44OCAxOTYuNzM1IDE2MC4wMTMgMTg2LjkyNSAxNzEuOTUzIDE4MC4wMzIgQyAxODMuODkzIDE3My4xNDUgMTk3Ljk1IDE2OS43MDIgMjE0LjEyMyAxNjkuNzAyIEMgMjMxLjM0MyAxNjkuNzAyIDI0Ni4zOTMgMTcyLjg0OSAyNTkuMjczIDE3OS4xNDIgTCAyNTEuMTgzIDE5NS41MzIgQyAyMzguNzU2IDE4OS42OTIgMjI2LjMzIDE4Ni43NzIgMjEzLjkwMyAxODYuNzcyIFogTSAzNjUuMTU2IDMwMi42NzIgQyAzNjUuMTU2IDMxNC4xMjUgMzYwLjg4NiAzMjIuOTU5IDM1Mi4zNDYgMzI5LjE3MiBDIDM0My44MTIgMzM1LjM5MiAzMzEuODMyIDMzOC41MDIgMzE2LjQwNiAzMzguNTAyIEMgMzAwLjA4NiAzMzguNTAyIDI4Ny4zNTkgMzM1LjkxOSAyNzguMjI2IDMzMC43NTIgTCAyNzguMjI2IDMxMy40NTIgQyAyODQuMTM5IDMxNi40NDUgMjkwLjQ4NiAzMTguODA1IDI5Ny4yNjYgMzIwLjUzMiBDIDMwNC4wMzkgMzIyLjI1MiAzMTAuNTY5IDMyMy4xMTIgMzE2Ljg1NiAzMjMuMTEyIEMgMzI2LjU4OSAzMjMuMTEyIDMzNC4wNzYgMzIxLjU1OSAzMzkuMzE2IDMxOC40NTIgQyAzNDQuNTYyIDMxNS4zNDUgMzQ3LjE4NiAzMTAuNjA5IDM0Ny4xODYgMzA0LjI0MiBDIDM0Ny4xODYgMjk5LjQ1NSAzNDUuMTA2IDI5NS4zNTkgMzQwLjk0NiAyOTEuOTUyIEMgMzM2Ljc5MiAyODguNTQ1IDMyOC42ODkgMjg0LjUxOSAzMTYuNjM2IDI3OS44NzIgQyAzMDUuMTgyIDI3NS42MDUgMjk3LjAzOSAyNzEuODgyIDI5Mi4yMDYgMjY4LjcwMiBDIDI4Ny4zNzkgMjY1LjUyMiAyODMuNzg2IDI2MS45MDkgMjgxLjQyNiAyNTcuODYyIEMgMjc5LjA2NiAyNTMuODIyIDI3Ny44ODYgMjQ4Ljk5MiAyNzcuODg2IDI0My4zNzIgQyAyNzcuODg2IDIzMy4zNDUgMjgxLjk2OSAyMjUuNDI5IDI5MC4xMzYgMjE5LjYyMiBDIDI5OC4yOTYgMjEzLjgyMiAzMDkuNDg2IDIxMC45MjIgMzIzLjcwNiAyMTAuOTIyIEMgMzM2Ljk1OSAyMTAuOTIyIDM0OS45MTIgMjEzLjYxNSAzNjIuNTY2IDIxOS4wMDIgTCAzNTUuOTQ2IDIzNC4xNzIgQyAzNDMuNTkyIDIyOS4wNzkgMzMyLjM5OSAyMjYuNTMyIDMyMi4zNjYgMjI2LjUzMiBDIDMxMy41MzIgMjI2LjUzMiAzMDYuODY5IDIyNy45MTUgMzAyLjM3NiAyMzAuNjgyIEMgMjk3Ljg4MiAyMzMuNDU1IDI5NS42MzYgMjM3LjI3NSAyOTUuNjM2IDI0Mi4xNDIgQyAyOTUuNjM2IDI0NS40MzUgMjk2LjQ3OSAyNDguMjQyIDI5OC4xNjYgMjUwLjU2MiBDIDI5OS44NDYgMjUyLjg4MiAzMDIuNTU5IDI1NS4wOTIgMzA2LjMwNiAyNTcuMTkyIEMgMzEwLjA0NiAyNTkuMjg1IDMxNy4yMzIgMjYyLjMxNSAzMjcuODY2IDI2Ni4yODIgQyAzNDIuNDY2IDI3MS42MDIgMzUyLjMyOSAyNzYuOTU1IDM1Ny40NTYgMjgyLjM0MiBDIDM2Mi41ODkgMjg3LjczNSAzNjUuMTU2IDI5NC41MTIgMzY1LjE1NiAzMDIuNjcyIFoiIHN0eWxlPSJmaWxsOiByZ2IoNjQsIDQwLCAwKTsiIGJ4Om9yaWdpbj0iMC41IDAuNSIvPgo8L3N2Zz4K); } + + .row-header { + border-bottom: solid 1px #ccc !important; + margin: 0px; + min-height: 28px !important; } + + .col-header { + text-align: center; + display: block !important; } + + .col-15 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 15%; + -moz-box-flex: 0; + -moz-flex: 0 0 15%; + -ms-flex: 0 0 15%; + flex: 0 0 15%; + max-width: 15%; } + + .col-border-left { + border-left: solid 1px #ccc !important; } + + .col-border-right { + border-right: solid 1px #ccc !important; } + + .text-no-transform { + text-transform: inherit; } + +>> \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/resources/templates/css_logo.st b/duniter4j-es-subscription/src/main/resources/templates/css_logo.st new file mode 100644 index 00000000..8a554e95 --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/templates/css_logo.st @@ -0,0 +1,22 @@ +css_logo() ::= << + @media screen and (max-width: 767px) { + .logo { + height: 96px; + background-image: url(data:image/png;base64,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); + background-size: 96px 96px; } + } + + @media screen and (min-width: 768px) and (max-width: 991px) { + .logo { + height: 144px; + background-image: url(data:image/png;base64,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); + background-size: 144px 144px; } + } + + @media screen and (min-width: 992px) { + .logo { + height: 200px; + background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iNTEycHgiIGhlaWdodD0iNTEycHgiIHZpZXdCb3g9IjAgMCA1MDAgNTAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOmJ4PSJodHRwczovL2JveHktc3ZnLmNvbSI+CiAgPHBhdGggZD0iTSAzOTAuOTkyIDEyMi4yNzYgQyA0MTguMjA5IDE1Ny4xODMgNDM0LjkyNCAyMDAuMjc4IDQ0MS4yMDIgMjQ4LjI0IEMgNDQxLjE4NyAyNzYuNzExIDQzNS43MSAzMDUuMjkyIDQyNS4zMDggMzMzLjI4MiBDIDM3MS4xMDEgNDE2LjcyNyAyNzQuOTUxIDQ0OS4yMTMgMTY3LjY2OSA0MzQuMjc5IEMgMTM2LjQwNiA0MTYuMDM2IDEwOS4wMDkgMzkwLjA3NiA4Ni4yNzIgMzU4LjAxNiBDIDY3Ljc3OCAzMjMuNzk0IDU3Ljk0MiAyODQuNCA1Ni40ODkgMjQyLjA2MiBDIDYyLjIwNiAxOTkuNzY2IDc5LjYxNyAxNjEuOTEyIDEwNi4zMDEgMTI5LjYxNyBDIDE2Mi41MjQgODUuNDM5IDIzOS4wMyA3MC4xODEgMzIxLjk2OCA4Mi41MiBDIDM0NS41MDggOTIuNTM1IDM2OC42NTcgMTA1Ljg4MyAzOTAuOTkyIDEyMi4yNzYgWiIgc3R5bGU9ImZpbGw6IHJnYigyNTUsIDI1NSwgMjU1KTsiIGJ4Om9yaWdpbj0iMCAwIi8+CiAgPGcgdHJhbnNmb3JtPSJtYXRyaXgoMC41MTc4NDgsIDAsIDAsIDAuNTE3ODQ4LCAtNTMuMzA2NjI1LCAtNTk5LjkzMTIxMykiIHN0eWxlPSJvcGFjaXR5OiAxOyI+CiAgICA8ZyBpZD0iZy0xNCIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMC41OyIgdHJhbnNmb3JtPSJtYXRyaXgoMSwgMCwgMCwgMSwgMTQ0LjU3MDcyNCwgMTAwNy4wOTk0MjYpIj4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6I2ZmZDA4NjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MXB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiIGQ9Ik0gNTg1LjE2OTkyLDUyNC45MTIxMSBDIDQ0Ny40MTc0NSw3MzguODQwMTUgMjg1LjkzMDkzLDc5Ny42ODE0MiA5My4zNDc2NTYsODAxLjAzNzExIDE1OC42NjQ1Miw5MjEuODQwODMgMjg3LjIwMDM4LDEwMDMuMTY5OCA0MzQuMDM5MDYsMTAwMS4yNTU5IDYwNy41Njg1MSw5OTguOTk0NDYgNzUyLjUxMzE3LDg4MS4xODQ4OCA3OTYuNjUyMzQsNzIxLjk2NjggYyAtMi42ODY0LC02LjU3NzY0IC02LjIwMTA2LC0xMy42MjAzNyAtMTAuODE2NCwtMjEuMTM0NzcgQyA3NjguNjg5ODcsNjc3LjAzODc4IDcwOS4xMDQ3OCw1NjguNDc3MjEgNTg1LjE2OTkyLDUyNC45MTIxMSBaIiBpZD0icGF0aC0xMDIiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6IzI3MGIwYjtmaWxsLW9wYWNpdHk6MC45OTM5MzkzOTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MXB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiIGQ9Ik0gNTg2LjI1NCA1MjQuMTE1IEMgNTY0LjY4MiA2NTAuNDUzIDQ3Ny45NzQgNzU0LjQ3MiA0OTguNTg0IDgzNS42MDIgQyA1MjQuNjQ4IDkzOC4xOTkgNDE5LjQ1OCA5NjEuNTE1IDMzMy45NzMgOTg5LjM0MiBDIDM2NS45MjMgOTk3LjU0NSAzOTkuNDc1IDEwMDEuNzA2IDQzNC4wMzkgMTAwMS4yNTYgQyA2MzQuMDUyIDk5OC42NDkgNzk2LjA5MyA4NDIuNTM2IDgwOS41NjEgNjQ2LjQzOSBDIDc5My4xOTcgNjQxLjc3NyA3NzcuNDI1IDYzNC42ODkgNzY2LjcyMyA2MjIuNzQ2IEMgNzM0LjAzNSA1ODYuMjcyIDY1MC4xMTcgNTQ2LjU2NCA1ODYuMjU0IDUyNC4xMTUgWiIgaWQ9InBhdGgtMTAzIiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogcmdiKDIwMywgMTM3LCAzKTsgZmlsbC1vcGFjaXR5OiAwLjk5MzkzOTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IiBkPSJNIDU4Ni4yNTQgNTI0LjExNSBDIDU2NC42ODIgNjUwLjQ1MyA0NzcuOTc0IDc1NC40NzIgNDk4LjU4NCA4MzUuNjAyIEMgNTI0LjY0OCA5MzguMTk5IDQxOS40NTggOTYxLjUxNSAzMzMuOTczIDk4OS4zNDIgQyAzNjUuOTIzIDk5Ny41NDUgMzk5LjQ3NSAxMDAxLjcwNiA0MzQuMDM5IDEwMDEuMjU2IEMgNjM0LjA1MiA5OTguNjQ5IDc5Ni4wOTMgODQyLjUzNiA4MDkuNTYxIDY0Ni40MzkgQyA3OTMuMTk3IDY0MS43NzcgNzc3LjQyNSA2MzQuNjg5IDc2Ni43MjMgNjIyLjc0NiBDIDczNC4wMzUgNTg2LjI3MiA2NTAuMTE3IDU0Ni41NjQgNTg2LjI1NCA1MjQuMTE1IFoiIGlkPSJwYXRoLTEwNCIgYng6b3JpZ2luPSIwLjUgMC41Ii8+CiAgICA8L2c+CiAgICA8ZyBpZD0iZy0xNSIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMC41OyIgdHJhbnNmb3JtPSJtYXRyaXgoMSwgMCwgMCwgMSwgMTQ0LjU3MDcyNCwgMTAwNy4wOTk0MjYpIj4KICAgICAgPHJlY3QgeD0iNTA0LjI2NSIgeT0iNTAwLjI4NyIgd2lkdGg9IjIzLjQ5MiIgaGVpZ2h0PSIyNS41MjciIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojZmFiYjM3O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozNC45MDAwMDE1MztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjAuOTk2MDc4NDMiIGlkPSJwYXRoLTEwNSIvPgogICAgICA8cmVjdCB4PSIzNjkuMTc0IiB5PSI0MTUuNDI5IiB3aWR0aD0iMjIuMzg0IiBoZWlnaHQ9IjI0LjQxOSIgc3R5bGU9ImRpc3BsYXk6aW5saW5lO29wYWNpdHk6MTtmaWxsOiNmZmQwODY7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM0LjkwMDAwMTUzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MC45OTYwNzg0MyIgaWQ9InBhdGgtMTA2Ii8+CiAgICAgIDxyZWN0IHg9IjQxOC45OTUiIHk9IjQzMy4wMTkiIHdpZHRoPSIzMC41MjQiIGhlaWdodD0iMzAuNTI0IiBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6I2ZhYmIzNztmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzQuOTAwMDAxNTM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eTowLjk5NjA3ODQzIiBpZD0icGF0aC0xMDciLz4KICAgICAgPHJlY3QgeD0iNDE3LjM0IiB5PSI2NTIuNTU2IiB3aWR0aD0iNDYuODAzIiBoZWlnaHQ9IjQ2LjgwMyIgc3R5bGU9ImRpc3BsYXk6aW5saW5lO29wYWNpdHk6MTtmaWxsOiNmYmMxNGM7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM0LjkwMDAwMTUzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MC45OTYwNzg0MyIgaWQ9InBhdGgtMTA4Ii8+CiAgICAgIDxyZWN0IHg9IjQyMi41ODYiIHk9IjQ3NS44OTEiIHdpZHRoPSIzMC41MjQiIGhlaWdodD0iMzAuNTI0IiBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6I2ZhYmIzNztmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzQuOTAwMDAxNTM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eTowLjk5NjA3ODQzIiBpZD0icGF0aC0xMDkiLz4KICAgICAgPHJlY3QgeD0iNDcyLjYxOCIgeT0iNjA1LjQ1NyIgd2lkdGg9IjI0LjQxOSIgaGVpZ2h0PSIyNi40NTQiIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojY2M4OTAyO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozNC45MDAwMDE1MztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjAuOTk2MDc4NDMiIGlkPSJwYXRoLTExMCIvPgogICAgICA8cmVjdCB4PSI1MjAuNzcyIiB5PSI1NTcuOTAyIiB3aWR0aD0iMTguMzE0IiBoZWlnaHQ9IjE4LjMxNCIgc3R5bGU9ImRpc3BsYXk6aW5saW5lO29wYWNpdHk6MTtmaWxsOiNmYWJiMzc7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM0LjkwMDAwMTUzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MC45OTYwNzg0MyIgaWQ9InBhdGgtMTExIi8+CiAgICAgIDxyZWN0IHg9IjQ1NC43ODQiIHk9IjU2My4wMjgiIHdpZHRoPSIzMC41MjQiIGhlaWdodD0iMzAuNTI0IiBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6I2ZhYmIzNztmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzQuOTAwMDAxNTM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eTowLjk5NjA3ODQzIiBpZD0icGF0aC0xMTIiLz4KICAgICAgPHJlY3QgeD0iMzM1LjM0MiIgeT0iNzIwLjk4NyIgd2lkdGg9IjM4LjY2MyIgaGVpZ2h0PSI0MC42OTgiIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojZmJjMTRjO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozNC45MDAwMDE1MztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjAuOTk2MDc4NDMiIGlkPSJwYXRoLTExMyIvPgogICAgICA8cmVjdCB4PSIzNzEuOTciIHk9IjY2MS45NzUiIHdpZHRoPSIyNi40NTQiIGhlaWdodD0iMzAuNTI0IiBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3BhY2l0eToxO2ZpbGw6I2ZiYzE0YztmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzQuOTAwMDAxNTM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eTowLjk5NjA3ODQzIiBpZD0icGF0aC0xMTQiLz4KICAgICAgPHJlY3QgeD0iLTQyNy45MyIgeT0iNjEwLjA4NSIgd2lkdGg9IjI0LjUwNyIgaGVpZ2h0PSIyNC40MTkiIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojY2M4OTAyO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozNC45MDAwMDE1MztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjAuOTk2MDc4NDMiIGlkPSJwYXRoLTExNSIgdHJhbnNmb3JtPSJzY2FsZSgtMSwxKSIvPgogICAgICA8cmVjdCB4PSI0ODAuNDExIiB5PSI1MjMuNDY5IiB3aWR0aD0iMjAuMzQ5IiBoZWlnaHQ9IjIyLjM4NCIgc3R5bGU9ImRpc3BsYXk6aW5saW5lO29wYWNpdHk6MTtmaWxsOiNmZmQwODY7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM0LjkwMDAwMTUzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MC45OTYwNzg0MyIgaWQ9InBhdGgtMTE2Ii8+CiAgICAgIDxyZWN0IHg9Ii00OTkuNSIgeT0iNDY2LjMxNCIgd2lkdGg9IjI0LjUwNyIgaGVpZ2h0PSIyNC40MTkiIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjE7ZmlsbDojY2M4OTAyO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozNC45MDAwMDE1MztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjAuOTk2MDc4NDMiIGlkPSJwYXRoLTExNyIgdHJhbnNmb3JtPSJzY2FsZSgtMSwxKSIvPgogICAgPC9nPgogICAgPGcgaWQ9ImctMTYiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IG9wYWNpdHk6IDE7IiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAwMDAwMDA3MDAwMjA0OTUsIDAsIDAsIDEuMDAwMDAwMDcwMDAyMDQ5NSwgMTQ0LjU3MDcyMzkxMDc5NjEyLCAxMDA3LjA5OTQzOTg3MTU5OTQpIj4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogbm9uZTsgZmlsbC1vcGFjaXR5OiAxOyBmaWxsLXJ1bGU6IGV2ZW5vZGQ7IHN0cm9rZTogcmdiKDI1NSwgMTIyLCAwKTsgc3Ryb2tlLXdpZHRoOiAyLjM0ODg4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IiBkPSJNIDU4NS4xNjk5Miw1MjQuOTEyMTEgQyA0NDcuNDE3NDUsNzM4Ljg0MDE1IDI4NS45MzA5Myw3OTcuNjgxNDIgOTMuMzQ3NjU2LDgwMS4wMzcxMSAxNTguNjY0NTIsOTIxLjg0MDgzIDI4Ny4yMDAzOCwxMDAzLjE2OTggNDM0LjAzOTA2LDEwMDEuMjU1OSA2MDcuNTY4NTEsOTk4Ljk5NDQ2IDc1Mi41MTMxNyw4ODEuMTg0ODggNzk2LjY1MjM0LDcyMS45NjY4IGMgLTIuNjg2NCwtNi41Nzc2NCAtNi4yMDEwNiwtMTMuNjIwMzcgLTEwLjgxNjQsLTIxLjEzNDc3IEMgNzY4LjY4OTg3LDY3Ny4wMzg3OCA3MDkuMTA0NzgsNTY4LjQ3NzIxIDU4NS4xNjk5Miw1MjQuOTEyMTEgWiIgaWQ9InBhdGgtMTE4Ii8+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IG5vbmU7IGZpbGwtb3BhY2l0eTogMC45OTM5Mzk7IGZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiByZ2IoMjU1LCAxMjIsIDApOyBzdHJva2Utd2lkdGg6IDIuMzQ4ODg7IHN0cm9rZS1saW5lY2FwOiBidXR0OyBzdHJva2UtbGluZWpvaW46IG1pdGVyOyBzdHJva2Utb3BhY2l0eTogMTsiIGQ9Ik0gNTg2LjI1NCA1MjQuMTE1IEMgNTY0LjY4MiA2NTAuNDUzIDQ3Ny45NzQgNzU0LjQ3MiA0OTguNTg0IDgzNS42MDIgQyA1MjQuNjQ4IDkzOC4xOTkgNDE5LjQ1OCA5NjEuNTE1IDMzMy45NzMgOTg5LjM0MiBDIDM2NS45MjMgOTk3LjU0NSAzOTkuNDc1IDEwMDEuNzA2IDQzNC4wMzkgMTAwMS4yNTYgQyA2MzQuMDUyIDk5OC42NDkgNzk2LjA5MyA4NDIuNTM2IDgwOS41NjEgNjQ2LjQzOSBDIDc5My4xOTcgNjQxLjc3NyA3NzcuNDI1IDYzNC42ODkgNzY2LjcyMyA2MjIuNzQ2IEMgNzM0LjAzNSA1ODYuMjcyIDY1MC4xMTcgNTQ2LjU2NCA1ODYuMjU0IDUyNC4xMTUgWiIgaWQ9InBhdGgtMTE5IiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogbm9uZTsgZmlsbC1vcGFjaXR5OiAwLjk5MzkzOTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IHJnYigyNTUsIDEyMiwgMCk7IHN0cm9rZS13aWR0aDogMi4zNDg4ODsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1saW5lam9pbjogbWl0ZXI7IHN0cm9rZS1vcGFjaXR5OiAxOyIgZD0iTSA1ODYuMjU0IDUyNC4xMTUgQyA1NjQuNjgyIDY1MC40NTMgNDc3Ljk3NCA3NTQuNDcyIDQ5OC41ODQgODM1LjYwMiBDIDUyNC42NDggOTM4LjE5OSA0MTkuNDU4IDk2MS41MTUgMzMzLjk3MyA5ODkuMzQyIEMgMzY1LjkyMyA5OTcuNTQ1IDM5OS40NzUgMTAwMS43MDYgNDM0LjAzOSAxMDAxLjI1NiBDIDYzNC4wNTIgOTk4LjY0OSA3OTYuMDkzIDg0Mi41MzYgODA5LjU2MSA2NDYuNDM5IEMgNzkzLjE5NyA2NDEuNzc3IDc3Ny40MjUgNjM0LjY4OSA3NjYuNzIzIDYyMi43NDYgQyA3MzQuMDM1IDU4Ni4yNzIgNjUwLjExNyA1NDYuNTY0IDU4Ni4yNTQgNTI0LjExNSBaIiBpZD0icGF0aC0xMjAiIGJ4Om9yaWdpbj0iMC41IDAuNSIvPgogICAgPC9nPgogIDwvZz4KICA8ZyB0cmFuc2Zvcm09Im1hdHJpeCgwLjYwODI2MSwgMCwgMCwgMC42MDgyNjEsIC0yMC4wODQ5NzYsIDMuMjU1NzM2KSI+CiAgICA8Zz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogcmdiKDY0LCAxNzgsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IG9wYWNpdHk6IDAuNzg7IiBpZD0icGF0aC0xMCIgZD0iTSA0MTkuMTMzIDg1LjczOCBDIDQxNy4yOTUgODUuNzM5IDQxNS40NTUgODUuNzU0IDQxMy42MTEgODUuNzc4IEMgMzU0Ljg1MiA4Ni41NjEgMjk5LjAyMyA5OS4xNzQgMjQ4LjM1OCAxMjEuMzIgQyA1ODQuMTIxIDEzLjIwNiA3OTYuMTc1IDIxMS4yNiA4MzEuNyA1MDguNzczIEwgODQ2LjM4MyA1MDcuMTI0IEMgODE1LjU4NiAyMzUuODAxIDY1Mi40NzcgODUuNTg4IDQxOS4xMzMgODUuNzM4IFoiIHRyYW5zZm9ybT0ibWF0cml4KDAuOTYzNzMsIDAuMjY2ODc4LCAtMC4yNjY4NzgsIDAuOTYzNzMsIDg5LjUwNTIzMSwgLTEzNi42MTUwNjEpIiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogcmdiKDY0LCAxNzgsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IG9wYWNpdHk6IDE7IiBpZD0icGF0aC0zIiBkPSJNIDE0Ni4wMzcgMTk0LjA2NSBDIDE0NC4yMDEgMTk0LjA2NiAxNDIuMzYxIDE5NC4wODEgMTQwLjUxNyAxOTQuMTA0IEMgODEuNzYgMTk0Ljg4OCAyNS45MzEgMjA3LjUwMyAtMjQuNzM2IDIyOS42NDggQyAzMTEuMDI5IDEyMS41MzEgNTIzLjA4MyAzMTkuNTgzIDU1OC42MDQgNjE3LjA5MyBMIDU3My4yODQgNjE1LjQ0MyBDIDU0Mi40OSAzNDQuMTIyIDM3OS4zODUgMTkzLjkxMyAxNDYuMDM3IDE5NC4wNjUgWiIgdHJhbnNmb3JtPSJtYXRyaXgoLTAuMTgwOTg4LCAtMC45ODM0ODUsIDAuOTgzNDg1LCAtMC4xODA5ODgsIC0zOS4yOTg1ODEsIDcwNS44OTc1NDQpIiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogcmdiKDY0LCAxNzgsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IG9wYWNpdHk6IDAuNDsiIGlkPSJwYXRoLTExIiBkPSJNIDQ4Ny43NDQgMTkzLjA4NCBDIDQ4NS45MDYgMTkzLjA4NSA0ODQuMDY3IDE5My4xIDQ4Mi4yMjMgMTkzLjEyMyBDIDQyMy40NjQgMTkzLjkwNyAzNjcuNjM1IDIwNi41MiAzMTYuOTc1IDIyOC42NjggQyA2NTIuNzI2IDEyMC41NTIgODY0Ljc3NSAzMTguNjA1IDkwMC4yOTkgNjE2LjEwOSBMIDkxNC45NzkgNjE0LjQ2IEMgODg0LjE4NCAzNDMuMTQ0IDcyMS4wODEgMTkyLjkzNSA0ODcuNzQ0IDE5My4wODQgWiIgdHJhbnNmb3JtPSJtYXRyaXgoMC42MTk5OTcsIDAuNzg0NjA1LCAtMC43ODQ2MDUsIDAuNjE5OTk3LCA1MjMuMDY3MjMxLCAtMzQzLjMzMTUzOSkiIGJ4Om9yaWdpbj0iMC41IDAuNSIvPgogICAgICA8cGF0aCBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBmaWxsOiByZ2IoNjQsIDE3OCwgMjU1KTsgZmlsbC1vcGFjaXR5OiAxOyBmaWxsLXJ1bGU6IGV2ZW5vZGQ7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAxcHg7IHN0cm9rZS1saW5lY2FwOiBidXR0OyBzdHJva2UtbGluZWpvaW46IG1pdGVyOyBzdHJva2Utb3BhY2l0eTogMTsgb3BhY2l0eTogMC44NDsiIGlkPSJwYXRoLTEyIiBkPSJNIDI5NS45NjkgNDMyLjc1NyBDIDI5NC4xMzEgNDMyLjc1OCAyOTIuMjkzIDQzMi43NzMgMjkwLjQ0OSA0MzIuNzk3IEMgMjMxLjY4OCA0MzMuNTggMTc1Ljg2IDQ0Ni4xOTQgMTI1LjE5OCA0NjguMzQxIEMgNDYwLjk1NyAzNjAuMjI2IDY3My4wMDUgNTU4LjI4IDcwOC41MjYgODU1Ljc4NiBMIDcyMy4yMDcgODU0LjEzOSBDIDY5Mi40MTIgNTgyLjgxOSA1MjkuMzEgNDMyLjYwOSAyOTUuOTY5IDQzMi43NTcgWiIgdHJhbnNmb3JtPSJtYXRyaXgoLTAuOTc4ODQ5LCAwLjIwNDU4NCwgLTAuMjA0NTg0LCAtMC45Nzg4NDksIDk2My44MjA3OTYsIDExMTYuMzY3MjkzKSIgYng6b3JpZ2luPSIwLjUgMC41Ii8+CiAgICAgIDxwYXRoIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmU7IGZpbGw6IHJnYig2NCwgMTc4LCAyNTUpOyBmaWxsLW9wYWNpdHk6IDE7IGZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1saW5lam9pbjogbWl0ZXI7IHN0cm9rZS1vcGFjaXR5OiAxOyBvcGFjaXR5OiAwLjQ7IiBpZD0icGF0aC0xMyIgZD0iTSAxNTguMDM2IDE0OC44MyBDIDE1Ni4yIDE0OC44MzMgMTU0LjM2IDE0OC44NDYgMTUyLjUxNiAxNDguODcyIEMgOTMuNzU5IDE0OS42NTMgMzcuOTMgMTYyLjI2NyAtMTIuNzM0IDE4NC40MTEgQyAzMjMuMDIyIDc2LjMwMSA1MzUuMDc2IDI3NC4zNTIgNTcwLjYwNCA1NzEuODU3IEwgNTg1LjI4NiA1NzAuMjA4IEMgNTU0LjQ4MyAyOTguODkxIDM5MS4zOCAxNDguNjgzIDE1OC4wMzYgMTQ4LjgzIFoiIHRyYW5zZm9ybT0ibWF0cml4KDAuMzM4NjE0LCAtMC45NDA5MjYsIDAuOTQwOTI2LCAwLjMzODYxNCwgLTExNS41OTUxNTgsIDQ4My43MDU5ODQpIiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogcmdiKDY0LCAxNzgsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IG9wYWNpdHk6IDE7IiBpZD0icGF0aC0xNCIgZD0iTSA1MDEuMDE5IDI4OC4yOTIgQyA0OTkuMTgxIDI4OC4yOTMgNDk3LjM0IDI4OC4zMDggNDk1LjQ5NiAyODguMzMxIEMgNDM2LjczNiAyODkuMTE1IDM4MC45MDggMzAxLjcyNiAzMzAuMjQzIDMyMy44NzQgQyA2NjYuMDA0IDIxNS43NTcgODc4LjA2MiA0MTMuODEyIDkxMy41ODYgNzExLjMyMiBMIDkyOC4yNjggNzA5LjY3MyBDIDg5Ny40NjggNDM4LjM1MiA3MzQuMzYxIDI4OC4xNDEgNTAxLjAxOSAyODguMjkyIFoiIHRyYW5zZm9ybT0ibWF0cml4KDAuMTY0NjU2LCAwLjk4NjM1MSwgLTAuOTg2MzUxLCAwLjE2NDY1NiwgOTgyLjg1NzI2NiwgLTIzMy40NTIwNjMpIiBieDpvcmlnaW49IjAuNSAwLjUiLz4KICAgICAgPHBhdGggc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgZmlsbDogcmdiKDY0LCAxNzgsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsgZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtbGluZWNhcDogYnV0dDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW9wYWNpdHk6IDE7IG9wYWNpdHk6IDAuNDsiIGlkPSJwYXRoLTE1IiBkPSJNIDE5Mi45NTQgMzc2LjUyMSBDIDE5MS4xMTUgMzc2LjUyMiAxODkuMjc3IDM3Ni41MzcgMTg3LjQzMyAzNzYuNTYxIEMgMTI4LjY3NCAzNzcuMzQ0IDcyLjg0NSAzODkuOTU4IDIyLjE4MSA0MTIuMTAzIEMgMzU3Ljk0IDMwMy45ODkgNTY5Ljk4NyA1MDIuMDQ1IDYwNS41MDUgNzk5LjU1MyBMIDYyMC4xODggNzk3LjkwNSBDIDU4OS4zOTIgNTI2LjU4NCA0MjYuMjk1IDM3Ni4zNjkgMTkyLjk1NCAzNzYuNTIxIFoiIHRyYW5zZm9ybT0ibWF0cml4KC0wLjkzMTQwNCwgLTAuMzYzOTg4LCAwLjM2Mzk4OCwgLTAuOTMxNDA0LCA0MTkuNDk5MDA2LCAxMTgyLjU5OTgwOSkiIGJ4Om9yaWdpbj0iMC41IDAuNSIvPgogICAgICA8cGF0aCBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBmaWxsOiByZ2IoNjQsIDE3OCwgMjU1KTsgZmlsbC1vcGFjaXR5OiAxOyBmaWxsLXJ1bGU6IGV2ZW5vZGQ7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAxcHg7IHN0cm9rZS1saW5lY2FwOiBidXR0OyBzdHJva2UtbGluZWpvaW46IG1pdGVyOyBzdHJva2Utb3BhY2l0eTogMTsgb3BhY2l0eTogMTsiIGlkPSJwYXRoLTE2IiBkPSJNIDIyMS42MTQgNjMuOTczIEMgMjE5Ljc3NyA2My45NzYgMjE3LjkzOCA2My45OSAyMTYuMDk0IDY0LjAxNSBDIDE1Ny4zMzQgNjQuNzk1IDEwMS41MDYgNzcuNDA5IDUwLjg0MSA5OS41NTQgQyAzODYuNTk4IC04LjU1OSA1OTguNjUxIDE4OS40OTcgNjM0LjE3MyA0ODcuMDAxIEwgNjQ4Ljg1NCA0ODUuMzU0IEMgNjE4LjA1OCAyMTQuMDM3IDQ1NC45NTQgNjMuODI0IDIyMS42MTQgNjMuOTczIFoiIHRyYW5zZm9ybT0ibWF0cml4KDAuNzUwNDUyLCAtMC42NjA5MjUsIDAuNjYwOTI1LCAwLjc1MDQ1MiwgLTcwLjgwMzMyMiwgMjkwLjkyMDI3MykiIGJ4Om9yaWdpbj0iMC41IDAuNSIvPgogICAgICA8cGF0aCBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBmaWxsOiByZ2IoNjQsIDE3OCwgMjU1KTsgZmlsbC1vcGFjaXR5OiAxOyBmaWxsLXJ1bGU6IGV2ZW5vZGQ7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAxcHg7IHN0cm9rZS1saW5lY2FwOiBidXR0OyBzdHJva2UtbGluZWpvaW46IG1pdGVyOyBzdHJva2Utb3BhY2l0eTogMTsgb3BhY2l0eTogMC40OyIgaWQ9InBhdGgtMTciIGQ9Ik0gNDQxLjg4OCAzNDIuMDk4IEMgNDQwLjA0NyAzNDIuMDk4IDQzOC4yMDcgMzQyLjExNCA0MzYuMzYyIDM0Mi4xMzggQyAzNzcuNjAxIDM0Mi45MjIgMzIxLjc2NSAzNTUuNTM1IDI3MS4xMDMgMzc3LjY4MSBDIDYwNi44ODYgMjY5LjU2NyA4MTguOTQ0IDQ2Ny42MTUgODU0LjQ2MiA3NjUuMTMzIEwgODY5LjE0MiA3NjMuNDgzIEMgODM4LjM1NCA0OTIuMTU0IDY3NS4yNDIgMzQxLjk0OCA0NDEuODg4IDM0Mi4wOTggWiIgdHJhbnNmb3JtPSJtYXRyaXgoLTAuMzU2NTgyLCAwLjkzNDI2NCwgLTAuOTM0MjY0LCAtMC4zNTY1ODIsIDEyNTYuNzU5NDkzLCAxNjkuMTgyNTUyKSIgYng6b3JpZ2luPSIwLjUgMC41Ii8+CiAgICAgIDxnIHRyYW5zZm9ybT0ibWF0cml4KDAuNzYyNDkzLCAwLCAwLCAwLjc2MjQ5MywgMTkuMjk0NjQ3LCAtNzE2LjMyMjgxNSkiPgogICAgICAgIDxwYXRoIGQ9Ik0gNTY2LjQ2NiAxMDg5LjEzNyBMIDU2Ni40NjYgMTE0OC4yMjIgQyA1NjUuODY3IDExNDguMjE5IDU2NS4yNjcgMTE0OC4yMTcgNTY0LjY2NyAxMTQ4LjIxNyBDIDU2MS40ODEgMTE0OC4yMTcgNTU4LjMxIDExNDguMjU5IDU1NS4xNTQgMTE0OC4zNDEgTCA1NTUuMTU0IDEwODkuMTM3IFogTSA5MDguMjkgMTQ3Ny4xNDYgTCA5NTYuOTg3IDE0NzcuMTQ2IEwgOTU2Ljk4NyAxNDg4LjQ1OCBMIDkwOC41NjkgMTQ4OC40NTggQyA5MDguNTM5IDE0ODQuNjkzIDkwOC40NDcgMTQ4MC45MjIgOTA4LjI5IDE0NzcuMTQ2IFogTSA1NjYuNDY2IDE4MzUuMDEzIEwgNTY2LjQ2NiAxODc2LjQ2NyBMIDU1NS4xNTQgMTg3Ni40NjcgTCA1NTUuMTU0IDE4MzQuODg2IEMgNTU4LjMxOCAxODM0Ljk3MyA1NjEuNDkgMTgzNS4wMTcgNTY0LjY2NyAxODM1LjAxNyBDIDU2NS4yNjcgMTgzNS4wMTcgNTY1Ljg2NyAxODM1LjAxNiA1NjYuNDY2IDE4MzUuMDEzIFogTSAyMjAuNzc1IDE0ODguNDU4IEwgMTY5LjY1NyAxNDg4LjQ1OCBMIDE2OS42NTcgMTQ3Ny4xNDYgTCAyMjEuMDg5IDE0NzcuMTQ2IEMgMjIwLjkyMSAxNDgwLjkwOSAyMjAuODE2IDE0ODQuNjggMjIwLjc3NSAxNDg4LjQ1OCBaIiBzdHlsZT0iZmlsbDogcmdiKDY0LCA0MCwgMCk7IHN0cm9rZTogbm9uZTsiIGJ4Om9yaWdpbj0iMCAwIi8+CiAgICAgICAgPHBhdGggZD0iTSA3NjAuMTIxIDExNDMuMzExIEwgNzE3LjMzNiAxMjE3LjQxNyBDIDcxNS43MiAxMjE2LjUxOCA3MTQuMDk2IDEyMTUuNjMyIDcxMi40NjUgMTIxNC43NjEgTCA3NTUuMzE4IDExNDAuNTM3IFogTSA4MzAuMTIyIDEzMjQuMjAzIEwgOTAwLjQyNCAxMjgzLjYxNCBMIDkwMy4xOTggMTI4OC40MTcgTCA4MzMuMDQgMTMyOC45MjMgQyA4MzIuMDggMTMyNy4zMzkgODMxLjEwNyAxMzI1Ljc2NiA4MzAuMTIyIDEzMjQuMjAzIFogTSA4NDAuNTk5IDE2NDEuMTM3IEwgOTAzLjE5NyAxNjc3LjI3OCBMIDkwMC40MjQgMTY4Mi4wODIgTCA4MzcuOTExIDE2NDUuOTkgQyA4MzguODIxIDE2NDQuMzggODM5LjcxNyAxNjQyLjc2MiA4NDAuNTk5IDE2NDEuMTM3IFogTSA3MjUuMTY4IDE3NjEuODQzIEwgNzYwLjEyMiAxODIyLjM4NSBMIDc1NS4zMTggMTgyNS4xNTggTCA3MjAuMzc5IDE3NjQuNjQxIEMgNzIxLjk4NSAxNzYzLjcyMiA3MjMuNTgyIDE3NjIuNzg5IDcyNS4xNjggMTc2MS44NDMgWiBNIDQwMy41MzggMTc2MC45MzIgTCAzNjYuNDU2IDE4MjUuMTU5IEwgMzYxLjY1MyAxODIyLjM4NiBMIDM5OC44MDIgMTc1OC4wNDIgQyA0MDAuMzcyIDE3NTkuMDE5IDQwMS45NTEgMTc1OS45ODIgNDAzLjUzOCAxNzYwLjkzMiBaIE0gMjg5LjU4IDE2NDIuNjg5IEwgMjIxLjM1IDE2ODIuMDgyIEwgMjE4LjU3NyAxNjc3LjI3OSBMIDI4Ni45NDQgMTYzNy44MDcgQyAyODcuODA3IDE2MzkuNDM3IDI4OC42ODUgMTY0MS4wNjUgMjg5LjU4IDE2NDIuNjg5IFogTSAyOTQuMzU0IDEzMzIuMTY4IEwgMjE4LjU3NiAxMjg4LjQxNyBMIDIyMS4zNSAxMjgzLjYxNCBMIDI5Ny4yMTMgMTMyNy40MTQgQyAyOTYuMjQ2IDEzMjguOTkgMjk1LjI5MyAxMzMwLjU3NSAyOTQuMzU0IDEzMzIuMTY4IFogTSA0MDYuMDc5IDEyMjAuMjU5IEwgMzYxLjY1MyAxMTQzLjMxMSBMIDM2Ni40NTcgMTE0MC41MzcgTCA0MTAuODg5IDEyMTcuNDk1IEMgNDA5LjI3NiAxMjE4LjQwMyA0MDcuNjczIDEyMTkuMzI0IDQwNi4wNzkgMTIyMC4yNTkgWiIgc3R5bGU9ImZpbGw6IHJnYig2NCwgNDAsIDApOyBzdHJva2U6IG5vbmU7IiBieDpvcmlnaW49IjAgMCIvPgogICAgICA8L2c+CiAgICA8L2c+CiAgICA8cmVjdCB4PSI0MjkuMzY3IiB5PSI0MjUuOTc5IiB3aWR0aD0iMjAuMDAzIiBoZWlnaHQ9IjIxLjczNSIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMTsgZmlsbDogcmdiKDgwLCAxNTAsIDIwMCk7IGZpbGwtb3BhY2l0eTogMTsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDM0Ljk7IHN0cm9rZS1taXRlcmxpbWl0OiA0OyBzdHJva2UtZGFzaGFycmF5OiBub25lOyBzdHJva2UtZGFzaG9mZnNldDogMDsgc3Ryb2tlLW9wYWNpdHk6IDAuOTk2MDc4OyIgaWQ9InBhdGgtOTEiIHRyYW5zZm9ybT0ibWF0cml4KDEsIDAsIDAsIDAuOTk5OTk5LCAtMzAxLjM3NzA3NSwgLTIxOS40OTg0MzQpIi8+CiAgICA8cmVjdCB4PSI0NDYuODUzIiB5PSIyNS40NjIiIHdpZHRoPSIyNS45OSIgaGVpZ2h0PSIyNS45OSIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMTsgZmlsbDogcmdiKDgwLCAxNTAsIDIwMCk7IGZpbGwtb3BhY2l0eTogMTsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDM0Ljk7IHN0cm9rZS1taXRlcmxpbWl0OiA0OyBzdHJva2UtZGFzaGFycmF5OiBub25lOyBzdHJva2UtZGFzaG9mZnNldDogMDsgc3Ryb2tlLW9wYWNpdHk6IDAuOTk2MDc4OyIgaWQ9InBhdGgtOTMiLz4KICAgIDxyZWN0IHg9Ii0xMzUuOTU2IiB5PSI2MDUuMTQxIiB3aWR0aD0iMzkuODUxIiBoZWlnaHQ9IjM5Ljg1MSIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMTsgZmlsbDogcmdiKDgwLCAxNTAsIDIwMCk7IGZpbGwtb3BhY2l0eTogMTsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDM0Ljk7IHN0cm9rZS1taXRlcmxpbWl0OiA0OyBzdHJva2UtZGFzaGFycmF5OiBub25lOyBzdHJva2UtZGFzaG9mZnNldDogMDsgc3Ryb2tlLW9wYWNpdHk6IDAuOTk2MDc4OyIgaWQ9InBhdGgtOTQiIHRyYW5zZm9ybT0ibWF0cml4KDAuOTk5OTk5LCAwLCAwLCAxLCA4NDYuMTc2NzU2LCAtMzk0Ljk1NjAyNCkiLz4KICAgIDxyZWN0IHg9IjIyNS43NzkiIHk9IjY4OS44MzYiIHdpZHRoPSIyNS45OSIgaGVpZ2h0PSIyNS45OSIgc3R5bGU9ImRpc3BsYXk6IGlubGluZTsgb3BhY2l0eTogMTsgZmlsbDogcmdiKDgwLCAxNTAsIDIwMCk7IGZpbGwtb3BhY2l0eTogMTsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDM0Ljk7IHN0cm9rZS1taXRlcmxpbWl0OiA0OyBzdHJva2UtZGFzaGFycmF5OiBub25lOyBzdHJva2UtZGFzaG9mZnNldDogMDsgc3Ryb2tlLW9wYWNpdHk6IDAuOTk2MDc4OyIgaWQ9InBhdGgtOTUiLz4KICAgIDxyZWN0IHg9IjU5NC4wMTMiIHk9IjczNy4xNDIiIHdpZHRoPSIyMC43OTIiIGhlaWdodD0iMjIuNTI1IiBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBvcGFjaXR5OiAxOyBmaWxsOiByZ2IoODAsIDE1MCwgMjAwKTsgZmlsbC1vcGFjaXR5OiAxOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMzQuOTsgc3Ryb2tlLW1pdGVybGltaXQ6IDQ7IHN0cm9rZS1kYXNoYXJyYXk6IG5vbmU7IHN0cm9rZS1kYXNob2Zmc2V0OiAwOyBzdHJva2Utb3BhY2l0eTogMC45OTYwNzg7IiBpZD0icGF0aC05NiIvPgogICAgPHJlY3QgeD0iMzg3LjIzNSIgeT0iNDc5LjM5NyIgd2lkdGg9IjI1Ljk5IiBoZWlnaHQ9IjI1Ljk5IiBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBvcGFjaXR5OiAxOyBmaWxsOiByZ2IoODAsIDE1MCwgMjAwKTsgZmlsbC1vcGFjaXR5OiAxOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMzQuOTsgc3Ryb2tlLW1pdGVybGltaXQ6IDQ7IHN0cm9rZS1kYXNoYXJyYXk6IG5vbmU7IHN0cm9rZS1kYXNob2Zmc2V0OiAwOyBzdHJva2Utb3BhY2l0eTogMC45OTYwNzg7IiBpZD0icGF0aC05OCIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMDEsIDAsIDAsIDAuOTk5OTk5LCAzNjUuMjc0OTY2LCA3OS4yOTUyNDEpIi8+CiAgICA8cmVjdCB4PSI0MjEuOTYyIiB5PSI3NzUuOTM3IiB3aWR0aD0iMzIuOTIiIGhlaWdodD0iMzQuNjUzIiBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBvcGFjaXR5OiAxOyBmaWxsOiByZ2IoODAsIDE1MCwgMjAwKTsgZmlsbC1vcGFjaXR5OiAxOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMzQuOTsgc3Ryb2tlLW1pdGVybGltaXQ6IDQ7IHN0cm9rZS1kYXNoYXJyYXk6IG5vbmU7IHN0cm9rZS1kYXNob2Zmc2V0OiAwOyBzdHJva2Utb3BhY2l0eTogMC45OTYwNzg7IiBpZD0icGF0aC05OSIvPgogICAgPHJlY3QgeD0iLTY2LjkzOSIgeT0iLTU2OC45NzgiIHdpZHRoPSIyMC44NjciIGhlaWdodD0iMjAuNzkyIiBzdHlsZT0iZGlzcGxheTogaW5saW5lOyBvcGFjaXR5OiAxOyBmaWxsOiByZ2IoODAsIDE1MCwgMjAwKTsgZmlsbC1vcGFjaXR5OiAxOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMzQuOTsgc3Ryb2tlLW1pdGVybGltaXQ6IDQ7IHN0cm9rZS1kYXNoYXJyYXk6IG5vbmU7IHN0cm9rZS1kYXNob2Zmc2V0OiAwOyBzdHJva2Utb3BhY2l0eTogMC45OTYwNzg7IiBpZD0icGF0aC0xMDEiIHRyYW5zZm9ybT0ibWF0cml4KC0xLCAwLCAwLCAwLjk5OTk5NywgMzEuMzU2OTI4LCA5ODQuNzM2MzA2KSIvPgogIDwvZz4KICA8cGF0aCBkPSJNIDE1NC41MjYgMjMwLjY2IEMgMTQ4LjgwMSAyMzAuNjYgMTQ0LjI3OSAyMzIuNTY4IDE0MC45NjIgMjM2LjM4MyBDIDEzNy42NDggMjQwLjE5NSAxMzUuOTkyIDI0NS40MTcgMTM1Ljk5MiAyNTIuMDQ2IEMgMTM1Ljk5MiAyNTguODYzIDEzNy41OTEgMjY0LjEzIDE0MC43ODUgMjY3Ljg0OSBDIDE0My45ODEgMjcxLjU2NyAxNDguNTM2IDI3My40MjYgMTU0LjQ1MyAyNzMuNDI2IEMgMTU4LjA4NiAyNzMuNDI2IDE2Mi4yMzIgMjcyLjc3MyAxNjYuODkyIDI3MS40NjggTCAxNjYuODkyIDI3Ni43NzggQyAxNjMuMjc5IDI3OC4xMzMgMTU4LjgyNSAyNzguODA4IDE1My41MjggMjc4LjgwOCBDIDE0NS44NTMgMjc4LjgwOCAxMzkuOTI5IDI3Ni40ODIgMTM1Ljc2MSAyNzEuODI3IEMgMTMxLjU5IDI2Ny4xNjcgMTI5LjUwMiAyNjAuNTUgMTI5LjUwMiAyNTEuOTcyIEMgMTI5LjUwMiAyNDYuNjA0IDEzMC41MDcgMjQxLjg5OSAxMzIuNTE5IDIzNy44NjIgQyAxMzQuNTI2IDIzMy44MjMgMTM3LjQyNCAyMzAuNzEgMTQxLjIxIDIyOC41MjQgQyAxNDUuMDAyIDIyNi4zMzkgMTQ5LjQ2MyAyMjUuMjQ3IDE1NC41OTMgMjI1LjI0NyBDIDE2MC4wNiAyMjUuMjQ3IDE2NC44MzUgMjI2LjI0MyAxNjguOTI0IDIyOC4yMzggTCAxNjYuMzU2IDIzMy40MzkgQyAxNjIuNDExIDIzMS41ODYgMTU4LjQ2OSAyMzAuNjYgMTU0LjUyNiAyMzAuNjYgWiBNIDE5My40NjggMjc4LjgwOCBDIDE4Ny42OTIgMjc4LjgwOCAxODMuMTM2IDI3Ny4wNTEgMTc5Ljc5OSAyNzMuNTM1IEMgMTc2LjQ2MiAyNzAuMDIxIDE3NC43OTQgMjY1LjEzNyAxNzQuNzk0IDI1OC44ODkgQyAxNzQuNzk0IDI1Mi41OTIgMTc2LjM0MiAyNDcuNTg4IDE3OS40NCAyNDMuODgzIEMgMTgyLjU0MiAyNDAuMTc2IDE4Ni43MDcgMjM4LjMyMyAxOTEuOTMzIDIzOC4zMjMgQyAxOTYuODI5IDIzOC4zMjMgMjAwLjcwMSAyMzkuOTM0IDIwMy41NTIgMjQzLjE1NCBDIDIwNi40MDMgMjQ2LjM3NCAyMDcuODI4IDI1MC42MjEgMjA3LjgyOCAyNTUuODk1IEwgMjA3LjgyOCAyNTkuNjM2IEwgMTgwLjkyNSAyNTkuNjM2IEMgMTgxLjA0MyAyNjQuMjI0IDE4Mi4yIDI2Ny43MDQgMTg0LjM5OCAyNzAuMDgxIEMgMTg2LjU5NiAyNzIuNDU4IDE4OS42OSAyNzMuNjQ2IDE5My42NzkgMjczLjY0NiBDIDE5Ny44ODUgMjczLjY0NiAyMDIuMDQ0IDI3Mi43NjMgMjA2LjE1NSAyNzEuMDA2IEwgMjA2LjE1NSAyNzYuMjc5IEMgMjA0LjA2MyAyNzcuMTgzIDIwMi4wODQgMjc3LjgzMiAyMDAuMjE5IDI3OC4yMjUgQyAxOTguMzU3IDI3OC42MTUgMTk2LjEwOCAyNzguODA4IDE5My40NjggMjc4LjgwOCBNIDE5MS44NjEgMjQzLjI3NSBDIDE4OC43MjYgMjQzLjI3NSAxODYuMjI3IDI0NC4yOTYgMTg0LjM2MiAyNDYuMzQxIEMgMTgyLjQ5NyAyNDguMzgzIDE4MS4zOTcgMjUxLjIxMiAxODEuMDY1IDI1NC44MjYgTCAyMDEuNDg5IDI1NC44MjYgQyAyMDEuNDg5IDI1MS4wOTYgMjAwLjY1NyAyNDguMjM4IDE5OC45OTEgMjQ2LjI1NiBDIDE5Ny4zMjcgMjQ0LjI2OCAxOTQuOTUyIDI0My4yNzUgMTkxLjg2MSAyNDMuMjc1IFogTSAyNDIuNzU4IDI2Ny40NCBDIDI0Mi43NTggMjcxLjA3OCAyNDEuNDAyIDI3My44ODIgMjM4LjY5NSAyNzUuODUyIEMgMjM1Ljk4NiAyNzcuODI0IDIzMi4xODQgMjc4LjgwOCAyMjcuMjg5IDI3OC44MDggQyAyMjIuMTEgMjc4LjgwOCAyMTguMDcyIDI3Ny45OSAyMTUuMTczIDI3Ni4zNTIgTCAyMTUuMTczIDI3MC44NjYgQyAyMTcuMDUgMjcxLjgxNSAyMTkuMDYzIDI3Mi41NjMgMjIxLjIxMyAyNzMuMTEgQyAyMjMuMzYyIDI3My42NTMgMjI1LjQzNCAyNzMuOTI0IDIyNy40MyAyNzMuOTI0IEMgMjMwLjUxOSAyNzMuOTI0IDIzMi44OTUgMjczLjQzMSAyMzQuNTU4IDI3Mi40NDcgQyAyMzYuMjIxIDI3MS40NjIgMjM3LjA1MiAyNjkuOTU5IDIzNy4wNTIgMjY3LjkzOSBDIDIzNy4wNTIgMjY2LjQxOSAyMzYuMzkyIDI2NS4xMTggMjM1LjA3NiAyNjQuMDM1IEMgMjMzLjc1NyAyNjIuOTU2IDIzMS4xODUgMjYxLjY4IDIyNy4zNjIgMjYwLjIwOSBDIDIyMy43MjUgMjU4Ljg1MyAyMjEuMTQxIDI1Ny42NzMgMjE5LjYwNyAyNTYuNjYyIEMgMjE4LjA3NCAyNTUuNjUyIDIxNi45MzUgMjU0LjUwNiAyMTYuMTg5IDI1My4yMTkgQyAyMTUuNDM3IDI1MS45MzggMjE1LjA2NCAyNTAuNDA3IDIxNS4wNjQgMjQ4LjYyMSBDIDIxNS4wNjQgMjQ1LjQzNyAyMTYuMzYgMjQyLjkyNyAyMTguOTUxIDI0MS4wODUgQyAyMjEuNTM3IDIzOS4yNDUgMjI1LjA4OSAyMzguMzIzIDIyOS42MDcgMjM4LjMyMyBDIDIzMy44MTIgMjM4LjMyMyAyMzcuOTIzIDIzOS4xNzkgMjQxLjkzNyAyNDAuODkyIEwgMjM5LjgzMiAyNDUuNzAxIEMgMjM1LjkxNSAyNDQuMDg0IDIzMi4zNjIgMjQzLjI3NSAyMjkuMTc1IDI0My4yNzUgQyAyMjYuMzczIDI0My4yNzUgMjI0LjI1OCAyNDMuNzE1IDIyMi44MzEgMjQ0LjU5NCBDIDIyMS40MDcgMjQ1LjQ3NSAyMjAuNjk3IDI0Ni42ODggMjIwLjY5NyAyNDguMjMyIEMgMjIwLjY5NyAyNDkuMjc3IDIyMC45NjMgMjUwLjE2OCAyMjEuNDk5IDI1MC45MDIgQyAyMjIuMDM1IDI1MS42MzkgMjIyLjg5NSAyNTIuMzQyIDIyNC4wODUgMjUzLjAwNiBDIDIyNS4yNjcgMjUzLjY3MiAyMjcuNTQ4IDI1NC42MzYgMjMwLjkyNiAyNTUuODk1IEMgMjM1LjU1OCAyNTcuNTgzIDIzOC42ODUgMjU5LjI3OCAyNDAuMzEzIDI2MC45ODYgQyAyNDEuOTQyIDI2Mi42OTkgMjQyLjc1OCAyNjQuODQ5IDI0Mi43NTggMjY3LjQ0IFogTSAyNTcuOTkxIDI3OC4wOTcgTCAyNTIuMDc0IDI3OC4wOTcgTCAyNTIuMDc0IDIzOS4wMzYgTCAyNTcuOTkxIDIzOS4wMzYgTCAyNTcuOTkxIDI3OC4wOTcgTSAyNTEuNTc0IDIyOC40NTEgQyAyNTEuNTc0IDIyNy4wOTcgMjUxLjkwNyAyMjYuMTA2IDI1Mi41NzIgMjI1LjQ3NyBDIDI1My4yMzcgMjI0Ljg0NCAyNTQuMDY3IDIyNC41MjggMjU1LjA2NSAyMjQuNTI4IEMgMjU2LjAxOSAyMjQuNTI4IDI1Ni44NDEgMjI0Ljg1MSAyNTcuNTI5IDIyNS40OTUgQyAyNTguMjE4IDIyNi4xMzUgMjU4LjU2MyAyMjcuMTIxIDI1OC41NjMgMjI4LjQ1MSBDIDI1OC41NjMgMjI5Ljc4MSAyNTguMjE4IDIzMC43NzMgMjU3LjUyOSAyMzEuNDI2IEMgMjU2Ljg0MSAyMzIuMDc5IDI1Ni4wMTkgMjMyLjQwNSAyNTUuMDY1IDIzMi40MDUgQyAyNTQuMDY3IDIzMi40MDUgMjUzLjIzNyAyMzIuMDc5IDI1Mi41NzIgMjMxLjQyNiBDIDI1MS45MDcgMjMwLjc3MyAyNTEuNTc0IDIyOS43ODEgMjUxLjU3NCAyMjguNDUxIFogTSAyNzUuOTMzIDIzOS4wMzYgTCAyNzUuOTMzIDI2NC4zNzUgQyAyNzUuOTMzIDI2Ny41NTggMjc2LjY1OCAyNjkuOTM1IDI3OC4xMDkgMjcxLjUwNCBDIDI3OS41NTggMjczLjA3MyAyODEuODI4IDI3My44NTggMjg0LjkxOCAyNzMuODU4IEMgMjg5LjAwNCAyNzMuODU4IDI5MS45OTEgMjcyLjc0MSAyOTMuODgxIDI3MC41MDcgQyAyOTUuNzY5IDI2OC4yNzMgMjk2LjcxMiAyNjQuNjI1IDI5Ni43MTIgMjU5LjU2NCBMIDI5Ni43MTIgMjM5LjAzNiBMIDMwMi42MyAyMzkuMDM2IEwgMzAyLjYzIDI3OC4wOTcgTCAyOTcuNzQ1IDI3OC4wOTcgTCAyOTYuODkzIDI3Mi44NjEgTCAyOTYuNTcgMjcyLjg2MSBDIDI5NS4zNTkgMjc0Ljc4MiAyOTMuNjc5IDI3Ni4yNTQgMjkxLjUyOSAyNzcuMjc3IEMgMjg5LjM4IDI3OC4yOTggMjg2LjkyNiAyNzguODA4IDI4NC4xNjkgMjc4LjgwOCBDIDI3OS40MTcgMjc4LjgwOCAyNzUuODU4IDI3Ny42ODIgMjczLjQ5MyAyNzUuNDI4IEMgMjcxLjEzIDI3My4xNjkgMjY5Ljk0NyAyNjkuNTU2IDI2OS45NDcgMjY0LjU4OCBMIDI2OS45NDcgMjM5LjAzNiBMIDI3NS45MzMgMjM5LjAzNiBaIE0gMzY0LjU3MyAyNzguMDk3IEwgMzY0LjU3MyAyNTIuNjg1IEMgMzY0LjU3MyAyNDkuNTczIDM2My45MDkgMjQ3LjI0MSAzNjIuNTc4IDI0NS42ODIgQyAzNjEuMjQ4IDI0NC4xMjYgMzU5LjE4IDI0My4zNDcgMzU2LjM3NCAyNDMuMzQ3IEMgMzUyLjY5MiAyNDMuMzQ3IDM0OS45NzEgMjQ0LjQwNiAzNDguMjExIDI0Ni41MjIgQyAzNDYuNDU1IDI0OC42MzYgMzQ1LjU3NyAyNTEuODkxIDM0NS41NzcgMjU2LjI4NiBMIDM0NS41NzcgMjc4LjA5NyBMIDMzOS42NiAyNzguMDk3IEwgMzM5LjY2IDI1Mi42ODUgQyAzMzkuNjYgMjQ5LjU3MyAzMzguOTkzIDI0Ny4yNDEgMzM3LjY2NCAyNDUuNjgyIEMgMzM2LjMzNSAyNDQuMTI2IDMzNC4yNTUgMjQzLjM0NyAzMzEuNDI5IDI0My4zNDcgQyAzMjcuNzIyIDI0My4zNDcgMzI1LjAwOCAyNDQuNDU4IDMyMy4yODQgMjQ2LjY4MSBDIDMyMS41NiAyNDguOTAzIDMyMC43IDI1Mi41NDYgMzIwLjcgMjU3LjYwNiBMIDMyMC43IDI3OC4wOTcgTCAzMTQuNzgxIDI3OC4wOTcgTCAzMTQuNzgxIDIzOS4wMzYgTCAzMTkuNTkzIDIzOS4wMzYgTCAzMjAuNTU0IDI0NC4zODIgTCAzMjAuODQgMjQ0LjM4MiBDIDMyMS45NTggMjQyLjQ3OSAzMjMuNTM1IDI0MC45OTcgMzI1LjU2NiAyMzkuOTMgQyAzMjcuNTk4IDIzOC44NiAzMjkuODcyIDIzOC4zMjMgMzMyLjM5MSAyMzguMzIzIEMgMzM4LjQ5NyAyMzguMzIzIDM0Mi40OSAyNDAuNTMzIDM0NC4zNjcgMjQ0Ljk1NCBMIDM0NC42NDcgMjQ0Ljk1NCBDIDM0NS44MTUgMjQyLjkwOSAzNDcuNTAxIDI0MS4yOTQgMzQ5LjcwNyAyNDAuMTA2IEMgMzUxLjkxOCAyMzguOTE4IDM1NC40MzggMjM4LjMyMyAzNTcuMjY5IDIzOC4zMjMgQyAzNjEuNjg0IDIzOC4zMjMgMzY0Ljk5MSAyMzkuNDYgMzY3LjE4OSAyNDEuNzMxIEMgMzY5LjM4NyAyNDMuOTk3IDM3MC40ODUgMjQ3LjYyNSAzNzAuNDg1IDI1Mi42MTggTCAzNzAuNDg1IDI3OC4wOTcgTCAzNjQuNTczIDI3OC4wOTcgWiIgc3R5bGU9InRleHQtdHJhbnNmb3JtOiBub25lOyBmaWxsOiByZ2IoNjQsIDQwLCAwKTsgaXNvbGF0aW9uOiBhdXRvOyBvcGFjaXR5OiAxOyIgYng6b3JpZ2luPSIwLjUgMC41Ii8+Cjwvc3ZnPg==); + background-size: 200px 200px; } + } +>> \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/resources/templates/event_item.st b/duniter4j-es-subscription/src/main/resources/templates/event_item.st new file mode 100644 index 00000000..9fdd774d --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/templates/event_item.st @@ -0,0 +1,6 @@ +event_item(e) ::= << + <div class="item"> + <h3>$e.description$</h3> + <h4 class="gray">$e.time; format="short"$</h4> + </div> +>> \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/resources/templates/html.st b/duniter4j-es-subscription/src/main/resources/templates/html.st new file mode 100644 index 00000000..443bbb59 --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/templates/html.st @@ -0,0 +1,19 @@ +html(content, useCss) ::= << + <!DOCTYPE html> + <head> + <meta charset="UTF-8"> + <title>Cesium+</title> + $if(useCss)$ + <style> + $css()$ + $css_logo()$ + </style> + $endif$ + </head> + <body class="platform-browser platform-linux platform-ready"> + <ion-content> + $content$ + </ion-content> + </body> +</html> +>> \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/resources/templates/html_email_content.st b/duniter4j-es-subscription/src/main/resources/templates/html_email_content.st new file mode 100644 index 00000000..629515c4 --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/templates/html_email_content.st @@ -0,0 +1,33 @@ +html_email_content(issuer, senderPubkey, senderName, events, url) ::= << + <div class="row no-padding"> + <div class="col col-20 hidden-xs hidden-sm text-center" id="home"> + <div class="logo"></div> + </div> + <div class="col"> + <div class="padding padding-bottom row responsive-sm"> + <div class="col"> + $length(events):{count | $i18n_args("duniter4j.es.subscription.email.header", [issuer, count])$}$ + </div> + <div class="col"> + <a class="button button-positive pull-right" + href="$url$">$i18n("duniter4j.es.subscription.email.openCesium")$ >></a> + </div> + </div> + <div class="list item-border-large"> + <div class="item item-divider stable-bg"> + $i18n("duniter4j.es.subscription.email.notificationsDivider")$ + </div> + $events:{e|$event_item(e)$}$ + </div> + <div class="center padding text-center"> + <i class="ion-es-user-api"></i> + $i18n_args("duniter4j.es.subscription.email.footer.sendBy", [{$[url, "/#/app/wot/", senderPubkey, "/"]; separator=""$}, senderName])$ + <br/> + <small> + $i18n_args("duniter4j.es.subscription.email.footer.disableHelp", {$[url, "/#/app/wallet/subscriptions"]; separator=""$})$ + </small> + </div> + </div> + <div class="col col-20 hidden-xs hidden-sm"> </div> + </div> +>> \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/resources/templates/i18n.st b/duniter4j-es-subscription/src/main/resources/templates/i18n.st new file mode 100644 index 00000000..d5d042c6 --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/templates/i18n.st @@ -0,0 +1,2 @@ +i18n(key) ::= "$key; format=\"i18n\"$" + diff --git a/duniter4j-es-subscription/src/main/resources/templates/i18n_args.st b/duniter4j-es-subscription/src/main/resources/templates/i18n_args.st new file mode 100644 index 00000000..120d7753 --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/templates/i18n_args.st @@ -0,0 +1,2 @@ +i18n_args(key, params) ::= "$key; format={i18n:$params; separator=\",\"$}$" + diff --git a/duniter4j-es-subscription/src/main/resources/templates/text_email.st b/duniter4j-es-subscription/src/main/resources/templates/text_email.st new file mode 100644 index 00000000..b982a67a --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/templates/text_email.st @@ -0,0 +1,13 @@ +text_email(issuer, senderPubkey, senderName, events, url) ::= << +$length(events):{count | $i18n_args("duniter4j.es.subscription.email.header.text", [issuer, count])$}$ + +$i18n("duniter4j.es.subscription.email.notificationsDivider")$ +$events:{e|$text_event_item(e)$}$ + +$i18n("duniter4j.es.subscription.email.openCesium")$ : $url$ + +----------------------------------------------- +$i18n_args("duniter4j.es.subscription.email.footer.sendBy.text", [{$[url, "/#/app/wot/", senderPubkey, "/"]; separator=""$}, senderName])$ +$i18n_args("duniter4j.es.subscription.email.footer.disableHelp.text", {$[url, "/#/app/wallet/subscriptions"]; separator=""$})$ + +>> \ No newline at end of file diff --git a/duniter4j-es-subscription/src/main/resources/templates/text_event_item.st b/duniter4j-es-subscription/src/main/resources/templates/text_event_item.st new file mode 100644 index 00000000..51cd56fa --- /dev/null +++ b/duniter4j-es-subscription/src/main/resources/templates/text_event_item.st @@ -0,0 +1,3 @@ +text_event_item(e) ::= << + - $e.time; format="short"$ | $e.description$ +>> \ No newline at end of file diff --git a/duniter4j-es-gchange/src/test/es-home/config/elasticsearch.yml b/duniter4j-es-subscription/src/test/es-home/config/elasticsearch.yml similarity index 90% rename from duniter4j-es-gchange/src/test/es-home/config/elasticsearch.yml rename to duniter4j-es-subscription/src/test/es-home/config/elasticsearch.yml index 828ddbd0..c0d0fd11 100644 --- a/duniter4j-es-gchange/src/test/es-home/config/elasticsearch.yml +++ b/duniter4j-es-subscription/src/test/es-home/config/elasticsearch.yml @@ -15,7 +15,7 @@ # Use a descriptive name for your cluster: # # cluster.name: my-application -cluster.name: duniter4j-elasticsearch-TEST +cluster.name: duniter4j-subscription-TEST # # ------------------------------------ Node ------------------------------------ # @@ -153,12 +153,15 @@ duniter.data.sync.enable: false #duniter.data.sync.host: data.duniter.fr #duniter.data.sync.port: 80 -# ---------------------------------- Duniter4j SMTP server ------------------------- +# ---------------------------------- Duniter4j SMTP server ---------------------- # # SMTP server configuration (host and port) # +duniter.mail.enable: true #duniter.mail.smtp.host: localhost #duniter.mail.smtp.port: 25 +#duniter.mail.smtp.host: smtp.gmail.com +#duniter.mail.smtp.port: 25 # # Mail 'from' address # @@ -169,10 +172,21 @@ duniter.mail.from: root@EIS-DEV # #duniter.mail.admin: user@domain.com duniter.mail.admin: blavenie@EIS-DEV +#duniter.mail.admin: benoit.lavenier@e-is.pro # # Mail subject prefix # #duniter.mail.subject.prefix: [Duniter4j ES] -duniter.changes.listenSource: */block +duniter.changes.listenSource: '*/block' duniter.ws.port: 9400 + +# ---------------------------------- Duniter4j Subscription services ------------ +# +# Enable subscription services ? (default: true) +# +duniter.subscription.enable: true +# +# Time interval (millisecond) to send email ? (default: 3600000 = 1h) +# +duniter.subscription.email.interval: 10000 \ No newline at end of file diff --git a/duniter4j-es-gchange/src/test/es-home/config/logging.yml b/duniter4j-es-subscription/src/test/es-home/config/logging.yml similarity index 100% rename from duniter4j-es-gchange/src/test/es-home/config/logging.yml rename to duniter4j-es-subscription/src/test/es-home/config/logging.yml diff --git a/duniter4j-es-subscription/src/test/es-home/plugins/mapper-attachments/plugin-descriptor.properties b/duniter4j-es-subscription/src/test/es-home/plugins/mapper-attachments/plugin-descriptor.properties new file mode 100644 index 00000000..b2ab3586 --- /dev/null +++ b/duniter4j-es-subscription/src/test/es-home/plugins/mapper-attachments/plugin-descriptor.properties @@ -0,0 +1,80 @@ +# Elasticsearch plugin descriptor file +# This file must exist as 'plugin-descriptor.properties' at +# the root directory of all plugins. +# +# A plugin can be 'site', 'jvm', or both. +# +### example site plugin for "foo": +# +# foo.zip <-- zip file for the plugin, with this structure: +# _site/ <-- the contents that will be served +# plugin-descriptor.properties <-- example contents below: +# +# site=true +# description=My cool plugin +# version=1.0 +# +### example jvm plugin for "foo" +# +# foo.zip <-- zip file for the plugin, with this structure: +# <arbitrary name1>.jar <-- classes, resources, dependencies +# <arbitrary nameN>.jar <-- any number of jars +# plugin-descriptor.properties <-- example contents below: +# +# jvm=true +# classname=foo.bar.BazPlugin +# description=My cool plugin +# version=2.0.0-rc1 +# elasticsearch.version=2.0 +# java.version=1.7 +# +### mandatory elements for all plugins: +# +# 'description': simple summary of the plugin +description=The mapper attachments plugin adds the attachment type to Elasticsearch using Apache Tika. +# +# 'version': plugin's version +version=2.3.3 +# +# 'name': the plugin name +name=mapper-attachments + +### mandatory elements for site plugins: +# +# 'site': set to true to indicate contents of the _site/ +# directory in the root of the plugin should be served. +site=false +# +### mandatory elements for jvm plugins : +# +# 'jvm': true if the 'classname' class should be loaded +# from jar files in the root directory of the plugin. +# Note that only jar files in the root directory are +# added to the classpath for the plugin! If you need +# other resources, package them into a resources jar. +jvm=true +# +# 'classname': the name of the class to load, fully-qualified. +classname=org.elasticsearch.mapper.attachments.MapperAttachmentsPlugin +# +# 'java.version' version of java the code is built against +# use the system property java.specification.version +# version string must be a sequence of nonnegative decimal integers +# separated by "."'s and may have leading zeros +java.version=1.7 +# +# 'elasticsearch.version' version of elasticsearch compiled against +# You will have to release a new version of the plugin for each new +# elasticsearch release. This version is checked when the plugin +# is loaded so Elasticsearch will refuse to start in the presence of +# plugins with the incorrect elasticsearch.version. +elasticsearch.version=2.3.3 +# +### deprecated elements for jvm plugins : +# +# 'isolated': true if the plugin should have its own classloader. +# passing false is deprecated, and only intended to support plugins +# that have hard dependencies against each other. If this is +# not specified, then the plugin is isolated by default. +isolated=true +# diff --git a/duniter4j-es-subscription/src/test/es-home/plugins/mapper-attachments/plugin-security.policy b/duniter4j-es-subscription/src/test/es-home/plugins/mapper-attachments/plugin-security.policy new file mode 100644 index 00000000..32647666 --- /dev/null +++ b/duniter4j-es-subscription/src/test/es-home/plugins/mapper-attachments/plugin-security.policy @@ -0,0 +1,34 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// NOTE: when modifying this file, look at restrictions in TikaImpl too +grant { + // needed to apply additional sandboxing to tika parsing + permission java.security.SecurityPermission "createAccessControlContext"; + + // TODO: fix PDFBox not to actually install bouncy castle like this + permission java.security.SecurityPermission "putProviderProperty.BC"; + permission java.security.SecurityPermission "insertProvider"; + // needed only on java 7 + permission java.security.SecurityPermission "insertProvider.BC"; + // TODO: fix POI XWPF to not do this: https://bz.apache.org/bugzilla/show_bug.cgi?id=58597 + permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + // needed by xmlbeans, as part of POI for MS xml docs + permission java.lang.RuntimePermission "getClassLoader"; +}; diff --git a/duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/TestFixtures.java b/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/TestFixtures.java similarity index 87% rename from duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/TestFixtures.java rename to duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/TestFixtures.java index 36f09330..43ba7fe6 100644 --- a/duniter4j-es-gchange/src/test/java/org/duniter/elasticsearch/TestFixtures.java +++ b/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/TestFixtures.java @@ -1,4 +1,4 @@ -package org.duniter.elasticsearch; +package org.duniter.elasticsearch.subscription; /* * #%L @@ -25,4 +25,7 @@ package org.duniter.elasticsearch; public class TestFixtures extends org.duniter.core.test.TestFixtures { + public String getEmail() { + return "contact@e-is.pro"; + } } diff --git a/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/TestResource.java b/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/TestResource.java new file mode 100644 index 00000000..04804775 --- /dev/null +++ b/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/TestResource.java @@ -0,0 +1,109 @@ +package org.duniter.elasticsearch.subscription; + +/* + * #%L + * UCoin Java Client :: Core API + * %% + * Copyright (C) 2014 - 2015 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import org.apache.commons.io.FileUtils; +import org.elasticsearch.bootstrap.Elasticsearch; +import org.junit.runner.Description; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +public class TestResource extends org.duniter.core.test.TestResource { + + private static final Logger log = LoggerFactory.getLogger(TestResource.class); + + + public static TestResource create() { + return new TestResource(null, true); + } + + public static TestResource createNotStartEs() { + return new TestResource(null, false); + } + + public static TestResource create(boolean startES) { + return new TestResource(null, startES); + } + + public static TestResource create(String configName) { + return new TestResource(configName, true); + } + + public static TestResource create(String configName, boolean startES) { + return new TestResource(configName, startES); + } + + private TestFixtures fixtures = new TestFixtures(); + private final boolean startESNode; + + protected TestResource(String configName, boolean startESNode) { + super(configName); + this.startESNode = startESNode; + } + + public TestFixtures getFixtures() { + return fixtures; + } + + public PluginSettings getPluginSettings() { + return PluginSettings.instance(); + } + + protected void before(Description description) throws Throwable { + super.before(description); + + // Prepare ES home + File esHomeDir = getResourceDirectory("es-home"); + + System.setProperty("es.path.home", esHomeDir.getCanonicalPath()); + + FileUtils.copyDirectory(new File("src/test/es-home"), esHomeDir); + FileUtils.copyDirectory(new File("target/classes"), new File(esHomeDir, "plugins/duniter4j-es-subscription")); + + // Copy dependencies plugins + FileUtils.copyDirectory(new File("../duniter4j-es-core/target/classes"), new File(esHomeDir, "plugins/duniter4j-es-core")); + FileUtils.copyDirectory(new File("../duniter4j-es-user/target/classes"), new File(esHomeDir, "plugins/duniter4j-es-user")); + + if (startESNode) { + Elasticsearch.main(new String[]{"start"}); + } + + /*while(true) { + Thread.sleep(10000); + }*/ + } + + /** + * Return configuration files prefix (i.e. 'allegro-test') + * Could be override by external project + * + * @return the prefix to use to retrieve configuration files + */ + protected String getConfigFilesPrefix() { + return "duniter4j-es-subscription-test"; + } + +} diff --git a/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionServiceTest.java b/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionServiceTest.java new file mode 100644 index 00000000..81b5babe --- /dev/null +++ b/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionServiceTest.java @@ -0,0 +1,168 @@ +package org.duniter.elasticsearch.subscription.service; + +/* + * #%L + * UCoin Java Client :: ElasticSearch Indexer + * %% + * Copyright (C) 2014 - 2016 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableList; +import org.duniter.core.client.model.ModelUtils; +import org.duniter.core.client.model.bma.jackson.JacksonUtils; +import org.duniter.core.client.model.elasticsearch.Record; +import org.duniter.core.client.model.local.Wallet; +import org.duniter.core.client.service.ServiceLocator; +import org.duniter.core.exception.TechnicalException; +import org.duniter.core.service.CryptoService; +import org.duniter.core.util.StringUtils; +import org.duniter.core.util.crypto.CryptoUtils; +import org.duniter.core.util.url.URLs; +import org.duniter.elasticsearch.subscription.TestResource; +import org.duniter.elasticsearch.subscription.model.email.EmailSubscription; +import org.duniter.elasticsearch.user.model.UserEvent; +import org.duniter.elasticsearch.user.model.UserEventCodes; +import org.duniter.elasticsearch.user.service.UserEventService; +import org.junit.*; +import org.nuiton.i18n.I18n; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.stringtemplate.v4.ST; +import org.stringtemplate.v4.STGroupFile; + +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * Created by Benoit on 06/05/2015. + */ +public class SubscriptionServiceTest { + private static final Logger log = LoggerFactory.getLogger(SubscriptionServiceTest.class); + + @ClassRule + public static final TestResource resource = TestResource.create(); + + private SubscriptionService service; + private UserEventService userEventService; + private CryptoService cryptoService; + private ObjectMapper objectMapper; + + @Before + public void setUp() throws Exception { + service = ServiceLocator.instance().getBean(SubscriptionService.class); + cryptoService = ServiceLocator.instance().getCryptoService(); + userEventService = ServiceLocator.instance().getBean(UserEventService.class); + objectMapper = JacksonUtils.newObjectMapper(); + } + + @Test + public void create() throws JsonProcessingException { + Wallet wallet = createTestWallet(); + + createAndIndexSubscription(wallet); + + } + + @Test + public void executeEmailSubscriptions() throws Exception{ + Wallet wallet = createTestWallet(); + try { + createAndIndexSubscription(wallet); + } catch(Exception e) { + Assume.assumeNoException(e); + } + + userEventService.indexEvent(Locale.getDefault(), + UserEvent.newBuilder( + UserEvent.EventType.INFO, + UserEventCodes.MEMBER_JOIN.name()) + .setRecipient(wallet.getPubKeyHash()) + .build()) + .get(); + + // wait 10s + Thread.sleep(10000); + + service.executeEmailSubscriptions(); + + // wait 10s + Thread.sleep(10000); + } + + /* -- internal methods -- */ + + protected Wallet createTestWallet() { + Wallet wallet = new Wallet( + resource.getFixtures().getCurrency(), + resource.getFixtures().getUid(), + CryptoUtils.decodeBase58(resource.getFixtures().getUserPublicKey()), + CryptoUtils.decodeBase58(resource.getFixtures().getUserSecretKey())); + + return wallet; + } + + protected EmailSubscription createAndIndexSubscription(Wallet wallet) throws JsonProcessingException { + + EmailSubscription subscription = createEmailSubscription(wallet); + + // Compute full JSON (with hash + signature) + String json = objectMapper.writeValueAsString(subscription); + + String id = service.create(json); + Assert.assertNotNull(id); + + subscription.setId(id); + return subscription; + } + + protected EmailSubscription createEmailSubscription(Wallet wallet) throws JsonProcessingException { + + EmailSubscription subscription = new EmailSubscription(); + subscription.setIssuer(wallet.getPubKeyHash()); + subscription.setTime(System.currentTimeMillis()/1000); + subscription.setRecipient(resource.getPluginSettings().getNodePubkey()); + + // Encrypt email then fill + String email = resource.getPluginSettings().getMailAdmin(); + byte[] nonce = cryptoService.getBoxRandomNonce(); + + EmailSubscription.Content content = EmailSubscription.newContent(); + content.setEmail(email); + String jsonContent = objectMapper.writeValueAsString(content); + + String cypherContent = cryptoService.box(jsonContent, nonce, wallet.getSecKey(), wallet.getPubKey()); + subscription.setRecipientContent(cypherContent); + subscription.setNonce(CryptoUtils.encodeBase58(nonce)); + + // Fill hash + signature + String json = objectMapper.writeValueAsString(subscription); + + json = JacksonUtils.removeAttribute(json, Record.PROPERTY_SIGNATURE); + json = JacksonUtils.removeAttribute(json, Record.PROPERTY_HASH); + + subscription.setHash(cryptoService.hash(json)); + subscription.setSignature(cryptoService.sign(json, wallet.getSecKey())); + + return subscription; + } +} + diff --git a/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionTemplateTest.java b/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionTemplateTest.java new file mode 100644 index 00000000..c526a6a2 --- /dev/null +++ b/duniter4j-es-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionTemplateTest.java @@ -0,0 +1,129 @@ +package org.duniter.elasticsearch.subscription.service; + +/* + * #%L + * UCoin Java Client :: ElasticSearch Indexer + * %% + * Copyright (C) 2014 - 2016 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import org.duniter.core.client.model.ModelUtils; +import org.duniter.core.exception.TechnicalException; +import org.duniter.core.test.TestResource; +import org.duniter.elasticsearch.subscription.util.stringtemplate.DateRenderer; +import org.duniter.elasticsearch.subscription.util.stringtemplate.I18nRenderer; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.stringtemplate.v4.ST; +import org.stringtemplate.v4.STGroup; +import org.stringtemplate.v4.STGroupDir; +import org.stringtemplate.v4.StringRenderer; + +import java.io.File; +import java.io.FileWriter; +import java.util.Date; + +import static org.junit.Assert.assertNotNull; + +/** + * Created by Benoit on 06/05/2015. + */ +public class SubscriptionTemplateTest { + private static final Logger log = LoggerFactory.getLogger(SubscriptionTemplateTest.class); + + private static final boolean verbose = true; + + //@ClassRule + public static final TestResource resource = TestResource.create(); + + @Test + public void testHtmlEmail() throws Exception{ + + try { + STGroup group = new STGroupDir("templates", '$', '$'); + + group.registerRenderer(Date.class, new DateRenderer()); + group.registerRenderer(String.class, new StringRenderer()); + group.registerRenderer(String.class, new I18nRenderer()); + + ST contentEmail = group.getInstanceOf("html_email_content"); + contentEmail.add("issuer", "MyIssuerName"); + contentEmail.add("url", "https://g1.duniter.fr"); + contentEmail.add("senderPubkey", "G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU"); + contentEmail.add("senderName", ModelUtils.minifyPubkey("G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU")); + contentEmail.addAggr("events.{description, time}", new Object[]{"My event description", new Date()}); + assertNotNull(contentEmail); + + ST css_logo = group.getInstanceOf("css_logo"); + assertNotNull(css_logo); + + ST htmlTpl = group.getInstanceOf("html"); + assertNotNull(htmlTpl); + htmlTpl.add("content", contentEmail.render()); + htmlTpl.add("useCss", "true"); + String html = htmlTpl.render(); + + if (verbose) { + System.out.println(html); + } + + //FileWriter fw = new FileWriter(new File(resource.getResourceDirectory("out"), "page.html")); + FileWriter fw = new FileWriter(new File("/home/blavenie/git/duniter4j/duniter4j-es-subscription/src/test/resources/test2.html")); + fw.write(html); + fw.flush(); + fw.close(); + + + } + catch (Exception e) { + throw new TechnicalException(e); + } + } + + @Test + public void testTextEmail() throws Exception{ + + try { + STGroup group = new STGroupDir("templates", '$', '$'); + + group.registerRenderer(Date.class, new DateRenderer()); + group.registerRenderer(String.class, new StringRenderer()); + group.registerRenderer(String.class, new I18nRenderer()); + + ST tpl = group.getInstanceOf("text_email"); + tpl.add("issuer", "MyIssuerName"); + tpl.add("url", "https://g1.duniter.fr"); + tpl.add("senderPubkey", "G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU"); + tpl.add("senderName", ModelUtils.minifyPubkey("G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU")); + tpl.addAggr("events.{description, time}", new Object[]{"My event description", new Date()}); + assertNotNull(tpl); + + String text = tpl.render(); + + if (verbose) { + System.out.println(text); + } + + } + catch (Exception e) { + throw new TechnicalException(e); + } + } +} + diff --git a/duniter4j-es-subscription/src/test/resources/META-INF/services/org.duniter.core.beans.Bean b/duniter4j-es-subscription/src/test/resources/META-INF/services/org.duniter.core.beans.Bean new file mode 100644 index 00000000..e69de29b diff --git a/duniter4j-es-gchange/src/test/resources/curl_test.sh b/duniter4j-es-subscription/src/test/resources/curl_test.sh similarity index 100% rename from duniter4j-es-gchange/src/test/resources/curl_test.sh rename to duniter4j-es-subscription/src/test/resources/curl_test.sh diff --git a/duniter4j-es-subscription/src/test/resources/duniter4j-es-subscription-test.properties b/duniter4j-es-subscription/src/test/resources/duniter4j-es-subscription-test.properties new file mode 100644 index 00000000..c58166c5 --- /dev/null +++ b/duniter4j-es-subscription/src/test/resources/duniter4j-es-subscription-test.properties @@ -0,0 +1,2 @@ +# Empty test file +# (need for inherited TestResource). See files 'src/test/es-home/config' \ No newline at end of file diff --git a/duniter4j-es-gchange/src/test/resources/log4j.properties b/duniter4j-es-subscription/src/test/resources/log4j.properties similarity index 68% rename from duniter4j-es-gchange/src/test/resources/log4j.properties rename to duniter4j-es-subscription/src/test/resources/log4j.properties index 2712b72e..29c857ca 100644 --- a/duniter4j-es-gchange/src/test/resources/log4j.properties +++ b/duniter4j-es-subscription/src/test/resources/log4j.properties @@ -9,10 +9,9 @@ log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %5p (%c:%L) - [%t] %m # duniter4j levels log4j.logger.org.duniter=INFO -#log4j.logger.org.duniter=DEBUG -log4j.logger.org.duniter.core=WARN -log4j.logger.org.duniter.elasticsearch=DEBUG +log4j.logger.org.duniter.elasticsearch.subscription=DEBUG # Other frameworks levels -log4j.logger.org.elasticsearch=INFO - +log4j.logger.org.elasticsearch=WARN +log4j.logger.org.apache=ERROR +log4j.logger.org.nuiton.converter=ERROR \ No newline at end of file diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/PluginInit.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/PluginInit.java index d06b1f75..0e554a0d 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/PluginInit.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/PluginInit.java @@ -22,6 +22,9 @@ package org.duniter.elasticsearch.user; * #L% */ +import org.duniter.core.util.StringUtils; +import org.duniter.core.util.crypto.CryptoUtils; +import org.duniter.core.util.crypto.KeyPair; import org.duniter.elasticsearch.PluginSettings; import org.duniter.elasticsearch.threadpool.ThreadPool; import org.duniter.elasticsearch.user.model.UserEvent; @@ -61,18 +64,9 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { threadPool.scheduleOnClusterHealthStatus(() -> { createIndices(); - // Waiting cluster back to GREEN or YELLOW state, before synchronize - threadPool.scheduleOnClusterHealthStatus(() -> { - synchronize(); - - // Notify admin - injector.getInstance(UserEventService.class) - .notifyAdmin(new UserEvent( - UserEvent.EventType.INFO, - UserEventCodes.NODE_STARTED.name(), - I18n.n("duniter.event.NODE_STARTED"), - clusterName)); - }, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); + // Waiting cluster back to GREEN or YELLOW state, before doAfterStart + threadPool.scheduleOnClusterHealthStatus(this::doAfterStart, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); + }, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); } @@ -130,10 +124,20 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { } } - protected void synchronize() { + protected void doAfterStart() { if (pluginSettings.enableDataSync()) { // Synchronize injector.getInstance(SynchroService.class).synchronize(); } + + // Notify admin + injector.getInstance(AdminService.class) + .notifyAdmin(new UserEvent( + UserEvent.EventType.INFO, + UserEventCodes.NODE_STARTED.name(), + I18n.n("duniter.user.event.NODE_STARTED"), + clusterName)); } + + } diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/PluginSettings.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/PluginSettings.java index b727961d..4ff4731a 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/PluginSettings.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/PluginSettings.java @@ -23,11 +23,18 @@ package org.duniter.elasticsearch.user; */ +import org.duniter.core.service.CryptoService; +import org.duniter.core.util.StringUtils; +import org.duniter.core.util.crypto.CryptoUtils; +import org.duniter.core.util.crypto.KeyPair; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.component.LifecycleListener; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.settings.Settings; +import java.util.Locale; + /** * Access to configuration options * @author Benoit Lavenier <benoit.lavenier@e-is.pro> @@ -36,11 +43,19 @@ import org.elasticsearch.common.settings.Settings; public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { private org.duniter.elasticsearch.PluginSettings delegate; + private CryptoService cryptoService; + + private KeyPair nodeKeyPair; + private boolean isRandomNodeKeyPair; + private String nodePubkey; @Inject - public PluginSettings(Settings settings, org.duniter.elasticsearch.PluginSettings delegate) { + public PluginSettings(Settings settings, + org.duniter.elasticsearch.PluginSettings delegate, + CryptoService cryptoService) { super(settings); this.delegate = delegate; + this.cryptoService = cryptoService; // Add i18n bundle name delegate.addI18nBundleName(getI18nBundleName()); @@ -97,6 +112,14 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { return settings.get("duniter.mail.smtp.password"); } + public boolean isMailSmtpStartTLS() { + return settings.getAsBoolean("duniter.mail.smtp.starttle", false); + } + + public boolean isMailSmtpUseSSL() { + return settings.getAsBoolean("duniter.mail.smtp.ssl", false); + } + public String getMailAdmin() { return settings.get("duniter.mail.admin"); } @@ -106,7 +129,7 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { } public String getMailSubjectPrefix() { - return settings.get("duniter.mail.subject.prefix", "[Duniter4j ES]"); + return settings.get("duniter.mail.subject.prefix", "[Cesium+]"); } /* -- delegate methods -- */ @@ -151,6 +174,25 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { delegate.addI18nBundleName(bundleName); } + public Locale getI18nLocale() { + return delegate.getI18nLocale(); + } + + public KeyPair getNodeKeypair() { + initNodeKeyring(); + return this.nodeKeyPair; + } + + public boolean isRandomNodeKeypair() { + initNodeKeyring(); + return this.isRandomNodeKeyPair; + } + + public String getNodePubkey() { + initNodeKeyring(); + return this.nodePubkey; + } + /* -- protected methods -- */ @@ -158,5 +200,26 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { return "duniter4j-es-user-i18n"; } + protected void initNodeKeyring() { + if (this.nodeKeyPair != null) return; + if (StringUtils.isNotBlank(getKeyringSalt()) && + StringUtils.isNotBlank(getKeyringPassword())) { + this.nodeKeyPair = cryptoService.getKeyPair(getKeyringSalt(), getKeyringPassword()); + this.nodePubkey = CryptoUtils.encodeBase58(this.nodeKeyPair.getPubKey()); + this.isRandomNodeKeyPair = false; + } + else { + // Use a ramdom keypair + this.nodeKeyPair = cryptoService.getRandomKeypair(); + this.nodePubkey = CryptoUtils.encodeBase58(this.nodeKeyPair.getPubKey()); + this.isRandomNodeKeyPair = true; + + logger.warn(String.format("No keyring in config. salt/password (or keyring) is need to signed user event documents. Will use a generated key [%s]", this.nodePubkey)); + if (logger.isDebugEnabled()) { + logger.debug(String.format(" salt: " + getKeyringSalt().replaceAll(".", "*"))); + logger.debug(String.format("password: " + getKeyringPassword().replaceAll(".", "*"))); + } + } + } } diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/AdminService.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/AdminService.java new file mode 100644 index 00000000..e014f885 --- /dev/null +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/AdminService.java @@ -0,0 +1,105 @@ +package org.duniter.elasticsearch.user.service; + +/* + * #%L + * UCoin Java Client :: Core API + * %% + * Copyright (C) 2014 - 2015 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import org.duniter.core.service.CryptoService; +import org.duniter.core.util.Preconditions; +import org.duniter.core.util.StringUtils; +import org.duniter.elasticsearch.client.Duniter4jClient; +import org.duniter.elasticsearch.user.PluginSettings; +import org.duniter.elasticsearch.user.model.UserEvent; +import org.duniter.elasticsearch.user.model.UserProfile; +import org.elasticsearch.common.inject.Inject; +import org.nuiton.i18n.I18n; + +import java.util.Locale; + +/** + * Created by Benoit on 30/03/2015. + */ +public class AdminService extends AbstractService { + + private final UserEventService userEventService; + private final MailService mailService; + + @Inject + public AdminService(final Duniter4jClient client, + final PluginSettings pluginSettings, + final CryptoService cryptoService, + final UserEventService userEventService, + final MailService mailService) { + super("duniter.admin", client, pluginSettings, cryptoService); + this.userEventService = userEventService; + this.mailService = mailService; + } + + /** + * Notify cluster admin + */ + public void notifyAdmin(UserEvent event) { + Preconditions.checkNotNull(event); + + String nodePubkey = pluginSettings.getNodePubkey(); + + UserProfile adminProfile; + if (StringUtils.isNotBlank(nodePubkey) && !pluginSettings.isRandomNodeKeypair()) { + adminProfile = getUserProfile(nodePubkey, UserProfile.PROPERTY_EMAIL, UserProfile.PROPERTY_LOCALE); + } + else { + adminProfile = new UserProfile(); + } + + // Add new event to index + Locale locale = StringUtils.isNotBlank(adminProfile.getLocale()) ? + new Locale(adminProfile.getLocale()) : + I18n.getDefaultLocale(); + if (StringUtils.isNotBlank(nodePubkey)) { + event.setRecipient(nodePubkey); + userEventService.indexEvent(locale, event); + } + + // Send email to admin + String adminEmail = StringUtils.isNotBlank(adminProfile.getEmail()) ? + adminProfile.getEmail() : + pluginSettings.getMailAdmin(); + if (StringUtils.isNotBlank(adminEmail)) { + String subjectPrefix = pluginSettings.getMailSubjectPrefix(); + mailService.sendTextEmail( + I18n.l(locale, "duniter4j.event.subject."+event.getType().name(), subjectPrefix), + event.getLocalizedMessage(locale), + adminEmail); + } + } + + /* -- Internal methods -- */ + + private UserProfile getUserProfile(String pubkey, String... fieldnames) { + UserProfile result = client.getSourceByIdOrNull(UserService.INDEX, UserService.PROFILE_TYPE, pubkey, UserProfile.class, fieldnames); + if (result == null) result = new UserProfile(); + return result; + } + + + +} diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/BlockchainUserEventService.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/BlockchainUserEventService.java index 2c1a3ccf..3c2e5fe8 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/BlockchainUserEventService.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/BlockchainUserEventService.java @@ -63,6 +63,8 @@ public class BlockchainUserEventService extends AbstractService implements Chang public final UserEventService userEventService; + public final AdminService adminService; + public final ObjectMapper objectMapper; @@ -72,9 +74,11 @@ public class BlockchainUserEventService extends AbstractService implements Chang public BlockchainUserEventService(Duniter4jClient client, PluginSettings settings, CryptoService cryptoService, BlockchainService blockchainService, UserService userService, + AdminService adminService, UserEventService userEventService) { super("duniter.user.event.blockchain", client, settings, cryptoService); this.userService = userService; + this.adminService = adminService; this.userEventService = userEventService; this.objectMapper = JacksonUtils.newObjectMapper(); ChangeService.registerListener(this); @@ -150,8 +154,8 @@ public class BlockchainUserEventService extends AbstractService implements Chang // Send notify on reconnection if (errorNotified) { errorNotified = false; - userEventService.notifyAdmin(UserEvent.newBuilder(UserEvent.EventType.INFO, UserEventCodes.NODE_BMA_UP.name()) - .setMessage(I18n.n("duniter.event.NODE_BMA_UP"), + adminService.notifyAdmin(UserEvent.newBuilder(UserEvent.EventType.INFO, UserEventCodes.NODE_BMA_UP.name()) + .setMessage(I18n.n("duniter.user.event.NODE_BMA_UP"), pluginSettings.getNodeBmaHost(), String.valueOf(pluginSettings.getNodeBmaPort()), pluginSettings.getClusterName()) @@ -168,8 +172,8 @@ public class BlockchainUserEventService extends AbstractService implements Chang boolean wait = now - lastTimeUp < 60; if (!wait) { errorNotified = true; - userEventService.notifyAdmin(UserEvent.newBuilder(UserEvent.EventType.ERROR, UserEventCodes.NODE_BMA_DOWN.name()) - .setMessage(I18n.n("duniter.event.NODE_BMA_DOWN"), + adminService.notifyAdmin(UserEvent.newBuilder(UserEvent.EventType.ERROR, UserEventCodes.NODE_BMA_DOWN.name()) + .setMessage(I18n.n("duniter.user.event.NODE_BMA_DOWN"), pluginSettings.getNodeBmaHost(), String.valueOf(pluginSettings.getNodeBmaPort()), pluginSettings.getClusterName(), @@ -184,21 +188,21 @@ public class BlockchainUserEventService extends AbstractService implements Chang // Joiners if (CollectionUtils.isNotEmpty(block.getJoiners())) { for (BlockchainBlock.Joiner joiner: block.getJoiners()) { - notifyUserEvent(block, joiner.getPublicKey(), UserEventCodes.MEMBER_JOIN, I18n.n("duniter.user.event.ms.join"), block.getCurrency()); + notifyUserEvent(block, joiner.getPublicKey(), UserEventCodes.MEMBER_JOIN, I18n.n("duniter.user.event.MEMBER_JOIN"), block.getCurrency()); } } // Leavers if (CollectionUtils.isNotEmpty(block.getLeavers())) { for (BlockchainBlock.Joiner leaver: block.getJoiners()) { - notifyUserEvent(block, leaver.getPublicKey(), UserEventCodes.MEMBER_LEAVE, I18n.n("duniter.user.event.ms.leave"), block.getCurrency()); + notifyUserEvent(block, leaver.getPublicKey(), UserEventCodes.MEMBER_LEAVE, I18n.n("duniter.user.event.MEMBER_LEAVE"), block.getCurrency()); } } // Actives if (CollectionUtils.isNotEmpty(block.getActives())) { for (BlockchainBlock.Joiner active: block.getActives()) { - notifyUserEvent(block, active.getPublicKey(), UserEventCodes.MEMBER_ACTIVE, I18n.n("duniter.user.event.ms.active"), block.getCurrency()); + notifyUserEvent(block, active.getPublicKey(), UserEventCodes.MEMBER_ACTIVE, I18n.n("duniter.user.event.MEMBER_ACTIVE"), block.getCurrency()); } } @@ -239,7 +243,7 @@ public class BlockchainUserEventService extends AbstractService implements Chang if (parts.length >= 3 && parts[2].startsWith("SIG(")) { String receiver = parts[2].substring(4, parts[2].length() - 1); if (!senders.contains(receiver) && !receivers.contains(receiver)) { - notifyUserEvent(block, receiver, UserEventCodes.TX_RECEIVED, I18n.n("duniter.user.event.tx.received"), sendersPubkeys, senderNames); + notifyUserEvent(block, receiver, UserEventCodes.TX_RECEIVED, I18n.n("duniter.user.event.TX_RECEIVED"), sendersPubkeys, senderNames); receivers.add(receiver); } } @@ -250,7 +254,7 @@ public class BlockchainUserEventService extends AbstractService implements Chang String receiverNames = userService.joinNamesFromPubkeys(receivers, DEFAULT_PUBKEYS_SEPARATOR, true); String receiverPubkeys = ModelUtils.joinPubkeys(receivers, DEFAULT_PUBKEYS_SEPARATOR, false); for (String sender : senders) { - notifyUserEvent(block, sender, UserEventCodes.TX_SENT, I18n.n("duniter.user.event.tx.sent"), receiverPubkeys, receiverNames); + notifyUserEvent(block, sender, UserEventCodes.TX_SENT, I18n.n("duniter.user.event.TX_SENT"), receiverPubkeys, receiverNames); } } @@ -266,14 +270,14 @@ public class BlockchainUserEventService extends AbstractService implements Chang if (senderName == null) { senderName = ModelUtils.minifyPubkey(sender); } - notifyUserEvent(block, receiver, UserEventCodes.CERT_RECEIVED, I18n.n("duniter.user.event.cert.received"), sender, senderName); + notifyUserEvent(block, receiver, UserEventCodes.CERT_RECEIVED, I18n.n("duniter.user.event.CERT_RECEIVED"), sender, senderName); // Sent String receiverName = userService.getProfileTitle(receiver); if (receiverName == null) { receiverName = ModelUtils.minifyPubkey(receiver); } - notifyUserEvent(block, sender, UserEventCodes.CERT_SENT, I18n.n("duniter.user.event.cert.sent"), receiver, receiverName); + notifyUserEvent(block, sender, UserEventCodes.CERT_SENT, I18n.n("duniter.user.event.CERT_SENT"), receiver, receiverName); } private void notifyUserEvent(BlockchainBlock block, String pubkey, UserEventCodes code, String message, String... params) { diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/GroupService.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/GroupService.java index 51e6a058..53c0604b 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/GroupService.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/GroupService.java @@ -64,7 +64,7 @@ public class GroupService extends AbstractService { } /** - * Create index need for blockchain registry, if need + * Create index need for blockchain mail, if need */ public GroupService createIndexIfNotExists() { try { @@ -79,7 +79,7 @@ public class GroupService extends AbstractService { } /** - * Create index for registry + * Create index for mail * @throws JsonProcessingException */ public GroupService createIndex() throws JsonProcessingException { diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/HistoryService.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/HistoryService.java index 7df49596..e2004b8a 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/HistoryService.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/HistoryService.java @@ -59,7 +59,7 @@ public class HistoryService extends AbstractService { @Inject public HistoryService(Duniter4jClient client, PluginSettings settings, CryptoService cryptoService) { - super("gchange." + INDEX, client, settings, cryptoService); + super("subscription." + INDEX, client, settings, cryptoService); } /** @@ -77,7 +77,7 @@ public class HistoryService extends AbstractService { } /** - * Create index need for blockchain registry, if need + * Create index need for blockchain mail, if need */ public HistoryService createIndexIfNotExists() { try { @@ -93,7 +93,7 @@ public class HistoryService extends AbstractService { } /** - * Create index need for category registry + * Create index need for category mail * @throws JsonProcessingException */ public HistoryService createIndex() throws JsonProcessingException { @@ -117,9 +117,9 @@ public class HistoryService extends AbstractService { JsonNode actualObj = readAndVerifyIssuerSignature(recordJson); String issuer = actualObj.get(DeleteRecord.PROPERTY_ISSUER).asText(); - String index = actualObj.get(DeleteRecord.PROPERTY_INDEX).asText(); - String type = actualObj.get(DeleteRecord.PROPERTY_TYPE).asText(); - String id = actualObj.get(DeleteRecord.PROPERTY_ID).asText(); + String index = getMandatoryField(actualObj, DeleteRecord.PROPERTY_INDEX).asText(); + String type = getMandatoryField(actualObj,DeleteRecord.PROPERTY_TYPE).asText(); + String id = getMandatoryField(actualObj,DeleteRecord.PROPERTY_ID).asText(); if (!client.existsIndex(index)) { throw new NotFoundException(String.format("Index [%s] not exists.", index)); diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/MailService.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/MailService.java new file mode 100644 index 00000000..9b259dcb --- /dev/null +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/MailService.java @@ -0,0 +1,139 @@ +package org.duniter.elasticsearch.user.service; + +/* + * #%L + * UCoin Java Client :: Core API + * %% + * Copyright (C) 2014 - 2015 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import org.duniter.core.exception.TechnicalException; +import org.duniter.core.model.SmtpConfig; +import org.duniter.core.service.CryptoService; +import org.duniter.core.util.Preconditions; +import org.duniter.core.util.StringUtils; +import org.duniter.core.util.crypto.CryptoUtils; +import org.duniter.core.util.crypto.KeyPair; +import org.duniter.elasticsearch.client.Duniter4jClient; +import org.duniter.elasticsearch.service.changes.ChangeService; +import org.duniter.elasticsearch.user.PluginSettings; +import org.duniter.elasticsearch.user.model.UserEvent; +import org.duniter.elasticsearch.user.model.UserProfile; +import org.elasticsearch.common.inject.Inject; +import org.nuiton.i18n.I18n; + +import javax.activation.CommandMap; +import javax.activation.MailcapCommandMap; +import java.util.Locale; + +/** + * Created by Benoit on 30/03/2015. + */ +public class MailService extends AbstractService { + + private final org.duniter.core.service.MailService delegate; + + private final boolean enable; + + @Inject + public MailService(final Duniter4jClient client, + final PluginSettings pluginSettings, + final CryptoService cryptoService, + final org.duniter.core.service.MailService delegate) { + super("duniter.mail", client, pluginSettings, cryptoService); + this.delegate = delegate; + this.enable = pluginSettings.getMailEnable(); + // Init delegated service + if (this.enable) { + delegate.setSmtpConfig(createConfig(pluginSettings)); + } + } + + /** + * Send email + */ + public void sendTextEmail(String subject, String textContent, String... recipients) { + if (!this.enable) return; + + try { + delegate.sendTextEmail(subject, textContent, recipients); + } + catch(TechnicalException e) { + if (logger.isDebugEnabled()) { + logger.error(e.getMessage(), e); + } + else { + logger.error(e.getMessage()); + } + } + } + + /** + * Send email + */ + public void sendHtmlEmail(String subject, String htmlContent, String... recipients) { + if (!this.enable) return; + + try { + delegate.sendHtmlEmail(subject, htmlContent, recipients); + } + catch(TechnicalException e) { + if (logger.isDebugEnabled()) { + logger.error(e.getMessage(), e); + } + else { + logger.error(e.getMessage()); + } + } + } + + /** + * Send email + */ + public void sendHtmlEmailWithText(String subject, String textContent, String htmlContent, String... recipients) { + if (!this.enable) return; + + try { + delegate.sendHtmlEmailWithText(subject, textContent, htmlContent, recipients); + } + catch(TechnicalException e) { + if (logger.isDebugEnabled()) { + logger.error(e.getMessage(), e); + } + else { + logger.error(e.getMessage()); + } + } + } + + /* -- internal methods -- */ + + protected SmtpConfig createConfig(PluginSettings pluginSettings) { + SmtpConfig config = new SmtpConfig(); + config.setSmtpHost(pluginSettings.getMailSmtpHost()); + config.setSmtpPort(pluginSettings.getMailSmtpPort()); + config.setSmtpUsername(pluginSettings.getMailSmtpUsername()); + config.setSmtpPassword(pluginSettings.getMailSmtpPassword()); + config.setSenderAddress(pluginSettings.getMailFrom()); + config.setStartTLS(pluginSettings.isMailSmtpStartTLS()); + config.setUseSsl(pluginSettings.isMailSmtpUseSSL()); + return config; + } + +} diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/MessageService.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/MessageService.java index 5a4a2a38..b1424cd2 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/MessageService.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/MessageService.java @@ -84,7 +84,7 @@ public class MessageService extends AbstractService { } /** - * Create index need for blockchain registry, if need + * Create index need for blockchain mail, if need */ public MessageService createIndexIfNotExists() { try { @@ -100,7 +100,7 @@ public class MessageService extends AbstractService { } /** - * Create index need for category registry + * Create index need for category mail * @throws JsonProcessingException */ public MessageService createIndex() throws JsonProcessingException { @@ -231,6 +231,18 @@ public class MessageService extends AbstractService { .field("index", "not_analyzed") .endObject() + // hash + .startObject("hash") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + + // signature + .startObject("signature") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + // read_signature .startObject("read_signature") .field("type", "string") diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/ServiceModule.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/ServiceModule.java index e1986861..af46406a 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/ServiceModule.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/ServiceModule.java @@ -35,6 +35,8 @@ public class ServiceModule extends AbstractModule implements Module { bind(UserService.class).asEagerSingleton(); bind(GroupService.class).asEagerSingleton(); + bind(AdminService.class).asEagerSingleton(); + bind(MailService.class).asEagerSingleton(); bind(UserEventService.class).asEagerSingleton(); bind(UserInvitationService.class).asEagerSingleton(); diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserEventService.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserEventService.java index eee64c1b..656790b3 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserEventService.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserEventService.java @@ -26,13 +26,14 @@ package org.duniter.elasticsearch.user.service; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableList; +import org.duniter.core.client.model.bma.jackson.JacksonUtils; +import org.duniter.core.client.model.elasticsearch.Record; import org.duniter.core.exception.TechnicalException; import org.duniter.core.service.CryptoService; import org.duniter.core.service.MailService; +import org.duniter.core.util.CollectionUtils; import org.duniter.core.util.Preconditions; import org.duniter.core.util.StringUtils; -import org.duniter.core.util.crypto.CryptoUtils; -import org.duniter.core.util.crypto.KeyPair; import org.duniter.elasticsearch.client.Duniter4jClient; import org.duniter.elasticsearch.exception.InvalidSignatureException; import org.duniter.elasticsearch.service.changes.ChangeEvent; @@ -51,17 +52,17 @@ import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.update.UpdateResponse; -import org.elasticsearch.client.Client; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; -import org.nuiton.i18n.I18n; import java.io.IOException; import java.util.*; +import java.util.stream.Collectors; /** * Created by Benoit on 30/03/2015. @@ -96,9 +97,6 @@ public class UserEventService extends AbstractService implements ChangeService.C private final MailService mailService; private final ThreadPool threadPool; - public final KeyPair nodeKeyPair; - public final String nodePubkey; - public final boolean mailEnable; public final boolean trace; @Inject @@ -110,53 +108,12 @@ public class UserEventService extends AbstractService implements ChangeService.C super("duniter.user.event", client, pluginSettings, cryptoService); this.mailService = mailService; this.threadPool = threadPool; - this.nodeKeyPair = getNodeKeyPairOrNull(pluginSettings); - this.nodePubkey = getNodePubKey(nodeKeyPair); - this.mailEnable = pluginSettings.getMailEnable(); this.trace = logger.isTraceEnabled(); - if (!this.mailEnable && this.trace) { - logger.trace("Mail disable"); - } ChangeService.registerListener(this); } - /** - * Notify cluster admin - */ - public void notifyAdmin(UserEvent event) { - Preconditions.checkNotNull(event); - - UserProfile adminProfile; - if (StringUtils.isNotBlank(nodePubkey)) { - adminProfile = getUserProfile(nodePubkey, UserProfile.PROPERTY_EMAIL, UserProfile.PROPERTY_LOCALE); - } - else { - adminProfile = new UserProfile(); - } - - // Add new event to index - Locale locale = StringUtils.isNotBlank(adminProfile.getLocale()) ? - new Locale(adminProfile.getLocale()) : - I18n.getDefaultLocale(); - if (StringUtils.isNotBlank(nodePubkey)) { - event.setRecipient(nodePubkey); - indexEvent(locale, event); - } - - // Send email to admin - String adminEmail = StringUtils.isNotBlank(adminProfile.getEmail()) ? - adminProfile.getEmail() : - pluginSettings.getMailAdmin(); - if (StringUtils.isNotBlank(adminEmail)) { - String subjectPrefix = pluginSettings.getMailSubjectPrefix(); - sendEmail(adminEmail, - I18n.l(locale, "duniter4j.event.subject."+event.getType().name(), subjectPrefix), - event.getLocalizedMessage(locale)); - } - } - /** * Notify a user */ @@ -179,6 +136,8 @@ public class UserEventService extends AbstractService implements ChangeService.C Preconditions.checkNotNull(event.getType()); Preconditions.checkNotNull(event.getCode()); + String nodePubkey = pluginSettings.getNodePubkey(); + // Generate json String eventJson; if (StringUtils.isNotBlank(nodePubkey)) { @@ -186,13 +145,18 @@ public class UserEventService extends AbstractService implements ChangeService.C signedEvent.setMessage(event.getLocalizedMessage(locale)); // set issuer, hash, signature signedEvent.setIssuer(nodePubkey); - String hash = cryptoService.hash(toJson(signedEvent)); + + // Add hash + String hash = cryptoService.hash(toJson(signedEvent, true)); signedEvent.setHash(hash); - String signature = cryptoService.sign(toJson(signedEvent), nodeKeyPair.getSecKey()); + + // Add signature + String signature = cryptoService.sign(toJson(signedEvent, true), pluginSettings.getNodeKeypair().getSecKey()); signedEvent.setSignature(signature); + eventJson = toJson(signedEvent); } else { - logger.debug("Could not generate hash for new user event (no keyring)"); + logger.warn("Could not generate hash for new user event (no keyring)"); // Node has not keyring: do NOT sign it eventJson = event.toJson(locale); } @@ -254,8 +218,40 @@ public class UserEventService extends AbstractService implements ChangeService.C .execute(); } + + + public List<UserEvent> getUserEvents(String pubkey, Long lastTime, String[] includesCodes, String[] excludesCodes) { + + BoolQueryBuilder query = QueryBuilders.boolQuery() + .must(QueryBuilders.termQuery(UserEvent.PROPERTY_RECIPIENT, pubkey)); + if (lastTime != null) { + query.must(QueryBuilders.rangeQuery(UserEvent.PROPERTY_TIME).gt(lastTime)); + } + + if (CollectionUtils.isNotEmpty(includesCodes)) { + query.must(QueryBuilders.termsQuery(UserEvent.PROPERTY_CODE, includesCodes)); + } + if (CollectionUtils.isNotEmpty(excludesCodes)) { + query.mustNot(QueryBuilders.termsQuery(UserEvent.PROPERTY_CODE, excludesCodes)); + } + + SearchResponse response = client.prepareSearch(INDEX) + .setTypes(EVENT_TYPE) + .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) + .setFetchSource(true) + .setQuery(query) + .get(); + + + return Arrays.asList(response.getHits().getHits()).stream() + .map(searchHit -> client.readSourceOrNull(searchHit, UserEvent.class)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + /* -- Internal methods -- */ + public static XContentBuilder createEventType() { try { XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject(EVENT_TYPE) @@ -356,54 +352,12 @@ public class UserEventService extends AbstractService implements ChangeService.C } } - - /** - * Send email - */ - private void sendEmail(String recipients, String subject, String textContent) { - if (!this.mailEnable) return; - - String smtpHost = pluginSettings.getMailSmtpHost(); - int smtpPort = pluginSettings.getMailSmtpPort(); - String smtpUsername = pluginSettings.getMailSmtpUsername(); - String smtpPassword = pluginSettings.getMailSmtpPassword(); - String from = pluginSettings.getMailFrom(); - - try { - mailService.sendTextEmail(smtpHost, smtpPort, smtpUsername, smtpPassword, from, recipients, subject, textContent); - } - catch(TechnicalException e) { - logger.error(String.format("Could not send email: %s", e.getMessage())/*, e*/); - } - } - - private KeyPair getNodeKeyPairOrNull(PluginSettings pluginSettings) { - KeyPair result; - if (StringUtils.isNotBlank(pluginSettings.getKeyringSalt()) && - StringUtils.isNotBlank(pluginSettings.getKeyringPassword())) { - result = cryptoService.getKeyPair(pluginSettings.getKeyringSalt(), - pluginSettings.getKeyringPassword()); - } - else { - // Use a ramdom keypair - result = cryptoService.getRandomKeypair(); - logger.warn(String.format("No keyring in config. salt/password (or keyring) is need to signed user event documents. Will use a generated key [%s]", getNodePubKey(result))); - if (logger.isDebugEnabled()) { - logger.debug(String.format(" salt: " + pluginSettings.getKeyringSalt().replaceAll(".", "*"))); - logger.debug(String.format("password: " + pluginSettings.getKeyringPassword().replaceAll(".", "*"))); - } - } - + private UserProfile getUserProfile(String pubkey, String... fieldnames) { + UserProfile result = client.getSourceByIdOrNull(UserService.INDEX, UserService.PROFILE_TYPE, pubkey, UserProfile.class, fieldnames); + if (result == null) result = new UserProfile(); return result; } - private String getNodePubKey(KeyPair nodeKeyPair) { - if (nodeKeyPair == null) return null; - return CryptoUtils.encodeBase58(nodeKeyPair.getPubKey()); - } - - - private void doDeleteEventsByReference(final UserEvent.Reference reference) { // Prepare search request @@ -461,19 +415,23 @@ public class UserEventService extends AbstractService implements ChangeService.C } } - private UserProfile getUserProfile(String pubkey, String... fieldnames) { - UserProfile result = client.getSourceByIdOrNull(UserService.INDEX, UserService.PROFILE_TYPE, pubkey, UserProfile.class, fieldnames); - if (result == null) result = new UserProfile(); - return result; - } private UserProfile getUserProfileOrNull(String pubkey, String... fieldnames) { return client.getSourceByIdOrNull(UserService.INDEX, UserService.PROFILE_TYPE, pubkey, UserProfile.class, fieldnames); } private String toJson(UserEvent userEvent) { + return toJson(userEvent, false); + } + + private String toJson(UserEvent userEvent, boolean cleanHashAndSignature) { try { - return objectMapper.writeValueAsString(userEvent); + String json = objectMapper.writeValueAsString(userEvent); + if (cleanHashAndSignature) { + json = JacksonUtils.removeAttribute(json, Record.PROPERTY_SIGNATURE); + json = JacksonUtils.removeAttribute(json, Record.PROPERTY_HASH); + } + return json; } catch(JsonProcessingException e) { throw new TechnicalException("Unable to serialize UserEvent object", e); } diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserInvitationService.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserInvitationService.java index 441b7e31..f5e393b8 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserInvitationService.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserInvitationService.java @@ -71,7 +71,7 @@ public class UserInvitationService extends AbstractService { } /** - * Create index need for blockchain registry, if need + * Create index need for blockchain mail, if need */ public UserInvitationService createIndexIfNotExists() { try { @@ -87,7 +87,7 @@ public class UserInvitationService extends AbstractService { } /** - * Create index need for category registry + * Create index need for category mail * @throws JsonProcessingException */ public UserInvitationService createIndex() throws JsonProcessingException { @@ -126,7 +126,7 @@ public class UserInvitationService extends AbstractService { // Notify recipient userEventService.notifyUser(UserEvent.newBuilder(UserEvent.EventType.INFO, UserEventCodes.INVITATION_TO_CERTIFY.name()) .setRecipient(recipient) - .setMessage(I18n.n("duniter.invitation.cert.received"), issuer, ModelUtils.minifyPubkey(issuer)) + .setMessage(I18n.n("duniter.user.event.INVITATION_TO_CERTIFY"), issuer, ModelUtils.minifyPubkey(issuer)) .setTime(time) .setReference(INDEX, CERTIFICATION_TYPE, invitationId) .build()); diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserService.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserService.java index 11f62c68..f827dd28 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserService.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/service/UserService.java @@ -67,7 +67,7 @@ public class UserService extends AbstractService { } /** - * Create index need for blockchain registry, if need + * Create index need for blockchain mail, if need */ public UserService createIndexIfNotExists() { try { @@ -82,7 +82,7 @@ public class UserService extends AbstractService { } /** - * Create index for registry + * Create index for mail * @throws JsonProcessingException */ public UserService createIndex() throws JsonProcessingException { diff --git a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/websocket/WebsocketUserEventEndPoint.java b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/websocket/WebsocketUserEventEndPoint.java index 5037ac3e..552300ca 100644 --- a/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/websocket/WebsocketUserEventEndPoint.java +++ b/duniter4j-es-user/src/main/java/org/duniter/elasticsearch/user/websocket/WebsocketUserEventEndPoint.java @@ -40,6 +40,7 @@ package org.duniter.elasticsearch.user.websocket; import org.duniter.core.client.model.bma.Constants; import org.duniter.core.util.StringUtils; +import org.duniter.elasticsearch.user.PluginSettings; import org.duniter.elasticsearch.user.model.UserEvent; import org.duniter.elasticsearch.user.service.UserEventService; import org.duniter.elasticsearch.websocket.WebSocketServer; @@ -57,11 +58,15 @@ import java.util.regex.Pattern; @ServerEndpoint(value = "/event/user/{pubkey}/{locale}") public class WebsocketUserEventEndPoint implements UserEventService.UserEventListener { + public static Locale defaultLocale; + public static class Init { @Inject - public Init(WebSocketServer webSocketServer) { + public Init(WebSocketServer webSocketServer, PluginSettings pluginSettings) { webSocketServer.addEndPoint(WebsocketUserEventEndPoint.class); + defaultLocale = pluginSettings.getI18nLocale(); + if (defaultLocale == null) defaultLocale = new Locale("en", "GB"); } } @@ -78,7 +83,7 @@ public class WebsocketUserEventEndPoint implements UserEventService.UserEventLis public void onOpen(Session session) { this.session = session; this.pubkey = session.getPathParameters() != null ? session.getPathParameters().get(PATH_PARAM_PUBKEY) : null; - this.locale = new Locale(session.getPathParameters() != null ? session.getPathParameters().get(PATH_PARAM_LOCALE) : "fr"); + this.locale = session.getPathParameters() != null ? new Locale(session.getPathParameters().get(PATH_PARAM_LOCALE)) : defaultLocale; if (StringUtils.isBlank(pubkey) || !PUBKEY_PATTERN.matcher(pubkey).matches()) { try { diff --git a/duniter4j-es-user/src/main/resources/i18n/duniter4j-es-user_en_GB.properties b/duniter4j-es-user/src/main/resources/i18n/duniter4j-es-user_en_GB.properties index e149f6a6..829d6574 100644 --- a/duniter4j-es-user/src/main/resources/i18n/duniter4j-es-user_en_GB.properties +++ b/duniter4j-es-user/src/main/resources/i18n/duniter4j-es-user_en_GB.properties @@ -1,7 +1,15 @@ -duniter.event.NODE_BMA_DOWN=Duniter node [%1$s\:%2$s] is DOWN\: no access from ES node [%3$s]. Last connexion at %4$d. Blockchain indexation waiting. -duniter.event.NODE_BMA_UP=Duniter node [%1$s\:%2$s] is UP again. -duniter.event.NODE_STARTED=Node started on cluster Duniter4j ES [%s] duniter.invitation.cert.received= +duniter.user.event.CERT_RECEIVED= +duniter.user.event.CERT_SENT= +duniter.user.event.INVITATION_TO_CERTIFY= +duniter.user.event.MEMBER_ACTIVE= +duniter.user.event.MEMBER_JOIN= +duniter.user.event.MEMBER_LEAVE= +duniter.user.event.NODE_BMA_DOWN=Duniter node [%1$s\:%2$s] is DOWN\: no access from ES node [%3$s]. Last connexion at %4$d. Blockchain indexation waiting. +duniter.user.event.NODE_BMA_UP=Duniter node [%1$s\:%2$s] is UP again. +duniter.user.event.NODE_STARTED=Node started on cluster Duniter4j ES [%s] +duniter.user.event.TX_RECEIVED= +duniter.user.event.TX_SENT= duniter.user.event.active= duniter.user.event.cert.received= duniter.user.event.cert.sent= diff --git a/duniter4j-es-user/src/main/resources/i18n/duniter4j-es-user_fr_FR.properties b/duniter4j-es-user/src/main/resources/i18n/duniter4j-es-user_fr_FR.properties index ab9df823..74e0b613 100644 --- a/duniter4j-es-user/src/main/resources/i18n/duniter4j-es-user_fr_FR.properties +++ b/duniter4j-es-user/src/main/resources/i18n/duniter4j-es-user_fr_FR.properties @@ -1,15 +1,15 @@ -duniter.event.NODE_BMA_DOWN=Noeud Duniter [%1$s\:%2$s] non joignable, depuis le noeud ES API [%3$s]. Dernière connexion à %4$d. Indexation de blockchain en attente. -duniter.event.NODE_BMA_UP=Noeud Duniter [%1$s\:%2$s] à nouveau accessible. -duniter.event.NODE_STARTED=Noeud ES API démarré sur le cluster Duniter [%1$s] -duniter.invitation.cert.received=%2$s vous invite à certifier une identité. -duniter.user.event.cert.received=%2$s vous a certifié (certification prise en compte). -duniter.user.event.cert.sent=Votre certification de %2$s a été pris en compte. +duniter.user.event.CERT_RECEIVED=%2$s vous a certifié (certification prise en compte). +duniter.user.event.CERT_SENT=Votre certification de %2$s a été pris en compte. +duniter.user.event.INVITATION_TO_CERTIFY=%2$s vous invite à certifier une identité. +duniter.user.event.MEMBER_ACTIVE=Votre adhésion comme membre a bien été renouvellée +duniter.user.event.MEMBER_JOIN=Vous êtes maintenant membre de la monnaie +duniter.user.event.MEMBER_LEAVE=Votre adhésion comme membre à expirée +duniter.user.event.NODE_BMA_DOWN=Noeud Duniter [%1$s\:%2$s] non joignable, depuis le noeud ES API [%3$s]. Dernière connexion à %4$d. Indexation de blockchain en attente. +duniter.user.event.NODE_BMA_UP=Noeud Duniter [%1$s\:%2$s] à nouveau accessible. +duniter.user.event.NODE_STARTED=Noeud ES API démarré sur le cluster Duniter [%1$s] +duniter.user.event.TX_RECEIVED=Vous avez recu un paiement de %2$s +duniter.user.event.TX_SENT=Votre paiement à %2$s a bien été executé duniter.user.event.message.received=Vous avez reçu un message de %2$s -duniter.user.event.ms.active=Votre adhésion comme membre a bien été renouvellée -duniter.user.event.ms.join=Vous êtes maintenant membre de la monnaie -duniter.user.event.ms.leave=Votre adhésion comme membre à expirée -duniter.user.event.tx.received=Vous avez recu un paiement de %2$s -duniter.user.event.tx.sent=Votre paiement à %2$s a bien été executé duniter4j.event.subject.ERROR=%s Message d'erreur duniter4j.event.subject.INFO=%s Message d'information duniter4j.event.subject.WARN=%s Message d'avertissement diff --git a/pom.xml b/pom.xml index 5baa771d..f2f19db9 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ <slf4j.version>1.7.5</slf4j.version> <guava.version>18.0</guava.version> <xml-apis.version>2.0.2</xml-apis.version> - <kalium.version>0.5.0</kalium.version> + <kalium.version>0.5.1-SNAPSHOT</kalium.version> <scrypt.version>1.4.0</scrypt.version> <elasticsearch.version>2.3.3</elasticsearch.version> <jna.version>4.1.0</jna.version> @@ -107,7 +107,7 @@ <module>duniter4j-client</module> <module>duniter4j-es-core</module> <module>duniter4j-es-user</module> - <module>duniter4j-es-gchange</module> + <module>duniter4j-es-subscription</module> <module>duniter4j-es-assembly</module> </modules> @@ -150,6 +150,11 @@ <artifactId>commons-lang3</artifactId> <version>3.1</version> </dependency> + <dependency> + <groupId>org.antlr</groupId> + <artifactId>stringtemplate</artifactId> + <version>4.0.2</version> + </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> -- GitLab