Pollen-commits
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- 3196 discussions
Author: tchemit
Date: 2013-06-14 11:22:03 +0200 (Fri, 14 Jun 2013)
New Revision: 3826
Url: http://chorem.org/projects/pollen/repository/revisions/3826
Log:
remove legacy modules
Removed:
trunk/pollen-persistence-legacy/
trunk/pollen-services-legacy/
trunk/pollen-ui-struts2/
1
0
Author: tchemit
Date: 2013-06-14 11:19:15 +0200 (Fri, 14 Jun 2013)
New Revision: 3825
Url: http://chorem.org/projects/pollen/repository/revisions/3825
Log:
Branch pollen-2.0 is the *new* trunk
Added:
trunk/
Removed:
branches/pollen-2.0/
Property changes on: trunk
___________________________________________________________________
Added: svn:ignore
+ target
nbactions.xml
.settings
.classpath
.project
*.ipr
*.iws
*.iml
.idea
atlassian-ide-plugin.xml
Added: svn:mergeinfo
+
1
0
Author: tchemit
Date: 2013-06-14 11:18:12 +0200 (Fri, 14 Jun 2013)
New Revision: 3824
Url: http://chorem.org/projects/pollen/repository/revisions/3824
Log:
Trunk goes to a branche (you never know...)
Added:
branches/pollen-1.5.x/
Removed:
trunk/
Property changes on: branches/pollen-1.5.x
___________________________________________________________________
Added: svn:ignore
+ target
nbactions.xml
.settings
.classpath
.project
*.ipr
*.iws
*.iml
.idea
atlassian-ide-plugin.xml
Added: svn:mergeinfo
+
1
0
Author: tchemit
Date: 2013-06-14 11:12:59 +0200 (Fri, 14 Jun 2013)
New Revision: 3823
Url: http://chorem.org/projects/pollen/repository/revisions/3823
Log:
- prepare new module layout
- implements FavoriteList service
- begin of security implementation
Added:
branches/pollen-2.0/pollen-rest-api/src/it/
branches/pollen-2.0/pollen-rest-api/src/it/pom/
branches/pollen-2.0/pollen-rest-api/src/it/pom/pom.xml
branches/pollen-2.0/pollen-rest-api/src/it/user/
branches/pollen-2.0/pollen-rest-api/src/it/user/README.txt
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenSecurityFilter.java
branches/pollen-2.0/pollen-services-legacy/
branches/pollen-2.0/pollen-services/
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/DefaultPollenServiceContext.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollResult.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenFixtures.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenSecurityContext.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenServiceContext.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenServiceSupport.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenTechnicalException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListImportException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberEmailAlreadyUsedException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNameAlreadyUsedException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNotOwnedByFavoriteListException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNameAlreadyUsedException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNotOwnedByUserException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/InvalidSessionTokenException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/package-info.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/AbstractPollenService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/AuthService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/CommentService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/EmailService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/FixturesService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/UserService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteCountingService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java
branches/pollen-2.0/pollen-services/src/main/resources/fixtures.yaml
branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java
branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/UserServiceTest.java
Removed:
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/BookmarkableDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoteDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoterListDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoterListMemberDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/AbstractJpaPollenEntity.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/BookmarkableEntity.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Choice.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/ChoiceEntity.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Comment.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/CommentEntity.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/JpaPollenEntity.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Poll.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollEntity.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Vote.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoteEntity.java
branches/pollen-2.0/pollen-persistence/src/test/java/org/chorem/pollen/persistence/entity/PollenEntitiesTest.java
branches/pollen-2.0/pollen-service/
branches/pollen-2.0/pollen-services/
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/AbstractPollenService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/AuthService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/CommentService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/EmailService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/FavoriteListService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/FixturesService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollResult.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenFixtures.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenServiceContext.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenServiceSupport.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenTechnicalException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/UserService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/VoteCountingService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/VoteService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/VoterListService.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/config/
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/exception/
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/package-info.java
branches/pollen-2.0/pollen-services/src/main/resources/fixtures.yaml
branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java
branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/UserServiceTest.java
Modified:
branches/pollen-2.0/pollen-persistence-legacy/pom.xml
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenEntityIdFactory.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/ChoiceDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/ChoiceJpaDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/CommentDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/CommentJpaDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollJpaDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserJpaDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenJpaDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoteJpaDao.java
branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties
branches/pollen-2.0/pollen-rest-api/pom.xml
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenApplicationContext.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenRender.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceContextFilter.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServices.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/AuthService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteCountingService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java
branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping
branches/pollen-2.0/pollen-rest-api/src/main/webapp/WEB-INF/web.xml
branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/AbstractPollenRestApiTest.java
branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/FakePollenServiceContext.java
branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/UserServiceTest.java
branches/pollen-2.0/pollen-rest-api/src/test/resources/pollen.properties
branches/pollen-2.0/pollen-services/pom.xml
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServiceConfig.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServiceConfigOption.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/package-info.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/EntityNotFoundException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserEmailAlreadyUsedException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserInvalidEmailActiviationTokenException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserInvalidPasswordException.java
branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserLoginAlreadyUsedException.java
branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/FakePollenServiceContext.java
branches/pollen-2.0/pom.xml
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenEntityIdFactory.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenEntityIdFactory.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenEntityIdFactory.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,10 +1,14 @@
package org.chorem.pollen.persistence;
import com.google.common.base.Preconditions;
-import org.chorem.pollen.persistence.entity.PollenEntities;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
import org.nuiton.jpa.api.JpaEntity;
import org.nuiton.jpa.api.JpaEntityIdFactory;
+import java.util.UUID;
+
/**
* TODO
*
@@ -13,10 +17,29 @@
*/
public class PollenEntityIdFactory implements JpaEntityIdFactory {
+ public static String generateId() {
+
+ // generate uuid
+ String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+
+ // decode in hexa base
+ byte[] decode;
+ try {
+ decode = Hex.decodeHex(uuid.toCharArray());
+ } catch (DecoderException e) {
+ // can't happen!
+ throw new RuntimeException(e);
+ }
+
+ // encode it in base64 (url safe version)
+ String result = Base64.encodeBase64URLSafeString(decode);
+ return result;
+ }
+
@Override
public String newId(JpaEntity entity) {
Preconditions.checkNotNull(entity);
- return entity.getClass().getName() + '#' + PollenEntities.generateId();
+ return generateId();
}
}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/BookmarkableDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/BookmarkableDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/BookmarkableDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,37 +0,0 @@
-package org.chorem.pollen.persistence.dao;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.nuiton.jpa.api.JpaEntity;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface BookmarkableDao<E extends JpaEntity> {
-
- E findBySimpleId(String simpleId);
-}
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/ChoiceDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/ChoiceDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/ChoiceDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,13 +23,11 @@
* #L%
*/
-import org.chorem.pollen.persistence.entity.Choice;
-
/**
* TODO
*
* @author tchemit <chemit(a)codelutin.com>
* @since 2.0
*/
-public interface ChoiceDao extends BookmarkableDao<Choice> {
+public interface ChoiceDao {
}
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/ChoiceJpaDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/ChoiceJpaDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/ChoiceJpaDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,9 +23,6 @@
* #L%
*/
-import org.chorem.pollen.persistence.entity.Choice;
-import org.chorem.pollen.persistence.entity.PollenEntities;
-
import javax.persistence.EntityManager;
public class ChoiceJpaDao extends AbstractChoiceJpaDao {
@@ -34,10 +31,4 @@
super(entityManager);
}
- @Override
- public Choice findBySimpleId(String simpleId) {
- String id = PollenEntities.getEntityId(getEntityClass(), simpleId);
- return findById(id);
- }
-
} //ChoiceJpaDao
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/CommentDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/CommentDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/CommentDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,13 +23,11 @@
* #L%
*/
-import org.chorem.pollen.persistence.entity.Comment;
-
/**
* TODO
*
* @author tchemit <chemit(a)codelutin.com>
* @since 2.0
*/
-public interface CommentDao extends BookmarkableDao<Comment> {
+public interface CommentDao {
}
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/CommentJpaDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/CommentJpaDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/CommentJpaDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,9 +23,6 @@
* #L%
*/
-import org.chorem.pollen.persistence.entity.Comment;
-import org.chorem.pollen.persistence.entity.PollenEntities;
-
import javax.persistence.EntityManager;
public class CommentJpaDao extends AbstractCommentJpaDao {
@@ -34,10 +31,4 @@
super(entityManager);
}
- @Override
- public Comment findBySimpleId(String simpleId) {
- String id = PollenEntities.getEntityId(getEntityClass(), simpleId);
- return findById(id);
- }
-
} //CommentJpaDao
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -33,7 +33,7 @@
* @author tchemit <chemit(a)codelutin.com>
* @since 2.0
*/
-public interface PollDao extends BookmarkableDao<Poll> {
+public interface PollDao {
Set<Poll> findAllCreated(String userId);
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollJpaDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollJpaDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollJpaDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -25,7 +25,6 @@
import com.google.common.collect.Sets;
import org.chorem.pollen.persistence.entity.Poll;
-import org.chorem.pollen.persistence.entity.PollenEntities;
import javax.persistence.EntityManager;
import java.util.Set;
@@ -60,10 +59,5 @@
return Sets.newHashSet();
}
- @Override
- public Poll findBySimpleId(String simpleId) {
- String id = PollenEntities.getEntityId(getEntityClass(), simpleId);
- return findById(id);
- }
} //PollJpaDao
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserJpaDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserJpaDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserJpaDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -26,7 +26,6 @@
import org.chorem.pollen.persistence.entity.PollenUser;
import javax.persistence.EntityManager;
-import javax.persistence.TypedQuery;
/**
* TODO
@@ -41,23 +40,6 @@
}
@Override
- public PollenUser findByLogin(String login) {
- TypedQuery<PollenUser> query =
- createQuery(PollenUser.PROPERTY_LOGIN, login);
- PollenUser result = findUniqueOrNull(query);
-
- return result;
- }
-
- @Override
- public PollenUser findByEmail(String email) {
- TypedQuery<PollenUser> query =
- createQuery(PollenUser.PROPERTY_EMAIL, email);
- PollenUser result = findUniqueOrNull(query);
- return result;
- }
-
- @Override
public boolean loginExists(String login) {
PollenUser user = findByLogin(login);
return user != null;
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenJpaDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenJpaDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenJpaDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,10 +23,7 @@
* #L%
*/
-import org.chorem.pollen.persistence.entity.SessionToken;
-
import javax.persistence.EntityManager;
-import javax.persistence.TypedQuery;
/**
* TODO
@@ -40,11 +37,4 @@
super(entityManager);
}
- @Override
- public SessionToken findByToken(String token) {
- TypedQuery<SessionToken> query = createQuery(SessionToken.PROPERTY_TOKEN, token);
- SessionToken result = findUniqueOrNull(query);
- return result;
- }
-
} //SessionTokenJpaDao
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoteDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoteDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoteDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,35 +0,0 @@
-package org.chorem.pollen.persistence.dao;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.chorem.pollen.persistence.entity.Vote;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface VoteDao extends BookmarkableDao<Vote> {
-}
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoteJpaDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoteJpaDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoteJpaDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,9 +23,6 @@
* #L%
*/
-import org.chorem.pollen.persistence.entity.PollenEntities;
-import org.chorem.pollen.persistence.entity.Vote;
-
import javax.persistence.EntityManager;
public class VoteJpaDao extends AbstractVoteJpaDao {
@@ -34,10 +31,4 @@
super(entityManager);
}
- @Override
- public Vote findBySimpleId(String simpleId) {
- String id = PollenEntities.getEntityId(getEntityClass(), simpleId);
- return findById(id);
- }
-
} //VoteJpaDao
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoterListDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoterListDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoterListDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,33 +0,0 @@
-package org.chorem.pollen.persistence.dao;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface VoterListDao {
-}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoterListMemberDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoterListMemberDao.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/VoterListMemberDao.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,34 +0,0 @@
-package org.chorem.pollen.persistence.dao;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface VoterListMemberDao {
-
-}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/AbstractJpaPollenEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/AbstractJpaPollenEntity.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/AbstractJpaPollenEntity.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,44 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.nuiton.jpa.api.AbstractJpaEntity;
-
-import java.io.Serializable;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public abstract class AbstractJpaPollenEntity extends AbstractJpaEntity implements JpaPollenEntity {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public String getSimpleId() {
- return PollenEntities.getSimpleId(this);
- }
-}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/BookmarkableEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/BookmarkableEntity.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/BookmarkableEntity.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,41 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface BookmarkableEntity {
-
- String getId();
-
- String getSimpleId();
-
-// PollenUser getPollenUser();
-
-// void setPollenUser(PollenUser pollenUser);
-}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Choice.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Choice.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Choice.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,43 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import javax.persistence.Entity;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-@Entity
-public class Choice extends AbstractJpaChoice {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public String getSimpleId() {
- return PollenEntities.getSimpleId(this);
- }
-} //Choice
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/ChoiceEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/ChoiceEntity.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/ChoiceEntity.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,33 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface ChoiceEntity extends BookmarkableEntity {
-}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Comment.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Comment.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Comment.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,43 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import javax.persistence.Entity;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-@Entity
-public class Comment extends AbstractJpaComment {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public String getSimpleId() {
- return PollenEntities.getSimpleId(this);
- }
-} //Comment
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/CommentEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/CommentEntity.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/CommentEntity.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,33 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface CommentEntity extends BookmarkableEntity {
-}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/JpaPollenEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/JpaPollenEntity.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/JpaPollenEntity.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,38 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.nuiton.jpa.api.JpaEntity;
-
-import java.io.Serializable;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface JpaPollenEntity extends JpaEntity, Serializable {
- String getSimpleId();
-}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Poll.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Poll.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Poll.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,43 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import javax.persistence.Entity;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-@Entity
-public class Poll extends AbstractJpaPoll {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public String getSimpleId() {
- return PollenEntities.getSimpleId(this);
- }
-} //Poll
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollEntity.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollEntity.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,33 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface PollEntity extends BookmarkableEntity {
-}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,80 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.lang3.StringUtils;
-import org.nuiton.jpa.api.JpaEntity;
-
-import java.util.UUID;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class PollenEntities {
-
- public static boolean isSimpleId(String id) {
- return !id.contains("#");
- }
-
- public static String getSimpleId(JpaEntity e) {
- String result = e.getId();
- if (result != null) {
- result = StringUtils.substringAfter(result, "#");
- }
- return result;
- }
-
- public static <E extends JpaEntity> String getEntityId(Class<E> type,
- String simpleId) {
- StringBuilder result = new StringBuilder(type.getName());
- result.append('#');
- result.append(simpleId);
- return result.toString();
- }
-
- public static String generateId() {
- // get uuid
- String uuid = UUID.randomUUID().toString().replaceAll("-", "");
-
- // decode in hexa decimal (reduce by 2 size of it)
- byte[] decode;
- try {
- decode = Hex.decodeHex(uuid.toCharArray());
- } catch (DecoderException e) {
- // can't happen!
- throw new RuntimeException(e);
- }
-
- // encode it in base64 (url safe version)
- String result = Base64.encodeBase64URLSafeString(decode);
- return result;
- }
-
-}
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Vote.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Vote.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Vote.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,43 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import javax.persistence.Entity;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-@Entity
-public class Vote extends AbstractJpaVote {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public String getSimpleId() {
- return PollenEntities.getSimpleId(this);
- }
-} //Vote
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoteEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoteEntity.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoteEntity.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,33 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface VoteEntity extends BookmarkableEntity {
-}
Modified: branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties 2013-06-14 09:12:59 UTC (rev 3823)
@@ -22,8 +22,9 @@
###m
model.tagValue.idFactory=true
model.tagValue.generatePropertyChangeListeners=true
+model.tagValue.generateVisitors=true
model.tagvalue.version=2.0
-model.tagvalue.entitySuperClass=org.chorem.pollen.persistence.entity.AbstractJpaPollenEntity
+#model.tagvalue.entitySuperClass=org.chorem.pollen.persistence.entity.AbstractJpaPollenEntity
org.chorem.pollen.persistence.entity.Poll.attribute.choice.stereotype=ordered
org.chorem.pollen.persistence.entity.Poll.attribute.voterList.stereotype=ordered
Deleted: branches/pollen-2.0/pollen-persistence/src/test/java/org/chorem/pollen/persistence/entity/PollenEntitiesTest.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/test/java/org/chorem/pollen/persistence/entity/PollenEntitiesTest.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence/src/test/java/org/chorem/pollen/persistence/entity/PollenEntitiesTest.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,57 +0,0 @@
-package org.chorem.pollen.persistence.entity;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.chorem.pollen.persistence.PollenEntityIdFactory;
-import org.junit.Assert;
-import org.junit.Test;
-import org.nuiton.jpa.api.JpaEntityIdFactoryResolver;
-
-/**
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class PollenEntitiesTest {
-
- @Test
- public void getSimpleId() {
-
- JpaEntityIdFactoryResolver.setFactory(new PollenEntityIdFactory());
-
- try {
- Poll poll = new Poll();
- poll.prepersist();
-
- String id = poll.getId();
- Assert.assertNotNull(id);
-
- String simpleId = PollenEntities.getSimpleId(poll);
- String id2 = PollenEntities.getEntityId(Poll.class, simpleId);
-
- Assert.assertEquals(id, id2);
- } finally {
- JpaEntityIdFactoryResolver.setFactory(null);
- }
- }
-}
Modified: branches/pollen-2.0/pollen-persistence-legacy/pom.xml
===================================================================
--- branches/pollen-2.0/pollen-persistence-legacy/pom.xml 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-persistence-legacy/pom.xml 2013-06-14 09:12:59 UTC (rev 3823)
@@ -10,7 +10,7 @@
<parent>
<groupId>org.chorem</groupId>
<artifactId>pollen</artifactId>
- <version>1.5.5-SNAPSHOT</version>
+ <version>2.0-SNAPSHOT</version>
</parent>
<groupId>org.chorem.pollen</groupId>
Modified: branches/pollen-2.0/pollen-rest-api/pom.xml
===================================================================
--- branches/pollen-2.0/pollen-rest-api/pom.xml 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/pom.xml 2013-06-14 09:12:59 UTC (rev 3823)
@@ -27,7 +27,7 @@
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>pollen-service</artifactId>
+ <artifactId>pollen-services</artifactId>
<version>${project.version}</version>
</dependency>
@@ -41,11 +41,6 @@
<artifactId>webmotion-unittest</artifactId>
</dependency>
- <!--dependency>
- <groupId>org.debux.webmotion</groupId>
- <artifactId>webmotion-extra-jpa</artifactId>
- </dependency-->
-
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
@@ -208,18 +203,7 @@
</resource>
</resources>
</build>
- <properties>
-
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-jcl</artifactId>
- <scope>runtime</scope>
- </dependency>
- </dependencies>
</profile>
-
</profiles>
</project>
Added: branches/pollen-2.0/pollen-rest-api/src/it/pom/pom.xml
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/it/pom/pom.xml (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/it/pom/pom.xml 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,272 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #%L
+ Pollen :: UI (struts2)
+ $Id$
+ $HeadURL: http://svn.chorem.org/svn/pollen/branches/pollen-2.0/pollen-ui-struts2/src/… $
+ %%
+ Copyright (C) 2009 - 2012 CodeLutin
+ %%
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (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 Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ #L%
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.chorem</groupId>
+ <artifactId>pollen</artifactId>
+ <version>@pom.version@</version>
+ </parent>
+
+ <groupId>org.chorem.pollen.it</groupId>
+ <artifactId>pollen-it</artifactId>
+ <name>Pollen :: IT</name>
+ <description>Super Pom des ITs</description>
+ <packaging>pom</packaging>
+
+ <properties>
+ <defaultWebContextPath>pollen</defaultWebContextPath>
+ <pollenServerPort>8765</pollenServerPort>
+ <defaultLogDir>${basedir}/target</defaultLogDir>
+
+ <pollenConfigurationFile>pollen-it.properties</pollenConfigurationFile>
+ <pollenDataDirectory>
+ ${project.build.testOutputDirectory}/data
+ </pollenDataDirectory>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.chorem.pollen</groupId>
+ <artifactId>pollen-rest-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-runner</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>false</filtering>
+ </resource>
+ </resources>
+
+ <plugins>
+
+ </plugins>
+
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <configuration>
+ <stopKey>A</stopKey>
+ <stopPort>1269</stopPort>
+ <contextXml>${basedir}/src/jetty/jetty-context.xml</contextXml>
+ <webAppConfig>
+ <contextPath>/${defaultWebContextPath}</contextPath>
+ </webAppConfig>
+ <systemProperties>
+ <systemProperty>
+ <name>basedir</name>
+ <value>${basedir}</value>
+ </systemProperty>
+ <systemProperty>
+ <name>pollen.log.dir</name>
+ <value>${project.build.directory}</value>
+ </systemProperty>
+ <systemProperty>
+ <name>pollenConfigurationFile</name>
+ <value>${pollenConfigurationFile}</value>
+ </systemProperty>
+ <systemProperty>
+ <name>jetty.port</name>
+ <value>${pollenServerPort}</value>
+ </systemProperty>
+ <systemProperty>
+ <name>pollenServerPort</name>
+ <value>${pollenServerPort}</value>
+ </systemProperty>
+ <systemProperty>
+ <name>pollenDataDirectory</name>
+ <value>${pollenDataDirectory}</value>
+ </systemProperty>
+ </systemProperties>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+
+ <execution>
+ <id>default-test</id>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <profiles>
+
+ <profile>
+ <id>start-server</id>
+ <activation>
+ <property>
+ <name>runIts</name>
+ <value>true</value>
+ </property>
+ </activation>
+
+ <properties>
+ <jetty.daemon>${runIts}</jetty.daemon>
+ </properties>
+ <build>
+ <defaultGoal>pre-integration-test</defaultGoal>
+ <plugins>
+
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>start-pollen</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <!--<daemon>true</daemon>-->
+ <webAppSourceDirectory>
+ ${explodedWarPath}
+ </webAppSourceDirectory>
+ <webAppConfig>
+ <descriptor>
+ ${explodedWarPath}/WEB-INF/web.xml
+ </descriptor>
+ </webAppConfig>
+ <classesDirectory>
+ ${explodedWarPath}/WEB-INF/classes
+ </classesDirectory>
+ <useTestScope>true</useTestScope>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>run-tests</id>
+ <activation>
+ <property>
+ <name>runIts</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <defaultGoal>integration-test</defaultGoal>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>run-tests</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>**/PollenTestSuite.java</include>
+ </includes>
+ <systemPropertyVariables>
+ <pollenServerPort>${pollenServerPort}</pollenServerPort>
+ <pollenConfigurationFile>
+ ${pollenConfigurationFile}
+ </pollenConfigurationFile>
+ <pollenDataDirectory>
+ ${pollenDataDirectory}
+ </pollenDataDirectory>
+ <extraDrivers>${extraDrivers}</extraDrivers>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>stop-server</id>
+ <activation>
+ <property>
+ <name>runIts</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <defaultGoal>post-integration-test</defaultGoal>
+ <plugins>
+
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>stop-pollen</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>stop</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ </profiles>
+
+</project>
Property changes on: branches/pollen-2.0/pollen-rest-api/src/it/pom/pom.xml
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Added: branches/pollen-2.0/pollen-rest-api/src/it/user/README.txt
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/it/user/README.txt (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/it/user/README.txt 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1 @@
+Test the user REST Api
\ No newline at end of file
Property changes on: branches/pollen-2.0/pollen-rest-api/src/it/user/README.txt
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenApplicationContext.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenApplicationContext.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenApplicationContext.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -26,9 +26,9 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
-import org.chorem.pollen.service.DefaultPollenServiceContext;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.config.PollenServiceConfig;
+import org.chorem.pollen.services.DefaultPollenServiceContext;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.config.PollenServiceConfig;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenRender.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenRender.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenRender.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -28,7 +28,6 @@
import com.google.gson.Gson;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.chorem.pollen.persistence.entity.JpaPollenEntity;
import org.debux.webmotion.server.call.Call;
import org.debux.webmotion.server.call.HttpContext;
import org.debux.webmotion.server.mapping.Mapping;
@@ -53,14 +52,13 @@
import java.util.Map;
/**
- * To render
+ * To render any entities.
*
* @author tchemit <chemit(a)codelutin.com>
* @since 2.0
*/
public class PollenRender<T> extends Render {
-
/**
* To specify entity collections to include in binded entities.
*
@@ -115,20 +113,20 @@
// single object
- if (model instanceof JpaPollenEntity) {
+ if (model instanceof JpaEntity) {
// entity need to transform it
- JpaPollenEntity jpaEntity = (JpaPollenEntity) model;
+ JpaEntity jpaEntity = (JpaEntity) model;
- PollenEntityBinder<JpaPollenEntity> binder = BinderFactory.newBinder(jpaEntity.getClass(), jpaEntity.getClass(), null, PollenEntityBinder.class);
+ PollenEntityBinder<JpaEntity> binder = BinderFactory.newBinder(jpaEntity.getClass(), jpaEntity.getClass(), null, PollenEntityBinder.class);
Map<String, Object> map = binder.obtainProperties(jpaEntity);
Map<String, Object> result = Maps.newTreeMap();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String propertyName = entry.getKey();
Object propertyValue = entry.getValue();
- if (propertyValue instanceof JpaPollenEntity) {
+ if (propertyValue instanceof JpaEntity) {
result.put(propertyName, toMap(propertyValue));
continue;
}
@@ -136,9 +134,6 @@
result.put(propertyName, propertyValue);
}
- // replace id to simpleId
- result.put(JpaEntity.PROPERTY_ID, jpaEntity.getSimpleId());
-
// treat collections
if (includeCollection != null) {
@@ -149,15 +144,12 @@
}
}
return result;
-
}
return model;
-
-
}
- protected static class PollenEntityBinder<E extends JpaPollenEntity> extends Binder<E, E> {
+ protected static class PollenEntityBinder<E extends JpaEntity> extends Binder<E, E> {
/** Logger. */
private static final Log log =
@@ -168,7 +160,6 @@
protected List<String> simpleProperties;
public PollenEntityBinder() {
-
}
@Override
@@ -176,7 +167,7 @@
super.setModel(model);
this.simpleProperties = Lists.newArrayList();
for (String property : model.getSourceDescriptors()) {
- if (model.getCollectionType(property)==null) {
+ if (model.getCollectionType(property) == null) {
simpleProperties.add(property);
}
}
Added: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenSecurityFilter.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenSecurityFilter.java (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenSecurityFilter.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,47 @@
+package org.chorem.pollen.rest;
+
+import org.apache.commons.lang3.StringUtils;
+import org.chorem.pollen.persistence.entity.SessionToken;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.InvalidSessionTokenException;
+import org.debux.webmotion.server.WebMotionFilter;
+import org.debux.webmotion.server.call.HttpContext;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class PollenSecurityFilter extends WebMotionFilter {
+
+ public static final String REQUEST_AUTH_PARAMETER = "auth";
+
+ void injectConnectedUser(HttpContext context) throws InvalidSessionTokenException {
+
+ String[] strings = context.getParameters().get(REQUEST_AUTH_PARAMETER);
+
+ String authParam = strings == null || strings.length < 1 ? null : strings[1];
+
+ if (StringUtils.isNotBlank(authParam)) {
+
+ // find out the userId from this auth
+
+ HttpServletRequest request = context.getRequest();
+
+ PollenServiceContext serviceContext =
+ PollenServices.getServiceContext(request);
+
+ SessionToken sessionToken =
+ serviceContext.getAuthService().getUserByAuth(authParam);
+
+ if (sessionToken != null) {
+
+ // reinject it in request
+ PollenServices.setSessionToken(request, sessionToken);
+ }
+ }
+ }
+}
Property changes on: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenSecurityFilter.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceContextFilter.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceContextFilter.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceContextFilter.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,7 +23,7 @@
* #L%
*/
-import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.services.PollenServiceContext;
import org.debux.webmotion.server.WebMotionFilter;
import org.debux.webmotion.server.call.HttpContext;
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,28 +23,21 @@
* #L%
*/
-import com.google.common.collect.Maps;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.chorem.pollen.persistence.entity.Comment;
-import org.chorem.pollen.persistence.entity.Poll;
-import org.chorem.pollen.persistence.entity.PollenEntities;
-import org.chorem.pollen.persistence.entity.PollenUser;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.exception.UserEmailAlreadyUsedException;
-import org.chorem.pollen.service.exception.UserLoginAlreadyUsedException;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.UserEmailAlreadyUsedException;
+import org.chorem.pollen.services.exception.UserLoginAlreadyUsedException;
import org.debux.webmotion.server.WebMotionServerListener;
import org.debux.webmotion.server.call.Call;
import org.debux.webmotion.server.call.HttpContext;
import org.debux.webmotion.server.call.ServerContext;
import org.debux.webmotion.server.handler.ExecutorParametersInjectorHandler;
import org.debux.webmotion.server.mapping.Mapping;
-import org.nuiton.jpa.api.JpaEntity;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;
-import java.util.Map;
/**
* TODO
@@ -62,7 +55,7 @@
public void onStart(Mapping mapping, ServerContext serverContext) {
serverContext.addInjector(new PollenServiceContextInjector());
- serverContext.addInjector(new PollenIdInjector());
+ serverContext.addInjector(new SessionTokenInjector());
// Create application context
PollenApplicationContext applicationContext =
@@ -75,7 +68,8 @@
EntityManager entityManager = applicationContext.newEntityManager();
try {
- PollenServiceContext serviceContext = applicationContext.newServiceContext(entityManager);
+ PollenServiceContext serviceContext =
+ applicationContext.newServiceContext(entityManager);
serviceContext.getUserService().createDefaultUsers();
} catch (UserEmailAlreadyUsedException e) {
//Can't happen
@@ -103,53 +97,28 @@
protected static class PollenServiceContextInjector implements ExecutorParametersInjectorHandler.Injector {
@Override
public Object getValue(Mapping mapping, Call call, String name, Class<?> type, Type generic) {
+ PollenServiceContext result = null;
if (PollenServiceContext.class.isAssignableFrom(type)) {
HttpContext httpContext = call.getContext();
HttpServletRequest request = httpContext.getRequest();
- return PollenServices.getServiceContext(request);
+
+ result = PollenServices.getServiceContext(request);
}
- return null;
+ return result;
}
}
- protected static class PollenIdInjector implements ExecutorParametersInjectorHandler.Injector {
-
- final Map<String, Class<? extends JpaEntity>> paramMapping;
-
- public PollenIdInjector() {
- paramMapping = Maps.newTreeMap();
- paramMapping.put("userId", PollenUser.class);
- paramMapping.put("pollId", Poll.class);
- paramMapping.put("commentId", Comment.class);
- }
-
+ protected static class SessionTokenInjector implements ExecutorParametersInjectorHandler.Injector {
@Override
- public Object getValue(Mapping mapping,
- Call call,
- String name,
- Class<?> type,
- Type generic) {
+ public Object getValue(Mapping mapping, Call call, String name, Class<?> type, Type generic) {
+ PollenServiceContext result = null;
+ if (PollenServiceContext.class.isAssignableFrom(type)) {
+ HttpContext httpContext = call.getContext();
+ HttpServletRequest request = httpContext.getRequest();
- if (String.class.isAssignableFrom(type) && paramMapping.containsKey(name)) {
-
- Class<? extends JpaEntity> entityType = paramMapping.get(name);
-
- Call.ParameterTree parameterTree = call.getParameterTree();
- Map<String, Call.ParameterTree> tree = parameterTree.getTree();
-
- Call.ParameterTree paramValue = tree.get(name);
- if (paramValue != null) {
- String id = String.valueOf(((String[]) paramValue.getValue())[0]);
- if (PollenEntities.isSimpleId(id)) {
-
- // get the full id
- String fullId = PollenEntities.getEntityId(
- entityType, id);
- return fullId;
- }
- }
+ result = PollenServices.getServiceContext(request);
}
- return null;
+ return result;
}
}
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServices.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServices.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServices.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,7 +23,8 @@
* #L%
*/
-import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.persistence.entity.SessionToken;
+import org.chorem.pollen.services.PollenServiceContext;
import org.nuiton.web.filter.JpaTransactionFilter;
import javax.persistence.EntityManager;
@@ -42,6 +43,8 @@
protected static final String REQUEST_POLLEN_SERVICE_CONTEXT = "pollen_PollenServiceContext";
+ protected static final String REQUEST_POLLEN_CONNECTED_USER = "pollen_PollenConnectedUser";
+
protected static final String REQUEST_ENTITY_MANAGER = JpaTransactionFilter.JPA_TRANSACTION_REQUEST_ATTRIBUTE;
public static PollenApplicationContext getApplicationContext(ServletContext servletContext) {
@@ -72,4 +75,15 @@
request.getAttribute(REQUEST_ENTITY_MANAGER);
return result;
}
+
+ public static SessionToken getSessionToken(HttpServletRequest request) {
+ SessionToken result = (SessionToken)
+ request.getAttribute(REQUEST_POLLEN_CONNECTED_USER);
+ return result;
+ }
+
+ public static void setSessionToken(HttpServletRequest request,
+ SessionToken sessionToken) {
+ request.setAttribute(REQUEST_POLLEN_CONNECTED_USER, sessionToken);
+ }
}
\ No newline at end of file
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/AuthService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/AuthService.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/AuthService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,9 +23,9 @@
* #L%
*/
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-import org.chorem.pollen.service.exception.UserInvalidPasswordException;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+import org.chorem.pollen.services.exception.UserInvalidPasswordException;
import org.debux.webmotion.server.WebMotionController;
/**
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -24,8 +24,8 @@
*/
import org.chorem.pollen.persistence.entity.Comment;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
import java.util.List;
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -25,14 +25,22 @@
import org.chorem.pollen.persistence.entity.FavoriteList;
import org.chorem.pollen.persistence.entity.FavoriteListMember;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+import org.chorem.pollen.services.exception.FavoriteListImportException;
+import org.chorem.pollen.services.exception.FavoriteListMemberEmailAlreadyUsedException;
+import org.chorem.pollen.services.exception.FavoriteListMemberNameAlreadyUsedException;
+import org.chorem.pollen.services.exception.FavoriteListMemberNotOwnedByFavoriteListException;
+import org.chorem.pollen.services.exception.FavoriteListNameAlreadyUsedException;
+import org.chorem.pollen.services.exception.FavoriteListNotOwnedByUserException;
import org.debux.webmotion.server.WebMotionController;
+import java.io.File;
import java.util.List;
/**
* TODO
+ * TODO All method needs a userId connected
*
* @author tchemit <chemit(a)codelutin.com>
* @since 2.0
@@ -48,18 +56,26 @@
return context.getFavoriteListService().getFavoriteList(favoriteListId);
}
- public FavoriteList createFavoriteList(PollenServiceContext context, String userId, FavoriteList favoriteList) throws EntityNotFoundException {
+ public FavoriteList createFavoriteList(PollenServiceContext context, String userId, FavoriteList favoriteList) throws EntityNotFoundException, FavoriteListNameAlreadyUsedException {
return context.getFavoriteListService().createFavoriteList(userId, favoriteList);
}
- public FavoriteList editFavoriteList(PollenServiceContext context, FavoriteList favoriteList) throws EntityNotFoundException {
- return context.getFavoriteListService().editFavoriteList(favoriteList);
+ public FavoriteList editFavoriteList(PollenServiceContext context, String userId, FavoriteList favoriteList) throws EntityNotFoundException, FavoriteListNameAlreadyUsedException, FavoriteListNotOwnedByUserException {
+ return context.getFavoriteListService().editFavoriteList(userId, favoriteList);
}
- public void deleteFavoriteList(PollenServiceContext context, String userId, String favoriteListId) throws EntityNotFoundException {
+ public void deleteFavoriteList(PollenServiceContext context, String userId, String favoriteListId) throws EntityNotFoundException, FavoriteListNotOwnedByUserException {
context.getFavoriteListService().deleteFavoriteList(userId, favoriteListId);
}
+ public int importFavoriteListMembersFromCsv(PollenServiceContext context, String userId, String favoriteListId, File csvFile) throws EntityNotFoundException, FavoriteListImportException, FavoriteListNotOwnedByUserException {
+ return context.getFavoriteListService().importFavoriteListMembersFromCsv(userId, favoriteListId, csvFile);
+ }
+
+ public int importFavoriteListMembersFromLdap(PollenServiceContext context, String userId, String favoriteListId, String ldap) throws EntityNotFoundException, FavoriteListImportException, FavoriteListNotOwnedByUserException {
+ return context.getFavoriteListService().importFavoriteListMembersFromLdap(userId, favoriteListId, ldap);
+ }
+
public List<FavoriteListMember> getMembers(PollenServiceContext context, String favoriteListId) throws EntityNotFoundException {
List<FavoriteListMember> members = context.getFavoriteListService().getFavoriteListMembers(favoriteListId);
return members;
@@ -69,15 +85,15 @@
return context.getFavoriteListService().getFavoriteListMember(memberId);
}
- public FavoriteListMember addMember(PollenServiceContext context, String favoriteListId, FavoriteListMember member) throws EntityNotFoundException {
+ public FavoriteListMember addMember(PollenServiceContext context, String favoriteListId, FavoriteListMember member) throws EntityNotFoundException, FavoriteListMemberEmailAlreadyUsedException, FavoriteListMemberNameAlreadyUsedException {
return context.getFavoriteListService().addFavoriteListMember(favoriteListId, member);
}
- public FavoriteListMember editMember(PollenServiceContext context, FavoriteListMember member) throws EntityNotFoundException {
- return context.getFavoriteListService().editFavoriteListMember(member);
+ public FavoriteListMember editMember(PollenServiceContext context, String favoriteListId, FavoriteListMember member) throws EntityNotFoundException, FavoriteListMemberEmailAlreadyUsedException, FavoriteListMemberNameAlreadyUsedException, FavoriteListMemberNotOwnedByFavoriteListException {
+ return context.getFavoriteListService().editFavoriteListMember(favoriteListId, member);
}
- public void removeMember(PollenServiceContext context, String favoriteListId, String memberId) throws EntityNotFoundException {
- context.getFavoriteListService().removeFavoriteListMember( favoriteListId, memberId);
+ public void removeMember(PollenServiceContext context, String favoriteListId, String memberId) throws EntityNotFoundException, FavoriteListMemberNotOwnedByFavoriteListException {
+ context.getFavoriteListService().removeFavoriteListMember(favoriteListId, memberId);
}
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -25,11 +25,10 @@
import org.chorem.pollen.persistence.entity.Choice;
import org.chorem.pollen.persistence.entity.Poll;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
-import javax.servlet.annotation.WebFilter;
import java.io.File;
import java.util.List;
import java.util.Set;
@@ -62,6 +61,10 @@
return polls;
}
+ public Poll getPoll(PollenServiceContext context, String pollId) throws EntityNotFoundException {
+ return context.getPollService().getPoll(pollId);
+ }
+
public Poll createPoll(PollenServiceContext context, String userId, Poll poll) throws EntityNotFoundException {
return context.getPollService().createPoll(userId, poll);
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -24,12 +24,12 @@
*/
import org.chorem.pollen.persistence.entity.PollenUser;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-import org.chorem.pollen.service.exception.UserEmailAlreadyUsedException;
-import org.chorem.pollen.service.exception.UserInvalidEmailActiviationTokenException;
-import org.chorem.pollen.service.exception.UserInvalidPasswordException;
-import org.chorem.pollen.service.exception.UserLoginAlreadyUsedException;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+import org.chorem.pollen.services.exception.UserEmailAlreadyUsedException;
+import org.chorem.pollen.services.exception.UserInvalidEmailActiviationTokenException;
+import org.chorem.pollen.services.exception.UserInvalidPasswordException;
+import org.chorem.pollen.services.exception.UserLoginAlreadyUsedException;
import org.debux.webmotion.server.WebMotionController;
import java.util.List;
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteCountingService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteCountingService.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteCountingService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -23,9 +23,9 @@
* #L%
*/
-import org.chorem.pollen.service.PollResult;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.services.PollResult;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
/**
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -24,8 +24,8 @@
*/
import org.chorem.pollen.persistence.entity.Vote;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
import java.util.List;
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -25,8 +25,8 @@
import org.chorem.pollen.persistence.entity.VoterList;
import org.chorem.pollen.persistence.entity.VoterListMember;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
import java.util.List;
Modified: branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping 2013-06-14 09:12:59 UTC (rev 3823)
@@ -33,20 +33,22 @@
GET /polls/{pollId}/comments CommentService.getComments
POST /polls/{pollId}/comments CommentService.addComment
GET /comments/{commentId} CommentService.getComment
-PUT /comments CommentService.editComment
+PUT /comments/{commentId} CommentService.editComment
DELETE /polls/{pollId}/comments/{commentId} CommentService.deleteComment
# FavoriteListService
GET /favoriteLists FavoriteListService.getFavoriteLists
GET /favoriteLists/{flId} FavoriteListService.getFavoriteList
+POST /favoriteLists/{flId}/importCsv FavoriteListService.importFavoriteListMemberFromCsv
+POST /favoriteLists/{flId}/importLdap FavoriteListService.importFavoriteListMemberFromLdap
POST /favoriteLists FavoriteListService.createFavoriteList
-PUT /favoriteLists FavoriteListService.editFavoriteList
+PUT /favoriteLists/{flId} FavoriteListService.editFavoriteList
DELETE /favoriteLists/{flId} FavoriteListService.deleteFavoriteList
GET /favoriteLists/{flId}/members FavoriteListService.getMembers
GET /favoriteListMembers/{mId} FavoriteListService.getMember
POST /favoriteLists/{flId}/members FavoriteListService.addMember
-PUT /favoriteListMembers FavoriteListService.editMember
+PUT /favoriteLists/{flId}/members/{mId} FavoriteListService.editMember
DELETE /favoriteLists/{flId}/members/{mId} FavoriteListService.removeMember
# PollService
@@ -56,7 +58,7 @@
GET /polls/invited PollService.getInvitedPolls
GET /polls/participated PollService.getParticipatedPolls
POST /polls PollService.createPoll
-PUT /polls PollService.editPoll
+PUT /polls/{pollId} PollService.editPoll
GET /polls/{pollId} PollService.getPoll
DELETE /polls/{pollId} PollService.deletePoll
POST /polls/{pollId} PollService.clonePoll
@@ -66,7 +68,7 @@
GET /polls/{pollId}/choices PollService.getChoices
POST /polls/{pollId}/choices PollService.addChoice
GET /choices/{choiceId} PollService.getChoice
-PUT /choices PollService.editChoice
+PUT /choices/{choiceId} PollService.editChoice
DELETE /polls/{pollId}/choices/{choiceId} PollService.deleteChoice
# UserService
@@ -74,7 +76,7 @@
GET /users UserService.getUsers
GET /users/{userId} UserService.getUser
POST /users UserService.createUser
-PUT /users UserService.editUser
+PUT /users/{userId} UserService.editUser
PUT /users/{userId}?token={} UserService.validateUserEmail
# VoteCountingService
@@ -86,13 +88,14 @@
PUT /polls/{pollId}/favoriteLists/{flId} VoterListService.importFavoriteList
GET /polls/{pollId}/voterLists VoterListService.getVoterLists
GET /voterLists/{vlId} VoterListService.getVoterList
+POST /voterLists VoterListService.createVoterList
PUT /voterLists/{vlId} VoterListService.editVoterList
DELETE /polls/{pollId}/voterLists/{vlId} VoterListService.deleteVoterList
GET /voterLists/{vlId}/members VoterListService.getMembers
GET /voterListMembers/{mId} VoterListService.getMember
POST /voterLists/{vlId}/members VoterListService.addMember
-PUT /voterListMembers VoterListService.editMember
+PUT /voterListMembers/{mId} VoterListService.editMember
DELETE /voterLists/{vlId}/members/{mId} VoterListService.deleteMember
# VoteService
@@ -100,5 +103,5 @@
GET /polls/{pollId}/votes VoteService.getVotes
PUT /polls/{pollId}/votes VoteService.addVote
GET /votes/{voteId} VoteService.getVote
-PUT /votes VoteService.editVote
+PUT /votes/{voteId} VoteService.editVote
DELETE /polls/{pollId}/votes/{voteId} VoteService.deleteVote
Modified: branches/pollen-2.0/pollen-rest-api/src/main/webapp/WEB-INF/web.xml
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/webapp/WEB-INF/web.xml 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/main/webapp/WEB-INF/web.xml 2013-06-14 09:12:59 UTC (rev 3823)
@@ -30,14 +30,6 @@
<display-name>Pollen REST Api</display-name>
- <listener>
- <listener-class>org.apache.commons.fileupload.servlet.FileCleanerCleanup</listener-class>
- </listener>
-
- <listener>
- <listener-class>org.debux.webmotion.server.WebMotionServletContextListener</listener-class>
- </listener>
-
<filter>
<filter-name>jpaTransaction</filter-name>
<filter-class>
@@ -45,24 +37,9 @@
</filter-class>
</filter>
- <filter>
- <filter-name>WebMotionServer</filter-name>
- <filter-class>org.debux.webmotion.server.WebMotionServer</filter-class>
- <async-supported>true</async-supported>
- </filter>
-
<filter-mapping>
<filter-name>jpaTransaction</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- <filter-mapping>
- <filter-name>WebMotionServer</filter-name>
- <url-pattern>/*</url-pattern>
- <dispatcher>REQUEST</dispatcher>
- <dispatcher>INCLUDE</dispatcher>
- <dispatcher>FORWARD</dispatcher>
- <dispatcher>ERROR</dispatcher>
- </filter-mapping>
-
</web-app>
\ No newline at end of file
Modified: branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/AbstractPollenRestApiTest.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/AbstractPollenRestApiTest.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/AbstractPollenRestApiTest.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -25,11 +25,10 @@
import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
import org.chorem.pollen.rest.PollenApplicationContext;
-import org.chorem.pollen.service.FixturesService;
-import org.chorem.pollen.service.PollenFixtures;
-import org.chorem.pollen.service.PollenServiceContext;
-import org.debux.webmotion.unittest.WebMotionTest;
-import org.junit.Before;
+import org.chorem.pollen.services.service.FixturesService;
+import org.chorem.pollen.services.PollenFixtures;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.debux.webmotion.unittest.WebMotionJUnit;
import org.junit.Rule;
import org.nuiton.jpa.junit.JpaEntityManagerRule;
@@ -42,7 +41,7 @@
* @author tchemit <chemit(a)codelutin.com>
* @since 2.0
*/
-public class AbstractPollenRestApiTest extends WebMotionTest {
+public class AbstractPollenRestApiTest extends WebMotionJUnit {
protected JpaEntityManagerRule jpaEntityManagerRule;
@@ -114,8 +113,8 @@
}
- @Before
- public void launchServer() throws Exception {
- runServer();
- }
+// @Before
+// public void launchServer() throws Exception {
+// runServer();
+// }
}
Modified: branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/FakePollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/FakePollenServiceContext.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/FakePollenServiceContext.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -26,7 +26,7 @@
import com.google.common.base.Preconditions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.chorem.pollen.service.DefaultPollenServiceContext;
+import org.chorem.pollen.services.DefaultPollenServiceContext;
import java.util.Date;
Modified: branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/UserServiceTest.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/UserServiceTest.java 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/UserServiceTest.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -52,7 +52,7 @@
Request request = createRequest("/users").Get();
String result = request.execute().returnContent().asString();
- assertTrue(result.contains("users"));
+ assertTrue(result.contains("email"));
}
Modified: branches/pollen-2.0/pollen-rest-api/src/test/resources/pollen.properties
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/test/resources/pollen.properties 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pollen-rest-api/src/test/resources/pollen.properties 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,5 +1,5 @@
javax.persistence.jdbc.driver=org.h2.Driver
-javax.persistence.jdbc.url=jdbc:h2:file:${testDirectory}/pollen/h2data
+javax.persistence.jdbc.url=jdbc:h2:file:target/pollen/h2data
javax.persistence.jdbc.user=sa
javax.persistence.jdbc.password=
hibernate.dialect=org.hibernate.dialect.H2Dialect
Modified: branches/pollen-2.0/pollen-services/pom.xml
===================================================================
--- branches/pollen-2.0/pollen-service/pom.xml 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/pom.xml 2013-06-14 09:12:59 UTC (rev 3823)
@@ -9,7 +9,7 @@
</parent>
<groupId>org.chorem.pollen</groupId>
- <artifactId>pollen-service</artifactId>
+ <artifactId>pollen-services</artifactId>
<name>Pollen :: Service </name>
<description>Pollen Service Layer</description>
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/AbstractPollenService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/AbstractPollenService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,117 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import org.chorem.pollen.persistence.PollenPersistenceContext;
-import org.chorem.pollen.service.config.PollenServiceConfig;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-import org.nuiton.jpa.api.JpaEntities;
-import org.nuiton.jpa.api.JpaEntity;
-
-import java.util.Date;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public abstract class AbstractPollenService implements PollenServiceSupport {
-
- protected PollenServiceContext serviceContext;
-
- protected void checkHasId(JpaEntity entity) {
- Preconditions.checkState(JpaEntities.isEntityHasId(entity));
- }
-
- protected void checkHasNoId(JpaEntity entity) {
- Preconditions.checkState(JpaEntities.isEntityHasNoId(entity));
- }
-
- @Override
- public void setServiceContext(PollenServiceContext serviceContext) {
- this.serviceContext = serviceContext;
- }
-
- protected Date getNow() {
- return serviceContext.getNow();
- }
-
- protected String generateId() {
- return serviceContext.generateUUID();
- }
-
- protected PollenPersistenceContext getPersistenceContext() {
- return serviceContext.getPersistenceContext();
- }
-
- protected PollenServiceConfig getPollenServiceConfig() {
- return serviceContext.getPollenServiceConfig();
- }
-
- protected AuthService getAuthService() {
- return serviceContext.getAuthService();
- }
-
- protected CommentService getCommentService() {
- return serviceContext.getCommentService();
- }
-
- protected FavoriteListService getFavoriteListService() {
- return serviceContext.getFavoriteListService();
- }
-
- protected PollService getPollService() {
- return serviceContext.getPollService();
- }
-
- protected UserService getUserService() {
- return serviceContext.getUserService();
- }
-
- protected VoteCountingService getVoteCountingService() {
- return serviceContext.getVoteCountingService();
- }
-
- protected VoterListService getVoterListService() {
- return serviceContext.getVoterListService();
- }
-
- protected VoteService getVoteService() {
- return serviceContext.getVoteService();
- }
-
- protected EmailService getEmailService() {
- return serviceContext.getEmailService();
- }
-
- protected <E extends JpaEntity> void checkEntityExists(Class<E> type,
- E entity,
- String entityId) throws EntityNotFoundException {
- if (entity == null) {
- throw new EntityNotFoundException(type, entityId);
- }
- }
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/AuthService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/AuthService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,116 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import org.chorem.pollen.persistence.dao.PollenUserJpaDao;
-import org.chorem.pollen.persistence.dao.SessionTokenJpaDao;
-import org.chorem.pollen.persistence.entity.PollenUser;
-import org.chorem.pollen.persistence.entity.SessionToken;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-import org.chorem.pollen.service.exception.UserInvalidPasswordException;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class AuthService extends AbstractPollenService {
-
- public String login(String login, String password) throws EntityNotFoundException, UserInvalidPasswordException {
- Preconditions.checkNotNull(login);
- Preconditions.checkNotNull(password);
-
- PollenUser user = getPersistenceContext().getPollenUserDao().findByLogin(login);
- if (user == null) {
- throw new EntityNotFoundException(PollenUser.class, login);
- }
-
- String encodedPassword = serviceContext.encodePassword(password);
- if (!encodedPassword.equals(user.getPassword())) {
- throw new UserInvalidPasswordException();
- }
-
- // Create a new session Token
- SessionTokenJpaDao dao = getPersistenceContext().getSessionTokenDao();
-
- SessionToken sessionToken = dao.newInstance();
- String token = serviceContext.generateUUID();
- String encodedToken = serviceContext.encodePassword(token);
- sessionToken.setPollenUser(user);
- sessionToken.setToken(encodedToken);
- sessionToken.setCreationDate(serviceContext.getNow());
-
- dao.persist(sessionToken);
- getPersistenceContext().commit();
-
- return token;
- }
-
- public void lostPassword(String login) throws EntityNotFoundException {
- Preconditions.checkNotNull(login);
-
- PollenUserJpaDao dao = getPersistenceContext().getPollenUserDao();
-
- PollenUser user = dao.findByLogin(login);
- if (user == null) {
- throw new EntityNotFoundException(PollenUser.class, login);
- }
-
- // Generate a new password
- String newPassword = serviceContext.generatePassword();
- String encodedPassword = serviceContext.encodePassword(newPassword);
- user.setPassword(encodedPassword);
- dao.merge(user);
- getPersistenceContext().commit();
-
- notifyPasswordChanged(user, newPassword);
- }
-
- public void logout(String login, String token) throws EntityNotFoundException {
- Preconditions.checkNotNull(login);
- Preconditions.checkNotNull(token);
- PollenUser user = getPersistenceContext().getPollenUserDao().findByLogin(login);
- if (user == null) {
- throw new EntityNotFoundException(PollenUser.class, login);
- }
-
- String encodedToken = serviceContext.encodePassword(token);
-
- SessionTokenJpaDao dao = getPersistenceContext().getSessionTokenDao();
-
- SessionToken sessionToken = dao.findByToken(encodedToken);
- if (sessionToken == null) {
- throw new EntityNotFoundException(SessionToken.class, token);
- }
-
- dao.remove(sessionToken);
- getPersistenceContext().commit();
- }
-
- protected void notifyPasswordChanged(PollenUser user, String newPassword) {
- //TODO
- }
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/CommentService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/CommentService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/CommentService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,94 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service API
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import org.chorem.pollen.persistence.entity.Comment;
-import org.chorem.pollen.persistence.entity.Poll;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-
-import java.util.List;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class CommentService extends AbstractPollenService {
-
- public List<Comment> getComments(String pollId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Poll poll = getPollService().getPoll(pollId);
- return poll.getComment();
- }
-
- public Comment getComment(String commentId) throws EntityNotFoundException {
- Preconditions.checkNotNull(commentId);
- Comment result = getPersistenceContext().getCommentDao().findById(commentId);
- checkEntityExists(Comment.class, result, commentId);
- return result;
- }
-
- public Comment addComment(String pollId, Comment comment) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- checkHasNoId(comment);
- Poll poll = getPollService().getPoll(pollId);
-
- poll.addComment(comment);
- getPersistenceContext().getPollDao().merge(poll);
- getPersistenceContext().commit();
-
- Comment result = getComment(comment.getId());
- return result;
- }
-
- public Comment editComment(Comment comment) throws EntityNotFoundException {
-
- // check comment exists
- getComment(comment.getId());
-
- getPersistenceContext().getCommentDao().merge(comment);
- getPersistenceContext().commit();
-
- Comment result = getComment(comment.getId());
- return result;
- }
-
- public void deleteComment(String pollId, String commentId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(commentId);
- Poll poll = getPollService().getPoll(pollId);
-
- Comment comment = getComment(commentId);
- Preconditions.checkNotNull(comment);
-
- poll.removeComment(comment);
-
- getPersistenceContext().getPollDao().merge(poll);
-
- getPersistenceContext().commit();
- }
-
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,158 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.apache.commons.lang3.RandomStringUtils;
-import org.chorem.pollen.persistence.PollenPersistenceContext;
-import org.chorem.pollen.service.config.PollenServiceConfig;
-import org.nuiton.util.StringUtil;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Date;
-import java.util.UUID;
-
-public class DefaultPollenServiceContext implements PollenServiceContext {
-
- protected PollenServiceConfig pollenServiceConfig;
-
- protected PollenPersistenceContext persistenceContext;
-
- public void setPollenServiceConfig(PollenServiceConfig pollenServiceConfig) {
- this.pollenServiceConfig = pollenServiceConfig;
- }
-
- public void setPersistenceContext(PollenPersistenceContext persistenceContext) {
- this.persistenceContext = persistenceContext;
- }
-
- @Override
- public PollenServiceConfig getPollenServiceConfig() {
- return pollenServiceConfig;
- }
-
- @Override
- public String generateUUID() {
- return UUID.randomUUID().toString();
- }
-
- @Override
- public Date getNow() {
- Date now = new Date();
- return now;
- }
-
- public String generatePassword() {
- return RandomStringUtils.randomAlphanumeric(8);
- }
-
- @Override
- public PollenPersistenceContext getPersistenceContext() {
- return persistenceContext;
- }
-
- @Override
- public AuthService getAuthService() {
- return newService(AuthService.class);
- }
-
- @Override
- public CommentService getCommentService() {
- return newService(CommentService.class);
- }
-
- @Override
- public FavoriteListService getFavoriteListService() {
- return newService(FavoriteListService.class);
- }
-
- @Override
- public PollService getPollService() {
- return newService(PollService.class);
- }
-
- @Override
- public UserService getUserService() {
- return newService(UserService.class);
- }
-
- @Override
- public VoteCountingService getVoteCountingService() {
- return newService(VoteCountingService.class);
- }
-
- @Override
- public VoterListService getVoterListService() {
- return newService(VoterListService.class);
- }
-
- @Override
- public VoteService getVoteService() {
- return newService(VoteService.class);
- }
-
- @Override
- public EmailService getEmailService() {
- return newService(EmailService.class);
- }
-
- @Override
- public String encodePassword(String password) {
- return StringUtil.encodeMD5(password);
- }
-
- protected <E extends PollenServiceSupport> E newService(Class<E> serviceClass) {
-
- E service;
-
- try {
-
- Constructor<E> constructor = serviceClass.getConstructor();
-
- service = constructor.newInstance();
-
- } catch (NoSuchMethodException e) {
-
- throw new PollenTechnicalException("all services must provide a default public constructor", e);
-
- } catch (InvocationTargetException e) {
-
- throw new PollenTechnicalException("unable to instantiate pollen service", e);
-
- } catch (InstantiationException e) {
-
- throw new PollenTechnicalException("unable to instantiate pollen service", e);
-
- } catch (IllegalAccessException e) {
-
- throw new PollenTechnicalException("unable to instantiate pollen service", e);
- }
-
- service.setServiceContext(this);
-
- return service;
-
- }
-
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/EmailService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/EmailService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/EmailService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,39 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.chorem.pollen.persistence.entity.PollenUser;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class EmailService extends AbstractPollenService {
-
- public void onUserCreated(PollenUser user) {
- //TODO
- }
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/FavoriteListService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FavoriteListService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/FavoriteListService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,159 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service API
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import org.chorem.pollen.persistence.entity.FavoriteList;
-import org.chorem.pollen.persistence.entity.FavoriteListMember;
-import org.chorem.pollen.persistence.entity.PollenUser;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-
-import java.util.List;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class FavoriteListService extends AbstractPollenService {
-
- public List<FavoriteList> getFavoriteLists(String userId)throws EntityNotFoundException {
- Preconditions.checkNotNull(userId);
- PollenUser user = getUserService().getUser(userId);
-
- List<FavoriteList> result = user.getFavoriteList();
- return result;
- }
-
- public FavoriteList getFavoriteList(String favoriteListId) throws EntityNotFoundException{
- Preconditions.checkNotNull(favoriteListId);
- FavoriteList result = getPersistenceContext().getFavoriteListDao().findById(favoriteListId);
- checkEntityExists(FavoriteList.class, result, favoriteListId);
- return result;
- }
-
- public FavoriteList createFavoriteList(String userId,
- FavoriteList favoriteList) throws EntityNotFoundException{
- Preconditions.checkNotNull(userId);
- Preconditions.checkNotNull(favoriteList);
- checkHasNoId(favoriteList);
-
- PollenUser user = getUserService().getUser(userId);
-
- user.addFavoriteList(favoriteList);
- getPersistenceContext().getPollenUserDao().merge(user);
-
- getPersistenceContext().commit();
- FavoriteList result = getFavoriteList(favoriteList.getId());
- return result;
- }
-
- public FavoriteList editFavoriteList(FavoriteList favoriteList) throws EntityNotFoundException{
- Preconditions.checkNotNull(favoriteList);
- checkHasId(favoriteList);
-
- getFavoriteList(favoriteList.getId());
-
- getPersistenceContext().getFavoriteListDao().merge(favoriteList);
-
- getPersistenceContext().commit();
- FavoriteList result = getFavoriteList(favoriteList.getId());
- return result;
- }
-
- public void deleteFavoriteList(String userId, String favoriteListId) throws EntityNotFoundException{
- Preconditions.checkNotNull(userId);
- Preconditions.checkNotNull(favoriteListId);
-
- PollenUser user = getUserService().getUser(userId);
-
- FavoriteList persisted = getFavoriteList(favoriteListId);
-
- user.removeFavoriteList(persisted);
- getPersistenceContext().getPollenUserDao().merge(user);
-
- getPersistenceContext().commit();
- }
-
- public List<FavoriteListMember> getFavoriteListMembers(String favoriteListId)throws EntityNotFoundException {
- Preconditions.checkNotNull(favoriteListId);
-
- FavoriteList favoriteList = getFavoriteList(favoriteListId);
-
- return favoriteList.getFavoriteListMember();
- }
-
- public FavoriteListMember getFavoriteListMember(String memberId)throws EntityNotFoundException {
- Preconditions.checkNotNull(memberId);
- FavoriteListMember result = getPersistenceContext().getFavoriteListMemberDao().findById(memberId);
- checkEntityExists(FavoriteListMember.class, result, memberId);
- return result;
- }
-
- public FavoriteListMember addFavoriteListMember(String favoriteListId,
- FavoriteListMember member)throws EntityNotFoundException {
- Preconditions.checkNotNull(favoriteListId);
- Preconditions.checkNotNull(member);
- checkHasNoId(member);
-
- FavoriteList favoriteList = getFavoriteList(favoriteListId);
-
- favoriteList.addFavoriteListMember(member);
-
- getPersistenceContext().getFavoriteListDao().merge(favoriteList);
-
- getPersistenceContext().commit();
- FavoriteListMember result = getFavoriteListMember(member.getId());
- return result;
- }
-
- public FavoriteListMember editFavoriteListMember(FavoriteListMember member)throws EntityNotFoundException {
- Preconditions.checkNotNull(member);
- checkHasId(member);
-
-
- getFavoriteListMember(member.getId());
-
- member = getPersistenceContext().getFavoriteListMemberDao().merge(member);
- getPersistenceContext().commit();
- FavoriteListMember result = getFavoriteListMember(member.getId());
- return result;
- }
-
- public void removeFavoriteListMember(String favoriteListId, String memberId) throws EntityNotFoundException{
- Preconditions.checkNotNull(favoriteListId);
- Preconditions.checkNotNull(memberId);
-
- FavoriteList favoriteList = getFavoriteList(favoriteListId);
-
- FavoriteListMember member = getFavoriteListMember(memberId);
-
- favoriteList.removeFavoriteListMember(member);
-
- getPersistenceContext().getFavoriteListDao().merge(favoriteList);
- getPersistenceContext().commit();
- }
-
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/FixturesService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FixturesService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/FixturesService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,100 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.chorem.pollen.persistence.PollenPersistenceContext;
-import org.chorem.pollen.persistence.dao.PollenUserJpaDao;
-import org.chorem.pollen.persistence.entity.PollenUser;
-
-import java.util.Collection;
-import java.util.Map;
-
-public class FixturesService extends AbstractPollenService {
-
- private static final Log log = LogFactory.getLog(FixturesService.class);
-
- protected Map<String, PollenFixtures> fixtureSets = Maps.newHashMap();
-
- public PollenFixtures cleanDatabaseAndLoadFixtures(String fixturesSetName) {
-
- return loadFixtures(fixturesSetName, true);
-
- }
-
- public PollenFixtures loadFixtures(String fixturesSetName) {
-
- return loadFixtures(fixturesSetName, false);
-
- }
-
- protected PollenFixtures loadFixtures(String fixturesSetName, boolean cleanDatabase) {
-
- boolean devMode = serviceContext.getPollenServiceConfig().isDevMode();
-
- Preconditions.checkState(devMode);
-
- PollenFixtures fixtures = fixtureSets.get(fixturesSetName);
-
- if (fixtures == null) {
-
- fixtures = new PollenFixtures(fixturesSetName);
-
- fixtureSets.put(fixturesSetName, fixtures);
-
- if (log.isInfoEnabled()) {
- log.info("will restore database with fixture set");
- }
-
- PollenPersistenceContext persistenceContext = serviceContext.getPersistenceContext();
-
- if (cleanDatabase) {
-
- persistenceContext.clearDatabase();
-
- }
-
- PollenUserJpaDao userDao = persistenceContext.getPollenUserDao();
-
- Collection<PollenUser> users = fixtures.fixture("users");
-
- for (PollenUser user : users) {
-
- user.setPassword(serviceContext.encodePassword(user.getPassword()));
- userDao.persist(user);
- }
-
- persistenceContext.commit();
-
-
- }
-
- return fixtures;
-
- }
-
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollResult.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollResult.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollResult.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,36 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import java.io.Serializable;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class PollResult implements Serializable {
- private static final long serialVersionUID = 1L;
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,200 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import org.chorem.pollen.persistence.entity.Choice;
-import org.chorem.pollen.persistence.entity.Poll;
-import org.chorem.pollen.persistence.entity.PollenUser;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-
-import java.io.File;
-import java.util.List;
-import java.util.Set;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class PollService extends AbstractPollenService {
-
- public Set<Poll> getCreatedPolls(String userId) throws EntityNotFoundException {
- Preconditions.checkNotNull(userId);
-
- getUserService().getUser(userId);
-
- return getPersistenceContext().getPollDao().findAllCreated(userId);
- }
-
- public Set<Poll> getInvitedPolls(String userId) throws EntityNotFoundException {
- Preconditions.checkNotNull(userId);
-
- getUserService().getUser(userId);
-
- return getPersistenceContext().getPollDao().findAllInvited(userId);
- }
-
- public Set<Poll> getParticipatedPolls(String userId) throws EntityNotFoundException {
- Preconditions.checkNotNull(userId);
-
- getUserService().getUser(userId);
-
- return getPersistenceContext().getPollDao().findAllParticipated(userId);
- }
-
- public Poll getPoll(String pollId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Poll result = getPersistenceContext().getPollDao().findById(pollId);
- checkEntityExists(Poll.class, result, pollId);
- return result;
- }
-
- public Poll createPoll(String userId, Poll poll) throws EntityNotFoundException {
- Preconditions.checkNotNull(userId);
- Preconditions.checkNotNull(poll);
- checkHasNoId(poll);
-
- if (userId != null) {
-
- // get user
- PollenUser user = getUserService().getUser(userId);
-
- // link it to creator
-
- }
-
- getPersistenceContext().getPollDao().persist(poll);
-
- getPersistenceContext().commit();
- return poll;
- }
-
- public Poll editPoll(Poll poll) throws EntityNotFoundException {
- Preconditions.checkNotNull(poll);
- checkHasId(poll);
-
- getPoll(poll.getId());
-
- getPersistenceContext().getPollDao().merge(poll);
- getPersistenceContext().commit();
-
- Poll result = getPoll(poll.getId());
- return result;
- }
-
- public void deletePoll(String pollId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
-
- Poll poll = getPoll(pollId);
-
- getPersistenceContext().getPollDao().remove(poll);
- getPersistenceContext().commit();
- }
-
- public Poll clonePoll(String pollId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
-
- Poll poll = getPoll(pollId);
- //TODO
- getPersistenceContext().commit();
- return null;
- }
-
- public File closePoll(String pollId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
-
- Poll poll = getPoll(pollId);
- //TODO
- getPersistenceContext().commit();
- return null;
- }
-
- public File exportPoll(String pollId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Poll poll = getPoll(pollId);
- //TODO
- return null;
- }
-
- public List<Choice> getChoices(String pollId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
-
- Poll poll = getPoll(pollId);
-
- return poll.getChoice();
- }
-
- public Choice getChoice(String choiceId) throws EntityNotFoundException {
- Preconditions.checkNotNull(choiceId);
-
- Choice result = getPersistenceContext().getChoiceDao().findById(choiceId);
- checkEntityExists(Choice.class, result, choiceId);
- return result;
- }
-
- public Choice addChoice(String pollId, Choice choice) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(choice);
- checkHasNoId(choice);
-
- Poll poll = getPoll(pollId);
-
- poll.addChoice(choice);
-
- getPersistenceContext().getPollDao().merge(poll);
-
- getPersistenceContext().commit();
- Choice result = getChoice(choice.getId());
- return result;
- }
-
- public Choice editChoice(Choice choice) throws EntityNotFoundException {
- Preconditions.checkNotNull(choice);
- checkHasId(choice);
-
- getChoice(choice.getId());
-
- getPersistenceContext().getChoiceDao().merge(choice);
- getPersistenceContext().commit();
-
- Choice result = getChoice(choice.getId());
- return result;
- }
-
- public void deleteChoice(String pollId, String choiceId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(choiceId);
-
- Poll poll = getPoll(pollId);
- Choice choice = getChoice(choiceId);
-
- poll.removeChoice(choice);
-
- getPersistenceContext().getPollDao().merge(poll);
-
- getPersistenceContext().commit();
- }
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenFixtures.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenFixtures.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenFixtures.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,78 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.esotericsoftware.yamlbeans.YamlException;
-import com.esotericsoftware.yamlbeans.YamlReader;
-import org.apache.commons.io.Charsets;
-import org.apache.commons.io.IOUtils;
-import org.chorem.pollen.persistence.entity.Choice;
-import org.chorem.pollen.persistence.entity.Comment;
-import org.chorem.pollen.persistence.entity.FavoriteList;
-import org.chorem.pollen.persistence.entity.FavoriteListMember;
-import org.chorem.pollen.persistence.entity.Poll;
-import org.chorem.pollen.persistence.entity.PollenUser;
-import org.chorem.pollen.persistence.entity.Vote;
-import org.chorem.pollen.persistence.entity.VoterList;
-import org.chorem.pollen.persistence.entity.VoterListMember;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map;
-
-public class PollenFixtures {
-
- protected Map<String, Object> fixtures;
-
- public PollenFixtures(String fixturesName) {
- String yamlPath = "/" + fixturesName + ".yaml";
- InputStream inputStream = PollenFixtures.class.getResourceAsStream(yamlPath);
- String yaml;
- try {
- yaml = IOUtils.toString(inputStream, Charsets.UTF_8);
- } catch (IOException e) {
- throw new IllegalArgumentException(fixturesName + " is not a valid fixtures set name", e);
- }
- YamlReader reader = new YamlReader(yaml);
- reader.getConfig().setClassTag("poll", Poll.class);
- reader.getConfig().setClassTag("user", PollenUser.class);
- reader.getConfig().setClassTag("favorite-list", FavoriteList.class);
- reader.getConfig().setClassTag("favorite-list-member", FavoriteListMember.class);
- reader.getConfig().setClassTag("comment", Comment.class);
- reader.getConfig().setClassTag("choice", Choice.class);
- reader.getConfig().setClassTag("voter-list", VoterList.class);
- reader.getConfig().setClassTag("voter-list-member", VoterListMember.class);
- reader.getConfig().setClassTag("vote", Vote.class);
-
- try {
- fixtures = (Map<String, Object>) reader.read();
- } catch (YamlException e) {
- throw new PollenTechnicalException("unable to read yaml file", e);
- }
- }
-
- public <E> E fixture(String id) {
- return (E) fixtures.get(id);
- }
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenServiceContext.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,66 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.chorem.pollen.persistence.PollenPersistenceContext;
-import org.chorem.pollen.service.config.PollenServiceConfig;
-
-import java.util.Date;
-
-/**
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface PollenServiceContext {
-
- String generateUUID();
-
- Date getNow();
-
- PollenPersistenceContext getPersistenceContext();
-
- PollenServiceConfig getPollenServiceConfig();
-
- AuthService getAuthService();
-
- CommentService getCommentService();
-
- FavoriteListService getFavoriteListService();
-
- PollService getPollService();
-
- UserService getUserService();
-
- VoteCountingService getVoteCountingService();
-
- VoterListService getVoterListService();
-
- VoteService getVoteService();
-
- EmailService getEmailService();
-
- String generatePassword();
-
- String encodePassword(String password);
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenServiceSupport.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceSupport.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenServiceSupport.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,35 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public interface PollenServiceSupport {
-
- void setServiceContext(PollenServiceContext serviceContext);
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenTechnicalException.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenTechnicalException.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/PollenTechnicalException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,44 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-public class PollenTechnicalException extends RuntimeException {
-
- private static final long serialVersionUID = 1L;
-
- public PollenTechnicalException() {
- }
-
- public PollenTechnicalException(String message) {
- super(message);
- }
-
- public PollenTechnicalException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public PollenTechnicalException(Throwable cause) {
- super(cause);
- }
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/UserService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/UserService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,244 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import org.apache.commons.lang3.ObjectUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.chorem.pollen.persistence.dao.PollenUserJpaDao;
-import org.chorem.pollen.persistence.entity.PollenUser;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-import org.chorem.pollen.service.exception.UserEmailAlreadyUsedException;
-import org.chorem.pollen.service.exception.UserInvalidEmailActiviationTokenException;
-import org.chorem.pollen.service.exception.UserInvalidPasswordException;
-import org.chorem.pollen.service.exception.UserLoginAlreadyUsedException;
-import org.nuiton.util.beans.Binder;
-import org.nuiton.util.beans.BinderFactory;
-
-import java.util.List;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class UserService extends AbstractPollenService implements PollenServiceSupport {
-
- public List<PollenUser> getUsers() {
- return getPollenUserDao().findAll();
- }
-
- public PollenUser getUser(String userId) throws EntityNotFoundException {
- Preconditions.checkNotNull(userId);
-
- PollenUser result = getPollenUserDao().findById(userId);
- checkEntityExists(PollenUser.class, result, userId);
- return result;
- }
-
- public PollenUser createUser(PollenUser user, boolean generatePassword) throws UserLoginAlreadyUsedException, UserEmailAlreadyUsedException {
- Preconditions.checkNotNull(user);
- checkHasNoId(user);
- Preconditions.checkNotNull(user.getLogin());
- Preconditions.checkNotNull(user.getEmail());
-
- PollenUserJpaDao dao = getPollenUserDao();
-
- // check login is available
- boolean loginExists = dao.loginExists(user.getLogin());
- if (loginExists) {
- throw new UserLoginAlreadyUsedException(user.getLogin());
- }
-
- // check email is available
- boolean emailExists = dao.emailExists(user.getEmail());
- if (emailExists) {
- throw new UserEmailAlreadyUsedException(user.getEmail());
- }
-
- PollenUser toCreate = dao.newInstance();
-
- // add a emailValidationToken
- String emailValidationToken = generateId();
-
- String password;
- if (generatePassword) {
- // let's generate the new password
- password = serviceContext.generatePassword();
- } else {
- password = user.getPassword();
- }
-
- // encode the password
- String encodedPassword = serviceContext.encodePassword(password);
-
- toCreate.setLogin(user.getLogin());
- toCreate.setEmailActivationToken(emailValidationToken);
- toCreate.setPassword(encodedPassword);
-
- copyPollenUser(user, toCreate, true);
-
- dao.persist(toCreate);
- getPersistenceContext().commit();
-
- notifyUserCreated(toCreate);
-
- return toCreate;
- }
-
- public PollenUser editUser(PollenUser user) throws UserInvalidPasswordException, UserEmailAlreadyUsedException, EntityNotFoundException {
- Preconditions.checkNotNull(user);
- checkHasId(user);
-
- PollenUser persisted = getUser(user.getId());
-
- PollenUserJpaDao dao = getPollenUserDao();
-
- // check current password
- String encodedPassword = serviceContext.encodePassword(user.getPassword());
- if (!encodedPassword.equals(persisted.getPassword())) {
- throw new UserInvalidPasswordException();
- }
-
- boolean emailChanged = ObjectUtils.notEqual(persisted.getEmail(),
- user.getEmail());
-
- if (emailChanged) {
-
- // check this email is not used by another user
- boolean emailUsed = dao.emailExists(user.getEmail());
- if (emailUsed) {
- throw new UserEmailAlreadyUsedException(user.getEmail());
- }
-
- // add a new emailValidationtoken
- String emailValidationToken = generateId();
- persisted.setEmailActivationToken(emailValidationToken);
- }
-
- copyPollenUser(user, persisted, true);
-
- persisted = dao.merge(persisted);
- getPersistenceContext().commit();
-
- if (emailChanged) {
-
- notifyEmailChanged(persisted);
- }
- return persisted;
- }
-
- public void changePassword(String userId,
- String oldPassword,
- String newPassword) throws UserInvalidPasswordException, EntityNotFoundException {
- Preconditions.checkNotNull(userId);
- Preconditions.checkNotNull(oldPassword);
- Preconditions.checkNotNull(newPassword);
-
- PollenUser user = getUser(userId);
-
- // check current password
- String encodedPassword = serviceContext.encodePassword(user.getPassword());
- if (!encodedPassword.equals(user.getPassword())) {
- throw new UserInvalidPasswordException();
- }
-
- // encode new password and store it in user account
- String newEncodedPassword = serviceContext.encodePassword(newPassword);
- user.setPassword(newEncodedPassword);
-
- user = getPollenUserDao().merge(user);
- getPersistenceContext().commit();
-
- notifyPasswordChanged(user);
- }
-
- public void validateUserEmail(String userId,
- String token) throws EntityNotFoundException, UserInvalidEmailActiviationTokenException {
-
- Preconditions.checkNotNull(userId);
- Preconditions.checkNotNull(token);
-
- PollenUser user = getUser(userId);
-
- Preconditions.checkNotNull(user);
-
- boolean valid = ObjectUtils.equals(
- user.getEmailActivationToken(), token);
-
- if (!valid) {
- throw new UserInvalidEmailActiviationTokenException();
- }
-
- // reset token in database
- user.setEmailActivationToken(null);
-
- getPollenUserDao().merge(user);
- getPersistenceContext().commit();
- }
-
- protected void notifyUserCreated(PollenUser user) {
-
- //TODO
- }
-
- protected void notifyEmailChanged(PollenUser user) {
-
- //TODO
- }
-
- protected void notifyPasswordChanged(PollenUser user) {
-
- //TODO
- }
-
- protected PollenUserJpaDao getPollenUserDao() {
- return getPersistenceContext().getPollenUserDao();
- }
-
- /**
- * Copy {@code source} user account to {@code destination} one.
- * The email is lower cased in the {@code destination} user account.
- *
- * @param source user account to copy
- * @param destination which receive the copy
- */
- protected void copyPollenUser(PollenUser source,
- PollenUser destination,
- boolean copyEmail) {
- Binder<PollenUser, PollenUser> binder =
- BinderFactory.newBinder(PollenUser.class);
-
- binder.copy(source, destination,
- PollenUser.PROPERTY_ADMINISTRATOR,
- PollenUser.PROPERTY_NAME,
- PollenUser.PROPERTY_LANGUAGE);
-
- if (copyEmail) {
- // Don't keep case for email
- destination.setEmail(StringUtils.lowerCase(source.getEmail()));
- }
- }
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/VoteCountingService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteCountingService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/VoteCountingService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,45 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import org.chorem.pollen.persistence.entity.Poll;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class VoteCountingService extends AbstractPollenService {
-
- //GET /poll/{pollId}/results
- public PollResult getResult(String pollId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Poll poll = getPollService().getPoll(pollId);
- //TODO
- return null;
- }
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/VoteService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/VoteService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,100 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import org.chorem.pollen.persistence.entity.Poll;
-import org.chorem.pollen.persistence.entity.Vote;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-
-import java.util.List;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class VoteService extends AbstractPollenService {
-
- public List<Vote> getVotes(String pollId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
-
- Poll poll = getPollService().getPoll(pollId);
- List<Vote> result = poll.getVote();
- return result;
- }
-
- public Vote getVote(String voteId) throws EntityNotFoundException{
- Preconditions.checkNotNull(voteId);
-
- Vote result = getPersistenceContext().getVoteDao().findById(voteId);
- checkEntityExists(Vote.class, result, voteId);
- return result;
- }
-
- public Vote addVote(String pollId, Vote vote)throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(vote);
- checkHasNoId(vote);
-
- Poll poll = getPollService().getPoll(pollId);
-
- poll.addVote(vote);
- getPersistenceContext().getPollDao().merge(poll);
-
- getPersistenceContext().commit();
- Vote result = getVote(vote.getId());
- return result;
- }
-
- public Vote editVote(Vote vote)throws EntityNotFoundException {
- Preconditions.checkNotNull(vote);
- checkHasId(vote);
-
- getVote(vote.getId());
-
- getPersistenceContext().getVoteDao().merge(vote);
- getPersistenceContext().commit();
-
- Vote result = getVote(vote.getId());
- return result;
- }
-
- public void deleteVote(String pollId, String voteId)throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(voteId);
-
- Poll poll = getPollService().getPoll(pollId);
-
- Vote vote = getVote(voteId);
-
- poll.removeVote(vote);
-
- getPersistenceContext().getPollDao().merge(poll);
-
- getPersistenceContext().commit();
- }
-
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/VoterListService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoterListService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/VoterListService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,200 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import com.google.common.base.Preconditions;
-import org.chorem.pollen.persistence.dao.VoterListJpaDao;
-import org.chorem.pollen.persistence.dao.VoterListMemberJpaDao;
-import org.chorem.pollen.persistence.entity.FavoriteList;
-import org.chorem.pollen.persistence.entity.FavoriteListMember;
-import org.chorem.pollen.persistence.entity.Poll;
-import org.chorem.pollen.persistence.entity.VoterList;
-import org.chorem.pollen.persistence.entity.VoterListMember;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class VoterListService extends AbstractPollenService {
-
- public VoterList importFavoriteList(String pollId,
- String favoriteListId) throws EntityNotFoundException {
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(favoriteListId);
-
- Poll poll = getPollService().getPoll(pollId);
-
- FavoriteList favoriteList = getFavoriteListService().getFavoriteList(favoriteListId);
-
- VoterListJpaDao dao = getPersistenceContext().getVoterListDao();
- VoterList result = dao.newInstance();
-
- result.setName(favoriteList.getName());
- result.setWeight(1d);
-
- VoterListMemberJpaDao voterListMemberDao =
- getPersistenceContext().getVoterListMemberDao();
-
- for (FavoriteListMember favoriteListMember : favoriteList.getFavoriteListMember()) {
-
- VoterListMember voterListMember = voterListMemberDao.newInstance();
- voterListMember.setWeight(1d);
- voterListMember.setEmail(favoriteListMember.getEmail());
- result.addVoterListMember(voterListMember);
- }
-
- poll.addVoterList(result);
-
- getPersistenceContext().getPollDao().merge(poll);
-
- getPersistenceContext().commit();
- return result;
- }
-
- public List<VoterList> getVoterLists(String pollId) throws EntityNotFoundException{
- Preconditions.checkNotNull(pollId);
-
- Poll poll = getPollService().getPoll(pollId);
-
- List<VoterList> result = poll.getVoterList();
- return result;
- }
-
- public VoterList getVoterList(String voterListId) throws EntityNotFoundException{
- Preconditions.checkNotNull(voterListId);
-
- VoterList result = getPersistenceContext().getVoterListDao().findById(voterListId);
- checkEntityExists(VoterList.class, result, voterListId);
-
- return result;
- }
-
- public VoterList addVoterList(String pollId, VoterList voterList) throws EntityNotFoundException{
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(voterList);
- checkHasNoId(voterList);
-
- Poll poll = getPollService().getPoll(pollId);
-
- poll.addVoterList(voterList);
-
- getPersistenceContext().getPollDao().merge(poll);
- getPersistenceContext().commit();
- VoterList result = getVoterList(voterList.getId());
- return result;
- }
-
- public VoterList editVoterList(VoterList voterList) throws EntityNotFoundException{
- Preconditions.checkNotNull(voterList);
- checkHasId(voterList);
-
- getVoterList(voterList.getId());
-
- getPersistenceContext().getVoterListDao().merge(voterList);
- getPersistenceContext().commit();
- VoterList result = getVoterList(voterList.getId());
- return result;
- }
-
- public void deleteVoterList(String pollId, String voterListId) throws EntityNotFoundException{
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(voterListId);
-
- Poll poll = getPollService().getPoll(pollId);
-
- VoterList voterList = getVoterList(voterListId);
-
- poll.removeVoterList(voterList);
-
- getPersistenceContext().getPollDao().merge(poll);
-
- getPersistenceContext().commit();
- }
-
- public Set<VoterListMember> getMembers(String voterListId) throws EntityNotFoundException{
- Preconditions.checkNotNull(voterListId);
-
- VoterList voterList = getVoterList(voterListId);
-
- Set<VoterListMember> result = voterList.getVoterListMember();
- return result;
- }
-
- public VoterListMember getMember(String memberId) throws EntityNotFoundException{
- Preconditions.checkNotNull(memberId);
-
- VoterListMember result = getPersistenceContext().getVoterListMemberDao().findById(memberId);
- checkEntityExists(VoterListMember.class, result, memberId);
- return result;
- }
-
- public VoterListMember addMember(String voterListId, VoterListMember member)throws EntityNotFoundException {
- Preconditions.checkNotNull(voterListId);
- Preconditions.checkNotNull(member);
- checkHasNoId(member);
-
- VoterList voterList = getVoterList(voterListId);
-
- voterList.addVoterListMember(member);
- getPersistenceContext().getVoterListDao().merge(voterList);
-
- getPersistenceContext().commit();
- VoterListMember result = getMember(member.getId());
- return result;
- }
-
- public VoterListMember editMember(VoterListMember member) throws EntityNotFoundException{
- Preconditions.checkNotNull(member);
- checkHasId(member);
-
- getMember(member.getId());
-
- getPersistenceContext().getVoterListMemberDao().merge(member);
-
- getPersistenceContext().commit();
- VoterListMember result = getMember(member.getId());
- return result;
- }
-
- public void deleteMember(String voterListId, String memberId) throws EntityNotFoundException{
- Preconditions.checkNotNull(voterListId);
- Preconditions.checkNotNull(memberId);
-
- VoterList voterList = getVoterList(voterListId);
-
- VoterListMember member = getMember(memberId);
- voterList.removeVoterListMember(member);
-
- getPersistenceContext().getVoterListDao().merge(voterList);
-
- getPersistenceContext().commit();
- }
-
-}
Deleted: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/package-info.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/package-info.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/service/package-info.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,30 +0,0 @@
-/**
- * Base Package for the pollen business service.
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/DefaultPollenServiceContext.java (from rev 3821, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/DefaultPollenServiceContext.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/DefaultPollenServiceContext.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,188 @@
+package org.chorem.pollen.services;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.chorem.pollen.persistence.PollenEntityIdFactory;
+import org.chorem.pollen.persistence.PollenPersistenceContext;
+import org.chorem.pollen.services.config.PollenServiceConfig;
+import org.chorem.pollen.services.service.AuthService;
+import org.chorem.pollen.services.service.CommentService;
+import org.chorem.pollen.services.service.EmailService;
+import org.chorem.pollen.services.service.FavoriteListService;
+import org.chorem.pollen.services.service.FixturesService;
+import org.chorem.pollen.services.service.PollService;
+import org.chorem.pollen.services.service.UserService;
+import org.chorem.pollen.services.service.VoteCountingService;
+import org.chorem.pollen.services.service.VoteService;
+import org.chorem.pollen.services.service.VoterListService;
+import org.nuiton.util.StringUtil;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Date;
+import java.util.Locale;
+
+public class DefaultPollenServiceContext implements PollenServiceContext {
+
+ protected PollenServiceConfig pollenServiceConfig;
+
+ protected PollenPersistenceContext persistenceContext;
+
+ protected Locale locale;
+
+ public void setPollenServiceConfig(PollenServiceConfig pollenServiceConfig) {
+ this.pollenServiceConfig = pollenServiceConfig;
+ }
+
+ public void setPersistenceContext(PollenPersistenceContext persistenceContext) {
+ this.persistenceContext = persistenceContext;
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
+
+ @Override
+ public PollenServiceConfig getPollenServiceConfig() {
+ return pollenServiceConfig;
+ }
+
+ @Override
+ public String generateToken() {
+ return PollenEntityIdFactory.generateId();
+ }
+
+ @Override
+ public Date getNow() {
+ Date now = new Date();
+ return now;
+ }
+
+ public String generatePassword() {
+ return RandomStringUtils.randomAlphanumeric(8);
+ }
+
+ @Override
+ public PollenPersistenceContext getPersistenceContext() {
+ return persistenceContext;
+ }
+
+ @Override
+ public AuthService getAuthService() {
+ return newService(AuthService.class);
+ }
+
+ @Override
+ public CommentService getCommentService() {
+ return newService(CommentService.class);
+ }
+
+ @Override
+ public FavoriteListService getFavoriteListService() {
+ return newService(FavoriteListService.class);
+ }
+
+ @Override
+ public PollService getPollService() {
+ return newService(PollService.class);
+ }
+
+ @Override
+ public UserService getUserService() {
+ return newService(UserService.class);
+ }
+
+ @Override
+ public VoteCountingService getVoteCountingService() {
+ return newService(VoteCountingService.class);
+ }
+
+ @Override
+ public VoterListService getVoterListService() {
+ return newService(VoterListService.class);
+ }
+
+ @Override
+ public VoteService getVoteService() {
+ return newService(VoteService.class);
+ }
+
+ @Override
+ public EmailService getEmailService() {
+ return newService(EmailService.class);
+ }
+
+ @Override
+ public FixturesService getFixturesService() {
+ return newService(FixturesService.class);
+ }
+
+ @Override
+ public String encodePassword(String password) {
+ return StringUtil.encodeMD5(password);
+ }
+
+ @Override
+ public Locale getLocale() {
+ if (locale==null) {
+ locale = Locale.getDefault();
+ }
+ return locale;
+ }
+
+ public <E extends PollenServiceSupport> E newService(Class<E> serviceClass) {
+
+ E service;
+
+ try {
+
+ Constructor<E> constructor = serviceClass.getConstructor();
+
+ service = constructor.newInstance();
+
+ } catch (NoSuchMethodException e) {
+
+ throw new PollenTechnicalException("all services must provide a default public constructor", e);
+
+ } catch (InvocationTargetException e) {
+
+ throw new PollenTechnicalException("unable to instantiate pollen service", e);
+
+ } catch (InstantiationException e) {
+
+ throw new PollenTechnicalException("unable to instantiate pollen service", e);
+
+ } catch (IllegalAccessException e) {
+
+ throw new PollenTechnicalException("unable to instantiate pollen service", e);
+ }
+
+ service.setServiceContext(this);
+
+ return service;
+
+ }
+
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollResult.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollResult.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollResult.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollResult.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,36 @@
+package org.chorem.pollen.services;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import java.io.Serializable;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class PollResult implements Serializable {
+ private static final long serialVersionUID = 1L;
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenFixtures.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenFixtures.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenFixtures.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenFixtures.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,78 @@
+package org.chorem.pollen.services;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.esotericsoftware.yamlbeans.YamlException;
+import com.esotericsoftware.yamlbeans.YamlReader;
+import org.apache.commons.io.Charsets;
+import org.apache.commons.io.IOUtils;
+import org.chorem.pollen.persistence.entity.Choice;
+import org.chorem.pollen.persistence.entity.Comment;
+import org.chorem.pollen.persistence.entity.FavoriteList;
+import org.chorem.pollen.persistence.entity.FavoriteListMember;
+import org.chorem.pollen.persistence.entity.Poll;
+import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.persistence.entity.Vote;
+import org.chorem.pollen.persistence.entity.VoterList;
+import org.chorem.pollen.persistence.entity.VoterListMember;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+public class PollenFixtures {
+
+ protected Map<String, Object> fixtures;
+
+ public PollenFixtures(String fixturesName) {
+ String yamlPath = "/" + fixturesName + ".yaml";
+ InputStream inputStream = PollenFixtures.class.getResourceAsStream(yamlPath);
+ String yaml;
+ try {
+ yaml = IOUtils.toString(inputStream, Charsets.UTF_8);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(fixturesName + " is not a valid fixtures set name", e);
+ }
+ YamlReader reader = new YamlReader(yaml);
+ reader.getConfig().setClassTag("poll", Poll.class);
+ reader.getConfig().setClassTag("user", PollenUser.class);
+ reader.getConfig().setClassTag("favorite-list", FavoriteList.class);
+ reader.getConfig().setClassTag("favorite-list-member", FavoriteListMember.class);
+ reader.getConfig().setClassTag("comment", Comment.class);
+ reader.getConfig().setClassTag("choice", Choice.class);
+ reader.getConfig().setClassTag("voter-list", VoterList.class);
+ reader.getConfig().setClassTag("voter-list-member", VoterListMember.class);
+ reader.getConfig().setClassTag("vote", Vote.class);
+
+ try {
+ fixtures = (Map<String, Object>) reader.read();
+ } catch (YamlException e) {
+ throw new PollenTechnicalException("unable to read yaml file", e);
+ }
+ }
+
+ public <E> E fixture(String id) {
+ return (E) fixtures.get(id);
+ }
+}
Added: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenSecurityContext.java
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenSecurityContext.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenSecurityContext.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,10 @@
+package org.chorem.pollen.services;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class PollenSecurityContext {
+}
Property changes on: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenSecurityContext.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenServiceContext.java (from rev 3821, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenServiceContext.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenServiceContext.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,81 @@
+package org.chorem.pollen.services;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.chorem.pollen.persistence.PollenPersistenceContext;
+import org.chorem.pollen.services.config.PollenServiceConfig;
+import org.chorem.pollen.services.service.AuthService;
+import org.chorem.pollen.services.service.CommentService;
+import org.chorem.pollen.services.service.EmailService;
+import org.chorem.pollen.services.service.FavoriteListService;
+import org.chorem.pollen.services.service.FixturesService;
+import org.chorem.pollen.services.service.PollService;
+import org.chorem.pollen.services.service.UserService;
+import org.chorem.pollen.services.service.VoteCountingService;
+import org.chorem.pollen.services.service.VoteService;
+import org.chorem.pollen.services.service.VoterListService;
+
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public interface PollenServiceContext {
+
+ String generateToken();
+
+ Date getNow();
+
+ PollenPersistenceContext getPersistenceContext();
+
+ PollenServiceConfig getPollenServiceConfig();
+
+ AuthService getAuthService();
+
+ CommentService getCommentService();
+
+ FavoriteListService getFavoriteListService();
+
+ PollService getPollService();
+
+ UserService getUserService();
+
+ VoteCountingService getVoteCountingService();
+
+ VoterListService getVoterListService();
+
+ VoteService getVoteService();
+
+ EmailService getEmailService();
+
+ FixturesService getFixturesService();
+
+ String generatePassword();
+
+ String encodePassword(String password);
+
+ Locale getLocale();
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenServiceSupport.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceSupport.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenServiceSupport.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenServiceSupport.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,35 @@
+package org.chorem.pollen.services;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public interface PollenServiceSupport {
+
+ void setServiceContext(PollenServiceContext serviceContext);
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenTechnicalException.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenTechnicalException.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenTechnicalException.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/PollenTechnicalException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,44 @@
+package org.chorem.pollen.services;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+public class PollenTechnicalException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public PollenTechnicalException() {
+ }
+
+ public PollenTechnicalException(String message) {
+ super(message);
+ }
+
+ public PollenTechnicalException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public PollenTechnicalException(Throwable cause) {
+ super(cause);
+ }
+}
Modified: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServiceConfig.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/config/PollenServiceConfig.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServiceConfig.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,4 +1,4 @@
-package org.chorem.pollen.service.config;
+package org.chorem.pollen.services.config;
/*
* #%L
@@ -27,7 +27,7 @@
import com.google.common.collect.Maps;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.chorem.pollen.service.PollenTechnicalException;
+import org.chorem.pollen.services.PollenTechnicalException;
import org.nuiton.util.config.ApplicationConfig;
import org.nuiton.util.config.ArgumentsParserException;
Modified: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServiceConfigOption.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/config/PollenServiceConfigOption.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServiceConfigOption.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,4 +1,4 @@
-package org.chorem.pollen.service.config;
+package org.chorem.pollen.services.config;
/*
* #%L
Modified: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/package-info.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/config/package-info.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/config/package-info.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -4,7 +4,7 @@
* @author tchemit <chemit(a)codelutin.com>
* @since 2.0
*/
-package org.chorem.pollen.service.config;
+package org.chorem.pollen.services.config;
/*
* #%L
Modified: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/EntityNotFoundException.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/EntityNotFoundException.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/EntityNotFoundException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,4 +1,4 @@
-package org.chorem.pollen.service.exception;
+package org.chorem.pollen.services.exception;
/*
* #%L
Added: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListImportException.java
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListImportException.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListImportException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,30 @@
+package org.chorem.pollen.services.exception;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class FavoriteListImportException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+
+ private String causeMessage;
+
+ public FavoriteListImportException(String causeMessage, Throwable cause) {
+ super(cause);
+ this.causeMessage = causeMessage;
+ }
+
+ public FavoriteListImportException(Throwable cause) {
+ this(cause.getMessage(), cause);
+ }
+
+ /** @return the error message source from import execution. */
+ public String getCauseMessage() {
+ return causeMessage;
+ }
+
+}
Property changes on: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListImportException.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Added: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberEmailAlreadyUsedException.java
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberEmailAlreadyUsedException.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberEmailAlreadyUsedException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,22 @@
+package org.chorem.pollen.services.exception;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class FavoriteListMemberEmailAlreadyUsedException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ protected final String email;
+
+ public FavoriteListMemberEmailAlreadyUsedException(String email) {
+ this.email = email;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+}
\ No newline at end of file
Property changes on: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberEmailAlreadyUsedException.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Added: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNameAlreadyUsedException.java
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNameAlreadyUsedException.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNameAlreadyUsedException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,22 @@
+package org.chorem.pollen.services.exception;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class FavoriteListMemberNameAlreadyUsedException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ protected final String name;
+
+ public FavoriteListMemberNameAlreadyUsedException(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
\ No newline at end of file
Property changes on: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNameAlreadyUsedException.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Added: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNotOwnedByFavoriteListException.java
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNotOwnedByFavoriteListException.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNotOwnedByFavoriteListException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,11 @@
+package org.chorem.pollen.services.exception;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class FavoriteListMemberNotOwnedByFavoriteListException extends Throwable {
+ private static final long serialVersionUID = 1L;
+}
Property changes on: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListMemberNotOwnedByFavoriteListException.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Added: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNameAlreadyUsedException.java
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNameAlreadyUsedException.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNameAlreadyUsedException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,22 @@
+package org.chorem.pollen.services.exception;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class FavoriteListNameAlreadyUsedException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ protected final String name;
+
+ public FavoriteListNameAlreadyUsedException(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
\ No newline at end of file
Property changes on: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNameAlreadyUsedException.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Added: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNotOwnedByUserException.java
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNotOwnedByUserException.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNotOwnedByUserException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,12 @@
+package org.chorem.pollen.services.exception;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class FavoriteListNotOwnedByUserException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+}
Property changes on: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/FavoriteListNotOwnedByUserException.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Added: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/InvalidSessionTokenException.java
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/InvalidSessionTokenException.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/InvalidSessionTokenException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,12 @@
+package org.chorem.pollen.services.exception;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class InvalidSessionTokenException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+}
Property changes on: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/InvalidSessionTokenException.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserEmailAlreadyUsedException.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserEmailAlreadyUsedException.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserEmailAlreadyUsedException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,4 +1,4 @@
-package org.chorem.pollen.service.exception;
+package org.chorem.pollen.services.exception;
/*
* #%L
Modified: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserInvalidEmailActiviationTokenException.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidEmailActiviationTokenException.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserInvalidEmailActiviationTokenException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,4 +1,4 @@
-package org.chorem.pollen.service.exception;
+package org.chorem.pollen.services.exception;
/*
* #%L
Modified: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserInvalidPasswordException.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidPasswordException.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserInvalidPasswordException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,4 +1,4 @@
-package org.chorem.pollen.service.exception;
+package org.chorem.pollen.services.exception;
/*
* #%L
Modified: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserLoginAlreadyUsedException.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserLoginAlreadyUsedException.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exception/UserLoginAlreadyUsedException.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,4 +1,4 @@
-package org.chorem.pollen.service.exception;
+package org.chorem.pollen.services.exception;
/*
* #%L
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/package-info.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/package-info.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/package-info.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/package-info.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,30 @@
+/**
+ * Base Package for the pollen business service.
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+package org.chorem.pollen.services;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/AbstractPollenService.java (from rev 3821, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/AbstractPollenService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/AbstractPollenService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,119 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import org.chorem.pollen.persistence.PollenPersistenceContext;
+import org.chorem.pollen.services.PollenServiceContext;
+import org.chorem.pollen.services.PollenServiceSupport;
+import org.chorem.pollen.services.config.PollenServiceConfig;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+import org.nuiton.jpa.api.JpaEntities;
+import org.nuiton.jpa.api.JpaEntity;
+
+import java.util.Date;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public abstract class AbstractPollenService implements PollenServiceSupport {
+
+ protected PollenServiceContext serviceContext;
+
+ protected void checkHasId(JpaEntity entity) {
+ Preconditions.checkState(JpaEntities.isEntityHasId(entity));
+ }
+
+ protected void checkHasNoId(JpaEntity entity) {
+ Preconditions.checkState(JpaEntities.isEntityHasNoId(entity));
+ }
+
+ @Override
+ public void setServiceContext(PollenServiceContext serviceContext) {
+ this.serviceContext = serviceContext;
+ }
+
+ protected Date getNow() {
+ return serviceContext.getNow();
+ }
+
+ protected String generateToken() {
+ return serviceContext.generateToken();
+ }
+
+ protected PollenPersistenceContext getPersistenceContext() {
+ return serviceContext.getPersistenceContext();
+ }
+
+ protected PollenServiceConfig getPollenServiceConfig() {
+ return serviceContext.getPollenServiceConfig();
+ }
+
+ protected AuthService getAuthService() {
+ return serviceContext.getAuthService();
+ }
+
+ protected CommentService getCommentService() {
+ return serviceContext.getCommentService();
+ }
+
+ protected FavoriteListService getFavoriteListService() {
+ return serviceContext.getFavoriteListService();
+ }
+
+ protected PollService getPollService() {
+ return serviceContext.getPollService();
+ }
+
+ protected UserService getUserService() {
+ return serviceContext.getUserService();
+ }
+
+ protected VoteCountingService getVoteCountingService() {
+ return serviceContext.getVoteCountingService();
+ }
+
+ protected VoterListService getVoterListService() {
+ return serviceContext.getVoterListService();
+ }
+
+ protected VoteService getVoteService() {
+ return serviceContext.getVoteService();
+ }
+
+ protected EmailService getEmailService() {
+ return serviceContext.getEmailService();
+ }
+
+ protected <E extends JpaEntity> void checkEntityExists(Class<E> type,
+ E entity,
+ String entityId) throws EntityNotFoundException {
+ if (entity == null) {
+ throw new EntityNotFoundException(type, entityId);
+ }
+ }
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/AuthService.java (from rev 3821, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/AuthService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/AuthService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,127 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import org.chorem.pollen.persistence.dao.PollenUserJpaDao;
+import org.chorem.pollen.persistence.dao.SessionTokenJpaDao;
+import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.persistence.entity.SessionToken;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+import org.chorem.pollen.services.exception.InvalidSessionTokenException;
+import org.chorem.pollen.services.exception.UserInvalidPasswordException;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class AuthService extends AbstractPollenService {
+
+ public String login(String login, String password) throws EntityNotFoundException, UserInvalidPasswordException {
+ Preconditions.checkNotNull(login);
+ Preconditions.checkNotNull(password);
+
+ PollenUser user = getPersistenceContext().getPollenUserDao().findByLogin(login);
+ if (user == null) {
+ throw new EntityNotFoundException(PollenUser.class, login);
+ }
+
+ String encodedPassword = serviceContext.encodePassword(password);
+ if (!encodedPassword.equals(user.getPassword())) {
+ throw new UserInvalidPasswordException();
+ }
+
+ // Create a new session Token
+ SessionTokenJpaDao dao = getPersistenceContext().getSessionTokenDao();
+
+ SessionToken sessionToken = dao.newInstance();
+ String token = serviceContext.generateToken();
+ String encodedToken = serviceContext.encodePassword(token);
+ sessionToken.setPollenUser(user);
+ sessionToken.setToken(encodedToken);
+ sessionToken.setCreationDate(serviceContext.getNow());
+
+ dao.persist(sessionToken);
+ getPersistenceContext().commit();
+
+ return token;
+ }
+
+ public void lostPassword(String login) throws EntityNotFoundException {
+ Preconditions.checkNotNull(login);
+
+ PollenUserJpaDao dao = getPersistenceContext().getPollenUserDao();
+
+ PollenUser user = dao.findByLogin(login);
+ if (user == null) {
+ throw new EntityNotFoundException(PollenUser.class, login);
+ }
+
+ // Generate a new password
+ String newPassword = serviceContext.generatePassword();
+ String encodedPassword = serviceContext.encodePassword(newPassword);
+ user.setPassword(encodedPassword);
+ dao.merge(user);
+ getPersistenceContext().commit();
+
+ notifyPasswordChanged(user, newPassword);
+ }
+
+ public void logout(String login, String token) throws EntityNotFoundException {
+ Preconditions.checkNotNull(login);
+ Preconditions.checkNotNull(token);
+ PollenUser user = getPersistenceContext().getPollenUserDao().findByLogin(login);
+ if (user == null) {
+ throw new EntityNotFoundException(PollenUser.class, login);
+ }
+
+ String encodedToken = serviceContext.encodePassword(token);
+
+ SessionTokenJpaDao dao = getPersistenceContext().getSessionTokenDao();
+
+ SessionToken sessionToken = dao.findByToken(encodedToken);
+ if (sessionToken == null) {
+ throw new EntityNotFoundException(SessionToken.class, token);
+ }
+
+ dao.remove(sessionToken);
+ getPersistenceContext().commit();
+ }
+
+ public SessionToken getUserByAuth(String authParam) throws InvalidSessionTokenException {
+
+ SessionToken sessionToken = getPersistenceContext().getSessionTokenDao().findByToken(authParam);
+ if (sessionToken == null) {
+ throw new InvalidSessionTokenException();
+ }
+
+ return sessionToken;
+ }
+
+ protected void notifyPasswordChanged(PollenUser user, String newPassword) {
+ //TODO
+ }
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/CommentService.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/CommentService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/CommentService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/CommentService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,94 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service API
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import org.chorem.pollen.persistence.entity.Comment;
+import org.chorem.pollen.persistence.entity.Poll;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+
+import java.util.List;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class CommentService extends AbstractPollenService {
+
+ public List<Comment> getComments(String pollId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Poll poll = getPollService().getPoll(pollId);
+ return poll.getComment();
+ }
+
+ public Comment getComment(String commentId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(commentId);
+ Comment result = getPersistenceContext().getCommentDao().findById(commentId);
+ checkEntityExists(Comment.class, result, commentId);
+ return result;
+ }
+
+ public Comment addComment(String pollId, Comment comment) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ checkHasNoId(comment);
+ Poll poll = getPollService().getPoll(pollId);
+
+ poll.addComment(comment);
+ getPersistenceContext().getPollDao().merge(poll);
+ getPersistenceContext().commit();
+
+ Comment result = getComment(comment.getId());
+ return result;
+ }
+
+ public Comment editComment(Comment comment) throws EntityNotFoundException {
+
+ // check comment exists
+ getComment(comment.getId());
+
+ getPersistenceContext().getCommentDao().merge(comment);
+ getPersistenceContext().commit();
+
+ Comment result = getComment(comment.getId());
+ return result;
+ }
+
+ public void deleteComment(String pollId, String commentId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Preconditions.checkNotNull(commentId);
+ Poll poll = getPollService().getPoll(pollId);
+
+ Comment comment = getComment(commentId);
+ Preconditions.checkNotNull(comment);
+
+ poll.removeComment(comment);
+
+ getPersistenceContext().getPollDao().merge(poll);
+
+ getPersistenceContext().commit();
+ }
+
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/EmailService.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/EmailService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/EmailService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/EmailService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,39 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.chorem.pollen.persistence.entity.PollenUser;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class EmailService extends AbstractPollenService {
+
+ public void onUserCreated(PollenUser user) {
+ //TODO
+ }
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FavoriteListService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,547 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service API
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.chorem.pollen.persistence.entity.FavoriteList;
+import org.chorem.pollen.persistence.entity.FavoriteListMember;
+import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.services.PollenTechnicalException;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+import org.chorem.pollen.services.exception.FavoriteListImportException;
+import org.chorem.pollen.services.exception.FavoriteListMemberEmailAlreadyUsedException;
+import org.chorem.pollen.services.exception.FavoriteListMemberNameAlreadyUsedException;
+import org.chorem.pollen.services.exception.FavoriteListMemberNotOwnedByFavoriteListException;
+import org.chorem.pollen.services.exception.FavoriteListNameAlreadyUsedException;
+import org.chorem.pollen.services.exception.FavoriteListNotOwnedByUserException;
+import org.nuiton.util.StringUtil;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Set;
+
+import static org.nuiton.i18n.I18n.l_;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class FavoriteListService extends AbstractPollenService {
+
+ public List<FavoriteList> getFavoriteLists(String userId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(userId);
+ PollenUser user = getUserService().getUser(userId);
+
+ List<FavoriteList> result = user.getFavoriteList();
+ return result;
+ }
+
+ public FavoriteList getFavoriteList(String favoriteListId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(favoriteListId);
+ FavoriteList result = getPersistenceContext().getFavoriteListDao().findById(favoriteListId);
+ checkEntityExists(FavoriteList.class, result, favoriteListId);
+ return result;
+ }
+
+ public FavoriteList createFavoriteList(String userId,
+ FavoriteList favoriteList) throws EntityNotFoundException, FavoriteListNameAlreadyUsedException {
+ Preconditions.checkNotNull(userId);
+ Preconditions.checkNotNull(favoriteList);
+ checkHasNoId(favoriteList);
+
+ String favoriteListName = favoriteList.getName();
+
+ // can't accept favorite list without name
+ Preconditions.checkArgument(StringUtils.isNotEmpty(favoriteListName));
+
+ PollenUser user = getUserService().getUser(userId);
+
+ // check there is not already a favorite list with same name
+ boolean nameFound = false;
+ if (!user.isFavoriteListEmpty()) {
+ for (FavoriteList list : user.getFavoriteList()) {
+ if (favoriteListName.equals(list.getName())) {
+ nameFound = true;
+ break;
+ }
+ }
+ }
+
+ if (nameFound) {
+ throw new FavoriteListNameAlreadyUsedException(favoriteListName);
+ }
+
+ FavoriteList toSave = getPersistenceContext().getFavoriteListDao().newInstance();
+ copyFavoriteList(favoriteList, toSave);
+
+ user.addFavoriteList(toSave);
+ getPersistenceContext().getPollenUserDao().merge(user);
+
+ getPersistenceContext().commit();
+ return toSave;
+ }
+
+ public FavoriteList editFavoriteList(String userId,
+ FavoriteList favoriteList) throws EntityNotFoundException, FavoriteListNameAlreadyUsedException, FavoriteListNotOwnedByUserException {
+ Preconditions.checkNotNull(favoriteList);
+ checkHasId(favoriteList);
+
+ String favoriteListName = favoriteList.getName();
+
+ // can't accept favorite list without name
+ Preconditions.checkArgument(StringUtils.isNotEmpty(favoriteListName));
+
+ // get user
+ PollenUser user = getUserService().getUser(userId);
+
+ // get list
+ FavoriteList toSave = getFavoriteList(favoriteList.getId());
+
+ // check user own this list
+ boolean ownedByUser = user.containsFavoriteListById(favoriteList.getId());
+
+ if (!ownedByUser) {
+ throw new FavoriteListNotOwnedByUserException();
+ }
+
+ if (ObjectUtils.notEqual(favoriteListName, toSave.getName())) {
+
+ // check that this name is not existing in another list
+ boolean nameFound = false;
+ if (!user.isFavoriteListEmpty()) {
+ for (FavoriteList list : user.getFavoriteList()) {
+ if (toSave != list &&
+ favoriteListName.equals(list.getName())) {
+
+ // found another list with same name
+ nameFound = true;
+ break;
+ }
+ }
+ }
+ if (nameFound) {
+ throw new FavoriteListNameAlreadyUsedException(favoriteListName);
+ }
+ }
+
+ copyFavoriteList(favoriteList, toSave);
+ getPersistenceContext().getFavoriteListDao().merge(toSave);
+
+ getPersistenceContext().commit();
+ return toSave;
+ }
+
+ public void deleteFavoriteList(String userId, String favoriteListId) throws EntityNotFoundException, FavoriteListNotOwnedByUserException {
+ Preconditions.checkNotNull(userId);
+ Preconditions.checkNotNull(favoriteListId);
+
+ PollenUser user = getUserService().getUser(userId);
+
+ FavoriteList persisted = getFavoriteList(favoriteListId);
+
+ // check user own this list
+ boolean ownedByUser = user.containsFavoriteListById(favoriteListId);
+ if (!ownedByUser) {
+ throw new FavoriteListNotOwnedByUserException();
+ }
+
+ user.removeFavoriteList(persisted);
+ getPersistenceContext().getPollenUserDao().merge(user);
+
+ getPersistenceContext().commit();
+ }
+
+ public List<FavoriteListMember> getFavoriteListMembers(String favoriteListId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(favoriteListId);
+
+ FavoriteList favoriteList = getFavoriteList(favoriteListId);
+
+ return favoriteList.getFavoriteListMember();
+ }
+
+ public FavoriteListMember getFavoriteListMember(String memberId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(memberId);
+ FavoriteListMember result = getPersistenceContext().getFavoriteListMemberDao().findById(memberId);
+ checkEntityExists(FavoriteListMember.class, result, memberId);
+ return result;
+ }
+
+ public FavoriteListMember addFavoriteListMember(String favoriteListId,
+ FavoriteListMember member) throws EntityNotFoundException, FavoriteListMemberNameAlreadyUsedException, FavoriteListMemberEmailAlreadyUsedException {
+ Preconditions.checkNotNull(favoriteListId);
+ Preconditions.checkNotNull(member);
+ checkHasNoId(member);
+
+ // can't accept member without name
+ String memberName = member.getName();
+ Preconditions.checkArgument(StringUtils.isNotEmpty(memberName));
+
+ // can't accept member without email
+ String memberEmail = member.getEmail();
+ Preconditions.checkArgument(StringUtils.isNotEmpty(memberEmail));
+
+ // lowerCase email
+ memberEmail = StringUtils.lowerCase(memberEmail);
+
+ //TODO Validate email form
+
+ FavoriteList favoriteList = getFavoriteList(favoriteListId);
+
+ if (!favoriteList.isFavoriteListMemberEmpty()) {
+
+ for (FavoriteListMember listMember : favoriteList.getFavoriteListMember()) {
+
+ // check there is no other member with same name
+ if (memberName.equals(listMember.getName())) {
+ throw new FavoriteListMemberNameAlreadyUsedException(memberName);
+ }
+ // check there is no other member with same email
+ if (memberEmail.equals(listMember.getEmail())) {
+ throw new FavoriteListMemberEmailAlreadyUsedException(memberEmail);
+ }
+ }
+ }
+
+ FavoriteListMember newMember =
+ getPersistenceContext().getFavoriteListMemberDao().newInstance();
+ copyFavoriteListMember(member, newMember);
+ favoriteList.addFavoriteListMember(newMember);
+
+ getPersistenceContext().getFavoriteListDao().merge(favoriteList);
+
+ getPersistenceContext().commit();
+ return newMember;
+ }
+
+ public FavoriteListMember editFavoriteListMember(String favoriteListId, FavoriteListMember member) throws EntityNotFoundException, FavoriteListMemberNotOwnedByFavoriteListException, FavoriteListMemberNameAlreadyUsedException, FavoriteListMemberEmailAlreadyUsedException {
+ Preconditions.checkNotNull(member);
+ checkHasId(member);
+
+ // can't accept member without name
+ String memberName = member.getName();
+ Preconditions.checkArgument(StringUtils.isNotEmpty(memberName));
+
+ // can't accept member without email
+ String memberEmail = member.getEmail();
+ Preconditions.checkArgument(StringUtils.isNotEmpty(memberEmail));
+
+ // lowerCase email
+ memberEmail = StringUtils.lowerCase(memberEmail);
+
+ //TODO Validate email form
+
+ FavoriteList favoriteList = getFavoriteList(favoriteListId);
+
+ String memberId = member.getId();
+
+ FavoriteListMember toSave = getFavoriteListMember(memberId);
+
+ // check favorite list own this member
+ boolean ownedByUser = favoriteList.containsFavoriteListMemberById(memberId);
+ if (!ownedByUser) {
+ throw new FavoriteListMemberNotOwnedByFavoriteListException();
+ }
+
+
+ if (!memberName.equals(toSave.getName())) {
+
+ // name has changed must check name is available in the list
+ for (FavoriteListMember listMember : favoriteList.getFavoriteListMember()) {
+
+ // check there is no other member with same name
+ if (!memberId.equals(listMember.getId()) &&
+ memberName.equals(listMember.getName())) {
+ throw new FavoriteListMemberNameAlreadyUsedException(memberName);
+ }
+ }
+ }
+
+ if (!memberEmail.equals(toSave.getEmail())) {
+
+ // email has changed must check name is available in the list
+ for (FavoriteListMember listMember : favoriteList.getFavoriteListMember()) {
+
+ if (!memberId.equals(listMember.getId()) &&
+ memberEmail.equals(listMember.getEmail())) {
+ throw new FavoriteListMemberEmailAlreadyUsedException(memberEmail);
+ }
+ }
+ }
+ copyFavoriteListMember(member, toSave);
+
+ getPersistenceContext().getFavoriteListMemberDao().merge(toSave);
+
+ getPersistenceContext().commit();
+ return toSave;
+ }
+
+ public void removeFavoriteListMember(String favoriteListId, String memberId) throws EntityNotFoundException, FavoriteListMemberNotOwnedByFavoriteListException {
+ Preconditions.checkNotNull(favoriteListId);
+ Preconditions.checkNotNull(memberId);
+
+ FavoriteList favoriteList = getFavoriteList(favoriteListId);
+
+ FavoriteListMember member = getFavoriteListMember(memberId);
+
+ // check favorite list own this member
+ boolean ownedByUser = favoriteList.containsFavoriteListMemberById(memberId);
+ if (!ownedByUser) {
+ throw new FavoriteListMemberNotOwnedByFavoriteListException();
+ }
+
+ favoriteList.removeFavoriteListMember(member);
+
+ getPersistenceContext().getFavoriteListDao().merge(favoriteList);
+ getPersistenceContext().commit();
+ }
+
+ public int importFavoriteListMembersFromCsv(String userId, String favoriteListId,
+ File file) throws EntityNotFoundException, FavoriteListImportException, FavoriteListNotOwnedByUserException {
+ Preconditions.checkNotNull(userId);
+ Preconditions.checkNotNull(favoriteListId);
+ Preconditions.checkNotNull(file);
+
+ PollenUser user = getUserService().getUser(userId);
+
+ FavoriteList favoriteList = getFavoriteList(favoriteListId);
+
+ // check user own this list
+ boolean ownedByUser = user.containsFavoriteListById(favoriteListId);
+ if (!ownedByUser) {
+ throw new FavoriteListNotOwnedByUserException();
+ }
+
+ Locale locale = serviceContext.getLocale();
+
+ Set<String> usedName = Sets.newHashSet();
+ Set<String> usedEmail = Sets.newHashSet();
+
+ if (!favoriteList.isFavoriteListMemberEmpty()) {
+ for (FavoriteListMember member : favoriteList.getFavoriteListMember()) {
+ usedName.add(member.getName());
+ usedEmail.add(member.getEmail());
+ }
+ }
+
+ int result = 0;
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ String line;
+ int lineNumber = 0;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (StringUtils.isBlank(line) || line.startsWith("#")) {
+
+ // comment line
+ continue;
+ }
+ lineNumber++;
+ result++;
+
+ int spaceIndex = line.indexOf(' ');
+ String email;
+ String memberName;
+ if (spaceIndex == -1) {
+ // only email
+ email = line;
+ memberName = line;
+ } else {
+ // email + name
+ email = line.substring(0, spaceIndex);
+ memberName = line.substring(spaceIndex);
+ }
+ memberName = memberName.trim();
+
+ if (!usedName.add(memberName)) {
+ // name already exists
+ String error = l_(locale, "pollen.error.favoriteList.import.csv.already.used.name", lineNumber, memberName);
+ throw new FavoriteListImportException(error, null);
+ }
+
+ email = email.toLowerCase().trim();
+ if (!usedEmail.add(email)) {
+ // email already exists
+ String error = l_(locale, "pollen.error.favoriteList.import.csv.already.used.email", lineNumber, email);
+ throw new FavoriteListImportException(error, null);
+ }
+
+ if (!StringUtil.isEmail(email)) {
+
+ // email is not valid
+ String error = l_(locale, "pollen.error.favoriteList.import.csv.invalid.email", lineNumber, email);
+ throw new FavoriteListImportException(error, null);
+ }
+
+ FavoriteListMember member = getPersistenceContext().getFavoriteListMemberDao().newInstance();
+ member.setName(memberName);
+ member.setEmail(email);
+
+ favoriteList.addFavoriteListMember(member);
+ }
+
+ reader.close();
+
+ } catch (FileNotFoundException e) {
+ // should never happens ?
+ throw new PollenTechnicalException(e);
+ } catch (IOException e) {
+ // should never happens ?
+ throw new PollenTechnicalException(e);
+ } finally {
+ IOUtils.closeQuietly(reader);
+ }
+
+ getPersistenceContext().getFavoriteListDao().merge(favoriteList);
+
+ getPersistenceContext().commit();
+
+ return result;
+ }
+
+ public int importFavoriteListMembersFromLdap(String userId,
+ String favoriteListId,
+ String ldap) throws EntityNotFoundException, FavoriteListImportException, FavoriteListNotOwnedByUserException {
+ Preconditions.checkNotNull(favoriteListId);
+ Preconditions.checkNotNull(ldap);
+
+ PollenUser user = getUserService().getUser(userId);
+
+ FavoriteList favoriteList = getFavoriteList(favoriteListId);
+
+ // check user own this list
+ boolean ownedByUser = user.containsFavoriteListById(favoriteListId);
+ if (!ownedByUser) {
+ throw new FavoriteListNotOwnedByUserException();
+ }
+
+ Locale locale = serviceContext.getLocale();
+
+ Set<String> usedName = Sets.newHashSet();
+ Set<String> usedEmail = Sets.newHashSet();
+
+ if (!favoriteList.isFavoriteListMemberEmpty()) {
+ for (FavoriteListMember member : favoriteList.getFavoriteListMember()) {
+ usedName.add(member.getName());
+ usedEmail.add(member.getEmail());
+ }
+ }
+
+ int result = 0;
+
+ try {
+
+ // Initialisation du contexte
+ Properties env = new Properties();
+
+ DirContext ictx = new InitialDirContext(env);
+
+ // Recherche en profondeur
+ SearchControls control = new SearchControls();
+ control.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+ // Création des comptes avec les résultats de la recherche
+ NamingEnumeration<SearchResult> e = ictx.search(ldap, null, control);
+ while (e.hasMore()) {
+ SearchResult r = e.next();
+
+ Attribute attrName = r.getAttributes().get("cn");
+ Attribute attrEmail = r.getAttributes().get("mail");
+
+ if (attrName != null) {
+
+ result++;
+
+ String memberName = attrName.get().toString().trim();
+
+ if (!usedName.add(memberName)) {
+ // name already exists
+ String error = l_(locale, "pollen.error.favoriteList.import.ldap.already.used.name", memberName);
+ throw new FavoriteListImportException(error, null);
+ }
+
+ String email = attrEmail.get().toString().toLowerCase().trim();
+
+ if (!usedEmail.add(email)) {
+ // email already exists
+ String error = l_(locale, "pollen.error.favoriteList.import.ldap.already.used.email", email);
+ throw new FavoriteListImportException(error, null);
+ }
+
+ if (!StringUtil.isEmail(email)) {
+
+ // email is not valid
+ String error = l_(locale, "pollen.error.favoriteList.import.ldap.invalid.email", email);
+ throw new FavoriteListImportException(error, null);
+ }
+
+ FavoriteListMember member = getPersistenceContext().getFavoriteListMemberDao().newInstance();
+ member.setName(memberName);
+ member.setEmail(email);
+
+ favoriteList.addFavoriteListMember(member);
+ }
+ }
+ } catch (NamingException ex) {
+ throw new FavoriteListImportException("LDAP", ex);
+ }
+
+ getPersistenceContext().getFavoriteListDao().merge(favoriteList);
+
+ getPersistenceContext().commit();
+ return result;
+ }
+
+ protected void copyFavoriteList(FavoriteList source,
+ FavoriteList destination) {
+
+ destination.setName(source.getName());
+ }
+
+ protected void copyFavoriteListMember(FavoriteListMember source,
+ FavoriteListMember destination) {
+
+ destination.setName(source.getName());
+ destination.setEmail(StringUtils.lowerCase(source.getEmail()));
+ }
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/FixturesService.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FixturesService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/FixturesService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/FixturesService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,101 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.chorem.pollen.persistence.PollenPersistenceContext;
+import org.chorem.pollen.persistence.dao.PollenUserJpaDao;
+import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.services.PollenFixtures;
+
+import java.util.Collection;
+import java.util.Map;
+
+public class FixturesService extends AbstractPollenService {
+
+ private static final Log log = LogFactory.getLog(FixturesService.class);
+
+ protected Map<String, PollenFixtures> fixtureSets = Maps.newHashMap();
+
+ public PollenFixtures cleanDatabaseAndLoadFixtures(String fixturesSetName) {
+
+ return loadFixtures(fixturesSetName, true);
+
+ }
+
+ public PollenFixtures loadFixtures(String fixturesSetName) {
+
+ return loadFixtures(fixturesSetName, false);
+
+ }
+
+ protected PollenFixtures loadFixtures(String fixturesSetName, boolean cleanDatabase) {
+
+ boolean devMode = serviceContext.getPollenServiceConfig().isDevMode();
+
+ Preconditions.checkState(devMode);
+
+ PollenFixtures fixtures = fixtureSets.get(fixturesSetName);
+
+ if (fixtures == null) {
+
+ fixtures = new PollenFixtures(fixturesSetName);
+
+ fixtureSets.put(fixturesSetName, fixtures);
+
+ if (log.isInfoEnabled()) {
+ log.info("will restore database with fixture set");
+ }
+
+ PollenPersistenceContext persistenceContext = serviceContext.getPersistenceContext();
+
+ if (cleanDatabase) {
+
+ persistenceContext.clearDatabase();
+
+ }
+
+ PollenUserJpaDao userDao = persistenceContext.getPollenUserDao();
+
+ Collection<PollenUser> users = fixtures.fixture("users");
+
+ for (PollenUser user : users) {
+
+ user.setPassword(serviceContext.encodePassword(user.getPassword()));
+ userDao.persist(user);
+ }
+
+ persistenceContext.commit();
+
+
+ }
+
+ return fixtures;
+
+ }
+
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java (from rev 3820, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,205 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import org.chorem.pollen.persistence.entity.Choice;
+import org.chorem.pollen.persistence.entity.Poll;
+import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class PollService extends AbstractPollenService {
+
+ public Set<Poll> getCreatedPolls(String userId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(userId);
+
+ getUserService().getUser(userId);
+
+ return getPersistenceContext().getPollDao().findAllCreated(userId);
+ }
+
+ public Set<Poll> getInvitedPolls(String userId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(userId);
+
+ getUserService().getUser(userId);
+
+ return getPersistenceContext().getPollDao().findAllInvited(userId);
+ }
+
+ public Set<Poll> getParticipatedPolls(String userId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(userId);
+
+ getUserService().getUser(userId);
+
+ return getPersistenceContext().getPollDao().findAllParticipated(userId);
+ }
+
+ public Poll getPoll(String pollId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Poll result = getPersistenceContext().getPollDao().findById(pollId);
+ checkEntityExists(Poll.class, result, pollId);
+ return result;
+ }
+
+ public Poll createPoll(String userId, Poll poll) throws EntityNotFoundException {
+ Preconditions.checkNotNull(userId);
+ Preconditions.checkNotNull(poll);
+ checkHasNoId(poll);
+
+ if (userId != null) {
+
+ // get user
+ PollenUser user = getUserService().getUser(userId);
+
+ // link it to creator
+
+ }
+
+ getPersistenceContext().getPollDao().persist(poll);
+
+ getPersistenceContext().commit();
+ return poll;
+ }
+
+ public Poll editPoll(Poll poll) throws EntityNotFoundException {
+ Preconditions.checkNotNull(poll);
+ checkHasId(poll);
+
+ getPoll(poll.getId());
+
+ getPersistenceContext().getPollDao().merge(poll);
+ getPersistenceContext().commit();
+
+ Poll result = getPoll(poll.getId());
+ return result;
+ }
+
+ public void deletePoll(String pollId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+
+ Poll poll = getPoll(pollId);
+
+ getPersistenceContext().getPollDao().remove(poll);
+ getPersistenceContext().commit();
+ }
+
+ public Poll clonePoll(String pollId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+
+ Poll poll = getPoll(pollId);
+ //TODO
+ getPersistenceContext().commit();
+ return null;
+ }
+
+ public File closePoll(String pollId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+
+ Poll poll = getPoll(pollId);
+ //TODO
+ getPersistenceContext().commit();
+ return null;
+ }
+
+ public File exportPoll(String pollId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Poll poll = getPoll(pollId);
+ //TODO
+ return null;
+ }
+
+ public List<Choice> getChoices(String pollId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+
+ Poll poll = getPoll(pollId);
+
+ return poll.getChoice();
+ }
+
+ public Choice getChoice(String choiceId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(choiceId);
+
+ Choice result = getPersistenceContext().getChoiceDao().findById(choiceId);
+ checkEntityExists(Choice.class, result, choiceId);
+ return result;
+ }
+
+ public Choice addChoice(String pollId, Choice choice) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Preconditions.checkNotNull(choice);
+ checkHasNoId(choice);
+
+ Poll poll = getPoll(pollId);
+
+ poll.addChoice(choice);
+
+ getPersistenceContext().getPollDao().merge(poll);
+
+ getPersistenceContext().commit();
+ Choice result = getChoice(choice.getId());
+ return result;
+ }
+
+ public Choice editChoice(Choice choice) throws EntityNotFoundException {
+ Preconditions.checkNotNull(choice);
+ checkHasId(choice);
+
+ getChoice(choice.getId());
+
+ getPersistenceContext().getChoiceDao().merge(choice);
+ getPersistenceContext().commit();
+
+ Choice result = getChoice(choice.getId());
+ return result;
+ }
+
+ public void deleteChoice(String pollId, String choiceId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Preconditions.checkNotNull(choiceId);
+
+ Poll poll = getPoll(pollId);
+ Choice choice = getChoice(choiceId);
+
+ poll.removeChoice(choice);
+
+ getPersistenceContext().getPollDao().merge(poll);
+
+ getPersistenceContext().commit();
+ }
+
+ public Set<Poll> getPolls(String userId) throws EntityNotFoundException {
+ return Sets.newHashSet(getPersistenceContext().getPollDao().findAll());
+ }
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/UserService.java (from rev 3821, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/UserService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/UserService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,252 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.chorem.pollen.persistence.dao.PollenUserJpaDao;
+import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.services.PollenServiceSupport;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+import org.chorem.pollen.services.exception.UserEmailAlreadyUsedException;
+import org.chorem.pollen.services.exception.UserInvalidEmailActiviationTokenException;
+import org.chorem.pollen.services.exception.UserInvalidPasswordException;
+import org.chorem.pollen.services.exception.UserLoginAlreadyUsedException;
+
+import java.util.List;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class UserService extends AbstractPollenService implements PollenServiceSupport {
+
+ public List<PollenUser> getUsers() {
+ return getPollenUserDao().findAll();
+ }
+
+ public PollenUser getUser(String userId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(userId);
+
+ PollenUser result = getPollenUserDao().findById(userId);
+ checkEntityExists(PollenUser.class, result, userId);
+ return result;
+ }
+
+ public PollenUser createUser(PollenUser user, boolean generatePassword) throws UserLoginAlreadyUsedException, UserEmailAlreadyUsedException {
+ Preconditions.checkNotNull(user);
+ checkHasNoId(user);
+ Preconditions.checkNotNull(user.getLogin());
+ Preconditions.checkNotNull(user.getEmail());
+
+ PollenUserJpaDao dao = getPollenUserDao();
+
+ // check login is available
+ boolean loginExists = dao.loginExists(user.getLogin());
+ if (loginExists) {
+ throw new UserLoginAlreadyUsedException(user.getLogin());
+ }
+
+ // check email is available
+ boolean emailExists = dao.emailExists(user.getEmail());
+ if (emailExists) {
+ throw new UserEmailAlreadyUsedException(user.getEmail());
+ }
+
+ PollenUser toCreate = dao.newInstance();
+
+ // add a emailValidationToken
+ String emailValidationToken = generateToken();
+
+ String password;
+ if (generatePassword) {
+ // let's generate the new password
+ password = serviceContext.generatePassword();
+ } else {
+ password = user.getPassword();
+ }
+
+ // encode the password
+ String encodedPassword = serviceContext.encodePassword(password);
+
+ toCreate.setLogin(user.getLogin());
+ toCreate.setEmailActivationToken(emailValidationToken);
+ toCreate.setPassword(encodedPassword);
+
+ copyPollenUser(user, toCreate, true);
+
+ dao.persist(toCreate);
+ getPersistenceContext().commit();
+
+ notifyUserCreated(toCreate);
+
+ return toCreate;
+ }
+
+ public PollenUser editUser(PollenUser user) throws UserInvalidPasswordException, UserEmailAlreadyUsedException, EntityNotFoundException {
+ Preconditions.checkNotNull(user);
+ checkHasId(user);
+
+ PollenUser persisted = getUser(user.getId());
+
+ PollenUserJpaDao dao = getPollenUserDao();
+
+ // check current password
+ String encodedPassword = serviceContext.encodePassword(user.getPassword());
+ if (!encodedPassword.equals(persisted.getPassword())) {
+ throw new UserInvalidPasswordException();
+ }
+
+ boolean emailChanged = ObjectUtils.notEqual(persisted.getEmail(),
+ user.getEmail());
+
+ if (emailChanged) {
+
+ // check this email is not used by another user
+ boolean emailUsed = dao.emailExists(user.getEmail());
+ if (emailUsed) {
+ throw new UserEmailAlreadyUsedException(user.getEmail());
+ }
+
+ // add a new emailValidationtoken
+ String emailValidationToken = generateToken();
+ persisted.setEmailActivationToken(emailValidationToken);
+ }
+
+ copyPollenUser(user, persisted, true);
+
+ persisted = dao.merge(persisted);
+ getPersistenceContext().commit();
+
+ if (emailChanged) {
+
+ notifyEmailChanged(persisted);
+ }
+ return persisted;
+ }
+
+ public void changePassword(String userId,
+ String oldPassword,
+ String newPassword) throws UserInvalidPasswordException, EntityNotFoundException {
+ Preconditions.checkNotNull(userId);
+ Preconditions.checkNotNull(oldPassword);
+ Preconditions.checkNotNull(newPassword);
+
+ PollenUser user = getUser(userId);
+
+ // check current password
+ String encodedPassword = serviceContext.encodePassword(user.getPassword());
+ if (!encodedPassword.equals(user.getPassword())) {
+ throw new UserInvalidPasswordException();
+ }
+
+ // encode new password and store it in user account
+ String newEncodedPassword = serviceContext.encodePassword(newPassword);
+ user.setPassword(newEncodedPassword);
+
+ user = getPollenUserDao().merge(user);
+ getPersistenceContext().commit();
+
+ notifyPasswordChanged(user);
+ }
+
+ public void validateUserEmail(String userId,
+ String token) throws EntityNotFoundException, UserInvalidEmailActiviationTokenException {
+
+ Preconditions.checkNotNull(userId);
+ Preconditions.checkNotNull(token);
+
+ PollenUser user = getUser(userId);
+
+ Preconditions.checkNotNull(user);
+
+ boolean valid = ObjectUtils.equals(
+ user.getEmailActivationToken(), token);
+
+ if (!valid) {
+ throw new UserInvalidEmailActiviationTokenException();
+ }
+
+ // reset token in database
+ user.setEmailActivationToken(null);
+
+ getPollenUserDao().merge(user);
+ getPersistenceContext().commit();
+ }
+
+ public void createDefaultUsers() throws UserEmailAlreadyUsedException, UserLoginAlreadyUsedException {
+
+ PollenUser user = getPollenUserDao().newInstance();
+
+ user.setAdministrator(true);
+ String login = "admin";
+ user.setLogin(login);
+ user.setEmail("admin(a)pollen.org");
+ user.setPassword("admin");
+ createUser(user, false);
+ }
+
+ protected void notifyUserCreated(PollenUser user) {
+
+ //TODO
+ }
+
+ protected void notifyEmailChanged(PollenUser user) {
+
+ //TODO
+ }
+
+ protected void notifyPasswordChanged(PollenUser user) {
+
+ //TODO
+ }
+
+ protected PollenUserJpaDao getPollenUserDao() {
+ return getPersistenceContext().getPollenUserDao();
+ }
+
+ /**
+ * Copy {@code source} user account to {@code destination} one.
+ * The email is lower cased in the {@code destination} user account.
+ *
+ * @param source user account to copy
+ * @param destination which receive the copy
+ */
+ protected void copyPollenUser(PollenUser source,
+ PollenUser destination,
+ boolean copyEmail) {
+
+ destination.setAdministrator(source.isAdministrator());
+ destination.setName(source.getName());
+ destination.setLanguage(source.getLanguage());
+
+ if (copyEmail) {
+ // Don't keep case for email
+ destination.setEmail(StringUtils.lowerCase(source.getEmail()));
+ }
+ }
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteCountingService.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteCountingService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteCountingService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteCountingService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,46 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import org.chorem.pollen.persistence.entity.Poll;
+import org.chorem.pollen.services.PollResult;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class VoteCountingService extends AbstractPollenService {
+
+ //GET /poll/{pollId}/results
+ public PollResult getResult(String pollId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Poll poll = getPollService().getPoll(pollId);
+ //TODO
+ return null;
+ }
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,100 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import org.chorem.pollen.persistence.entity.Poll;
+import org.chorem.pollen.persistence.entity.Vote;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+
+import java.util.List;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class VoteService extends AbstractPollenService {
+
+ public List<Vote> getVotes(String pollId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+
+ Poll poll = getPollService().getPoll(pollId);
+ List<Vote> result = poll.getVote();
+ return result;
+ }
+
+ public Vote getVote(String voteId) throws EntityNotFoundException{
+ Preconditions.checkNotNull(voteId);
+
+ Vote result = getPersistenceContext().getVoteDao().findById(voteId);
+ checkEntityExists(Vote.class, result, voteId);
+ return result;
+ }
+
+ public Vote addVote(String pollId, Vote vote)throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Preconditions.checkNotNull(vote);
+ checkHasNoId(vote);
+
+ Poll poll = getPollService().getPoll(pollId);
+
+ poll.addVote(vote);
+ getPersistenceContext().getPollDao().merge(poll);
+
+ getPersistenceContext().commit();
+ Vote result = getVote(vote.getId());
+ return result;
+ }
+
+ public Vote editVote(Vote vote)throws EntityNotFoundException {
+ Preconditions.checkNotNull(vote);
+ checkHasId(vote);
+
+ getVote(vote.getId());
+
+ getPersistenceContext().getVoteDao().merge(vote);
+ getPersistenceContext().commit();
+
+ Vote result = getVote(vote.getId());
+ return result;
+ }
+
+ public void deleteVote(String pollId, String voteId)throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Preconditions.checkNotNull(voteId);
+
+ Poll poll = getPollService().getPoll(pollId);
+
+ Vote vote = getVote(voteId);
+
+ poll.removeVote(vote);
+
+ getPersistenceContext().getPollDao().merge(poll);
+
+ getPersistenceContext().commit();
+ }
+
+}
Copied: branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java (from rev 3819, branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoterListService.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,200 @@
+package org.chorem.pollen.services.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import org.chorem.pollen.persistence.dao.VoterListJpaDao;
+import org.chorem.pollen.persistence.dao.VoterListMemberJpaDao;
+import org.chorem.pollen.persistence.entity.FavoriteList;
+import org.chorem.pollen.persistence.entity.FavoriteListMember;
+import org.chorem.pollen.persistence.entity.Poll;
+import org.chorem.pollen.persistence.entity.VoterList;
+import org.chorem.pollen.persistence.entity.VoterListMember;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class VoterListService extends AbstractPollenService {
+
+ public VoterList importFavoriteList(String pollId,
+ String favoriteListId) throws EntityNotFoundException {
+ Preconditions.checkNotNull(pollId);
+ Preconditions.checkNotNull(favoriteListId);
+
+ Poll poll = getPollService().getPoll(pollId);
+
+ FavoriteList favoriteList = getFavoriteListService().getFavoriteList(favoriteListId);
+
+ VoterListJpaDao dao = getPersistenceContext().getVoterListDao();
+ VoterList result = dao.newInstance();
+
+ result.setName(favoriteList.getName());
+ result.setWeight(1d);
+
+ VoterListMemberJpaDao voterListMemberDao =
+ getPersistenceContext().getVoterListMemberDao();
+
+ for (FavoriteListMember favoriteListMember : favoriteList.getFavoriteListMember()) {
+
+ VoterListMember voterListMember = voterListMemberDao.newInstance();
+ voterListMember.setWeight(1d);
+ voterListMember.setEmail(favoriteListMember.getEmail());
+ result.addVoterListMember(voterListMember);
+ }
+
+ poll.addVoterList(result);
+
+ getPersistenceContext().getPollDao().merge(poll);
+
+ getPersistenceContext().commit();
+ return result;
+ }
+
+ public List<VoterList> getVoterLists(String pollId) throws EntityNotFoundException{
+ Preconditions.checkNotNull(pollId);
+
+ Poll poll = getPollService().getPoll(pollId);
+
+ List<VoterList> result = poll.getVoterList();
+ return result;
+ }
+
+ public VoterList getVoterList(String voterListId) throws EntityNotFoundException{
+ Preconditions.checkNotNull(voterListId);
+
+ VoterList result = getPersistenceContext().getVoterListDao().findById(voterListId);
+ checkEntityExists(VoterList.class, result, voterListId);
+
+ return result;
+ }
+
+ public VoterList addVoterList(String pollId, VoterList voterList) throws EntityNotFoundException{
+ Preconditions.checkNotNull(pollId);
+ Preconditions.checkNotNull(voterList);
+ checkHasNoId(voterList);
+
+ Poll poll = getPollService().getPoll(pollId);
+
+ poll.addVoterList(voterList);
+
+ getPersistenceContext().getPollDao().merge(poll);
+ getPersistenceContext().commit();
+ VoterList result = getVoterList(voterList.getId());
+ return result;
+ }
+
+ public VoterList editVoterList(VoterList voterList) throws EntityNotFoundException{
+ Preconditions.checkNotNull(voterList);
+ checkHasId(voterList);
+
+ getVoterList(voterList.getId());
+
+ getPersistenceContext().getVoterListDao().merge(voterList);
+ getPersistenceContext().commit();
+ VoterList result = getVoterList(voterList.getId());
+ return result;
+ }
+
+ public void deleteVoterList(String pollId, String voterListId) throws EntityNotFoundException{
+ Preconditions.checkNotNull(pollId);
+ Preconditions.checkNotNull(voterListId);
+
+ Poll poll = getPollService().getPoll(pollId);
+
+ VoterList voterList = getVoterList(voterListId);
+
+ poll.removeVoterList(voterList);
+
+ getPersistenceContext().getPollDao().merge(poll);
+
+ getPersistenceContext().commit();
+ }
+
+ public Set<VoterListMember> getMembers(String voterListId) throws EntityNotFoundException{
+ Preconditions.checkNotNull(voterListId);
+
+ VoterList voterList = getVoterList(voterListId);
+
+ Set<VoterListMember> result = voterList.getVoterListMember();
+ return result;
+ }
+
+ public VoterListMember getMember(String memberId) throws EntityNotFoundException{
+ Preconditions.checkNotNull(memberId);
+
+ VoterListMember result = getPersistenceContext().getVoterListMemberDao().findById(memberId);
+ checkEntityExists(VoterListMember.class, result, memberId);
+ return result;
+ }
+
+ public VoterListMember addMember(String voterListId, VoterListMember member)throws EntityNotFoundException {
+ Preconditions.checkNotNull(voterListId);
+ Preconditions.checkNotNull(member);
+ checkHasNoId(member);
+
+ VoterList voterList = getVoterList(voterListId);
+
+ voterList.addVoterListMember(member);
+ getPersistenceContext().getVoterListDao().merge(voterList);
+
+ getPersistenceContext().commit();
+ VoterListMember result = getMember(member.getId());
+ return result;
+ }
+
+ public VoterListMember editMember(VoterListMember member) throws EntityNotFoundException{
+ Preconditions.checkNotNull(member);
+ checkHasId(member);
+
+ getMember(member.getId());
+
+ getPersistenceContext().getVoterListMemberDao().merge(member);
+
+ getPersistenceContext().commit();
+ VoterListMember result = getMember(member.getId());
+ return result;
+ }
+
+ public void deleteMember(String voterListId, String memberId) throws EntityNotFoundException{
+ Preconditions.checkNotNull(voterListId);
+ Preconditions.checkNotNull(memberId);
+
+ VoterList voterList = getVoterList(voterListId);
+
+ VoterListMember member = getMember(memberId);
+ voterList.removeVoterListMember(member);
+
+ getPersistenceContext().getVoterListDao().merge(voterList);
+
+ getPersistenceContext().commit();
+ }
+
+}
Deleted: branches/pollen-2.0/pollen-services/src/main/resources/fixtures.yaml
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/main/resources/fixtures.yaml 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,31 +0,0 @@
-tony:
- &tony !user
- id: pollen_user_tony
- login: tony
- password: fake
- name: T
- email: tony(a)pollen.fake
- administrator: false
-
-jean:
- &jean !user
- id: pollen_user_jean
- login: jean
- password: fake
- name: J
- email: jean(a)pollen.fake
- administrator: true
-
-julien:
- &julien !user
- id: pollen_user_julien
- login: julien
- password: fake
- name: J
- email: julien(a)pollen.fake
- administrator: true
-
-users:
- - *tony
- - *jean
- - *julien
\ No newline at end of file
Copied: branches/pollen-2.0/pollen-services/src/main/resources/fixtures.yaml (from rev 3821, branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml)
===================================================================
--- branches/pollen-2.0/pollen-services/src/main/resources/fixtures.yaml (rev 0)
+++ branches/pollen-2.0/pollen-services/src/main/resources/fixtures.yaml 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,28 @@
+tony:
+ &tony !user
+ login: tony
+ password: fake
+ name: T
+ email: tony(a)pollen.fake
+ administrator: false
+
+jean:
+ &jean !user
+ login: jean
+ password: fake
+ name: J
+ email: jean(a)pollen.fake
+ administrator: true
+
+julien:
+ &julien !user
+ login: julien
+ password: fake
+ name: J
+ email: julien(a)pollen.fake
+ administrator: true
+
+users:
+ - *tony
+ - *jean
+ - *julien
\ No newline at end of file
Deleted: branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,114 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.chorem.pollen.persistence.JpaEntityIdFactoryIfNotEmpty;
-import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
-import org.chorem.pollen.service.config.PollenServiceConfig;
-import org.junit.Rule;
-import org.nuiton.jpa.junit.JpaEntityManagerRule;
-
-import javax.persistence.EntityManager;
-import java.util.Map;
-
-public abstract class AbstractPollenServiceTest {
-
- protected static final double DELTA = 0.0001;
-
- protected static PollenServiceConfig config;
-
- protected JpaEntityManagerRule jpaEntityManagerRule;
-
- protected FakePollenServiceContext serviceContext;
-
- protected PollenFixtures fixtures;
-
- protected static PollenServiceConfig getPollenServiceConfig() {
-
- if (config == null) {
-
- config = new PollenServiceConfig();
- }
-
- return config;
-
- }
-
- protected FakePollenServiceContext getServiceContext() {
-
- if (serviceContext == null) {
-
- synchronized (this) {
- serviceContext = new FakePollenServiceContext();
-
- serviceContext.setPollenServiceConfig(getPollenServiceConfig());
-
- EntityManager entityManager = getJpaEntityManagerRule().getEntityManager();
-
- JpaEntityIdFactoryIfNotEmpty idGenerator = new JpaEntityIdFactoryIfNotEmpty();
- JpaPollenPersistenceContext persistenceContext = new JpaPollenPersistenceContext(idGenerator, entityManager);
-
- serviceContext.setPersistenceContext(persistenceContext);
- }
- }
-
- return serviceContext;
-
- }
-
- protected void loadFixtures(String fixturesSetName) {
-
- FixturesService fixturesService = getServiceContext().newService(FixturesService.class);
-
- fixtures = fixturesService.loadFixtures(fixturesSetName);
-
- }
-
- protected <E> E fixture(String id) {
-
- return fixtures.fixture(id);
-
- }
-
- protected <E extends PollenServiceSupport> E newService(Class<E> serviceClass) {
-
- return getServiceContext().newService(serviceClass);
-
- }
-
- @Rule
- public JpaEntityManagerRule getJpaEntityManagerRule() {
-
- if (jpaEntityManagerRule == null) {
-
- Map<String, String> jpaParameters = getPollenServiceConfig().getJpaParameters();
-
- jpaEntityManagerRule = new JpaEntityManagerRule("pollenPersistenceUnit", jpaParameters);
- }
-
- return jpaEntityManagerRule;
-
- }
-
-}
Copied: branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java (from rev 3821, branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,117 @@
+package org.chorem.pollen.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
+import org.chorem.pollen.services.PollenFixtures;
+import org.chorem.pollen.services.config.PollenServiceConfig;
+import org.chorem.pollen.services.service.FixturesService;
+import org.chorem.pollen.services.PollenServiceSupport;
+import org.junit.Rule;
+import org.nuiton.jpa.junit.JpaEntityManagerRule;
+
+import javax.persistence.EntityManager;
+import java.util.Map;
+
+public abstract class AbstractPollenServiceTest {
+
+ protected static final double DELTA = 0.0001;
+
+ protected static PollenServiceConfig config;
+
+ protected JpaEntityManagerRule jpaEntityManagerRule;
+
+ protected FakePollenServiceContext serviceContext;
+
+ protected PollenFixtures fixtures;
+
+ protected static PollenServiceConfig getPollenServiceConfig() {
+
+ if (config == null) {
+
+ config = new PollenServiceConfig();
+ }
+
+ return config;
+
+ }
+
+ protected FakePollenServiceContext getServiceContext() {
+
+ if (serviceContext == null) {
+
+ synchronized (this) {
+ serviceContext = new FakePollenServiceContext();
+
+ serviceContext.setPollenServiceConfig(getPollenServiceConfig());
+
+ EntityManager entityManager = getJpaEntityManagerRule().getEntityManager();
+
+// JpaEntityIdFactoryIfNotEmpty idGenerator = new JpaEntityIdFactoryIfNotEmpty();
+// JpaPollenPersistenceContext persistenceContext = new JpaPollenPersistenceContext(idGenerator, entityManager);
+ JpaPollenPersistenceContext persistenceContext = new JpaPollenPersistenceContext(entityManager);
+
+ serviceContext.setPersistenceContext(persistenceContext);
+ }
+ }
+
+ return serviceContext;
+
+ }
+
+ protected void loadFixtures(String fixturesSetName) {
+
+ FixturesService fixturesService = getServiceContext().newService(FixturesService.class);
+
+ fixtures = fixturesService.loadFixtures(fixturesSetName);
+
+ }
+
+ protected <E> E fixture(String id) {
+
+ return fixtures.fixture(id);
+
+ }
+
+ protected <E extends PollenServiceSupport> E newService(Class<E> serviceClass) {
+
+ return getServiceContext().newService(serviceClass);
+
+ }
+
+ @Rule
+ public JpaEntityManagerRule getJpaEntityManagerRule() {
+
+ if (jpaEntityManagerRule == null) {
+
+ Map<String, String> jpaParameters = getPollenServiceConfig().getJpaParameters();
+
+ jpaEntityManagerRule = new JpaEntityManagerRule("pollenPersistenceUnit", jpaParameters);
+ }
+
+ return jpaEntityManagerRule;
+
+ }
+
+}
Modified: branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/FakePollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/FakePollenServiceContext.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/FakePollenServiceContext.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -26,6 +26,7 @@
import com.google.common.base.Preconditions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.chorem.pollen.services.DefaultPollenServiceContext;
import java.util.Date;
Deleted: branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/UserServiceTest.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/UserServiceTest.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -1,201 +0,0 @@
-package org.chorem.pollen.service;
-
-/*
- * #%L
- * Pollen :: Service
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.apache.commons.collections.CollectionUtils;
-import org.chorem.pollen.persistence.entity.PollenUser;
-import org.chorem.pollen.service.exception.EntityNotFoundException;
-import org.chorem.pollen.service.exception.UserEmailAlreadyUsedException;
-import org.chorem.pollen.service.exception.UserInvalidEmailActiviationTokenException;
-import org.chorem.pollen.service.exception.UserInvalidPasswordException;
-import org.chorem.pollen.service.exception.UserLoginAlreadyUsedException;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.text.ParseException;
-import java.util.Date;
-import java.util.List;
-
-/**
- * TODO
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class UserServiceTest extends AbstractPollenServiceTest {
-
- protected UserService service;
-
- protected PollenUser user;
-
- @Before
- public void setUp() throws ParseException {
-
- loadFixtures("fixtures");
-
- service = serviceContext.getUserService();
-
- serviceContext.setDate(new Date(1363948427576l));
-
- user = fixture("tony");
- }
-
- @Test
- public void testGetPollenUsers() {
-
- List<PollenUser> users = service.getUsers();
-
- Assert.assertNotNull(users);
- Assert.assertTrue(CollectionUtils.isNotEmpty(users));
- }
-
- @Test
- public void testGetPollenUser() throws EntityNotFoundException {
-
- try {
- service.getUser("pollen_user_tony_" + System.nanoTime());
-
- } catch (EntityNotFoundException e) {
- Assert.assertTrue(true);
- }
-
- PollenUser user = service.getUser("pollen_user_tony");
-
- Assert.assertNotNull(user);
- Assert.assertEquals(this.user, user);
- }
-
- @Test
- public void testCreatePollenUser() throws Exception {
-
- try {
- service.createUser(user, false);
- Assert.fail();
- } catch (IllegalStateException e) {
- // Should having id
- Assert.assertTrue(true);
- }
-
- PollenUser newUser = new PollenUser();
- newUser.setLogin("pollen");
- newUser.setEmail("pollen(a)pollen.org");
-
- PollenUser savedUser = service.createUser(newUser, true);
- Assert.assertNotNull(savedUser);
- Assert.assertNotNull(savedUser.getId());
-
- PollenUser newUser2 = new PollenUser();
- newUser2.setLogin("pollen");
- newUser2.setEmail("pollen(a)pollen.org");
-
- try {
- service.createUser(newUser2, true);
- Assert.fail();
- } catch (UserLoginAlreadyUsedException e) {
- Assert.assertTrue(true);
- }
-
- newUser2.setLogin("pollen2");
- try {
- service.createUser(newUser2, true);
- Assert.fail();
- } catch (UserEmailAlreadyUsedException e) {
- Assert.assertTrue(true);
- }
-
- newUser2.setEmail("pollen2(a)pollen.org");
- PollenUser savedUser2 = service.createUser(newUser2, true);
- Assert.assertNotNull(savedUser2);
- Assert.assertNotNull(savedUser2.getId());
- }
-
- @Test
- public void testEditUser() throws EntityNotFoundException, UserInvalidPasswordException, UserEmailAlreadyUsedException {
-
- PollenUser user = service.getUser("pollen_user_tony");
-
- Assert.assertNotNull(user);
- Assert.assertNull(user.getEmailActivationToken());
-
- serviceContext.getPersistenceContext().detach(user);
-
- String originalLogin = user.getLogin();
-
- user.setLogin("yetanotherlogin");
- String email = "tony(a)pollen.org";
- user.setEmail(email);
-
- try {
- service.editUser(user);
- Assert.fail();
- } catch (UserInvalidPasswordException e) {
- Assert.assertTrue(true);
- }
-
- user.setPassword("fake");
- PollenUser savedUser = service.editUser(user);
- Assert.assertNotNull(savedUser);
- Assert.assertEquals(originalLogin, savedUser.getLogin());
- Assert.assertEquals(email, savedUser.getEmail());
- Assert.assertNotNull(savedUser.getEmailActivationToken());
- }
-
- @Test
- public void testValidateEmail() throws EntityNotFoundException, UserInvalidPasswordException, UserEmailAlreadyUsedException, UserInvalidEmailActiviationTokenException {
-
- PollenUser user = service.getUser("pollen_user_tony");
- Assert.assertNotNull(user);
- Assert.assertNull(user.getEmailActivationToken());
-
- serviceContext.getPersistenceContext().detach(user);
-
- String email = "tony(a)pollen.org";
- user.setEmail(email);
- user.setPassword("fake");
-
- PollenUser savedUser = service.editUser(user);
- Assert.assertNotNull(savedUser);
-
- Assert.assertEquals(email, savedUser.getEmail());
- Assert.assertNotNull(savedUser.getEmailActivationToken());
-
- try {
- service.validateUserEmail(user.getId(), "fakeToken");
- Assert.fail();
- } catch (UserInvalidEmailActiviationTokenException e) {
- Assert.assertTrue(true);
- }
-
- Assert.assertFalse(savedUser.isEmailActivated());
-
- service.validateUserEmail(user.getId(), savedUser.getEmailActivationToken());
-
-
-
- PollenUser reloadedUser = service.getUser("pollen_user_tony");
- Assert.assertTrue(reloadedUser.isEmailActivated());
-
- }
-}
Copied: branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/UserServiceTest.java (from rev 3821, branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java)
===================================================================
--- branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/UserServiceTest.java (rev 0)
+++ branches/pollen-2.0/pollen-services/src/test/java/org/chorem/pollen/service/UserServiceTest.java 2013-06-14 09:12:59 UTC (rev 3823)
@@ -0,0 +1,202 @@
+package org.chorem.pollen.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.apache.commons.collections.CollectionUtils;
+import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.services.exception.EntityNotFoundException;
+import org.chorem.pollen.services.exception.UserEmailAlreadyUsedException;
+import org.chorem.pollen.services.exception.UserInvalidEmailActiviationTokenException;
+import org.chorem.pollen.services.exception.UserInvalidPasswordException;
+import org.chorem.pollen.services.exception.UserLoginAlreadyUsedException;
+import org.chorem.pollen.services.service.UserService;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.text.ParseException;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class UserServiceTest extends AbstractPollenServiceTest {
+
+ protected UserService service;
+
+ protected PollenUser user;
+
+ @Before
+ public void setUp() throws ParseException {
+
+ loadFixtures("fixtures");
+
+ service = serviceContext.getUserService();
+
+ serviceContext.setDate(new Date(1363948427576l));
+
+ user = fixture("tony");
+ }
+
+ @Test
+ public void testGetPollenUsers() {
+
+ List<PollenUser> users = service.getUsers();
+
+ Assert.assertNotNull(users);
+ Assert.assertTrue(CollectionUtils.isNotEmpty(users));
+ }
+
+ @Test
+ public void testGetPollenUser() throws EntityNotFoundException {
+
+ try {
+ service.getUser("pollen_user_tony_" + System.nanoTime());
+
+ } catch (EntityNotFoundException e) {
+ Assert.assertTrue(true);
+ }
+
+ PollenUser user = service.getUser(this.user.getId());
+
+ Assert.assertNotNull(user);
+ Assert.assertEquals(this.user, user);
+ }
+
+ @Test
+ public void testCreatePollenUser() throws Exception {
+
+ try {
+ service.createUser(user, false);
+ Assert.fail();
+ } catch (IllegalStateException e) {
+ // Should having id
+ Assert.assertTrue(true);
+ }
+
+ PollenUser newUser = new PollenUser();
+ newUser.setLogin("pollen");
+ newUser.setEmail("pollen(a)pollen.org");
+
+ PollenUser savedUser = service.createUser(newUser, true);
+ Assert.assertNotNull(savedUser);
+ Assert.assertNotNull(savedUser.getId());
+
+ PollenUser newUser2 = new PollenUser();
+ newUser2.setLogin("pollen");
+ newUser2.setEmail("pollen(a)pollen.org");
+
+ try {
+ service.createUser(newUser2, true);
+ Assert.fail();
+ } catch (UserLoginAlreadyUsedException e) {
+ Assert.assertTrue(true);
+ }
+
+ newUser2.setLogin("pollen2");
+ try {
+ service.createUser(newUser2, true);
+ Assert.fail();
+ } catch (UserEmailAlreadyUsedException e) {
+ Assert.assertTrue(true);
+ }
+
+ newUser2.setEmail("pollen2(a)pollen.org");
+ PollenUser savedUser2 = service.createUser(newUser2, true);
+ Assert.assertNotNull(savedUser2);
+ Assert.assertNotNull(savedUser2.getId());
+ }
+
+ @Test
+ public void testEditUser() throws EntityNotFoundException, UserInvalidPasswordException, UserEmailAlreadyUsedException {
+
+ PollenUser user = service.getUser(this.user.getId());
+
+ Assert.assertNotNull(user);
+ Assert.assertNull(user.getEmailActivationToken());
+
+ serviceContext.getPersistenceContext().detach(user);
+
+ String originalLogin = user.getLogin();
+
+ user.setLogin("yetanotherlogin");
+ String email = "tony(a)pollen.org";
+ user.setEmail(email);
+
+ try {
+ service.editUser(user);
+ Assert.fail();
+ } catch (UserInvalidPasswordException e) {
+ Assert.assertTrue(true);
+ }
+
+ user.setPassword("fake");
+ PollenUser savedUser = service.editUser(user);
+ Assert.assertNotNull(savedUser);
+ Assert.assertEquals(originalLogin, savedUser.getLogin());
+ Assert.assertEquals(email, savedUser.getEmail());
+ Assert.assertNotNull(savedUser.getEmailActivationToken());
+ }
+
+ @Test
+ public void testValidateEmail() throws EntityNotFoundException, UserInvalidPasswordException, UserEmailAlreadyUsedException, UserInvalidEmailActiviationTokenException {
+
+ PollenUser user = service.getUser(this.user.getId());
+ Assert.assertNotNull(user);
+ Assert.assertNull(user.getEmailActivationToken());
+
+ serviceContext.getPersistenceContext().detach(user);
+
+ String email = "tony(a)pollen.org";
+ user.setEmail(email);
+ user.setPassword("fake");
+
+ PollenUser savedUser = service.editUser(user);
+ Assert.assertNotNull(savedUser);
+
+ Assert.assertEquals(email, savedUser.getEmail());
+ Assert.assertNotNull(savedUser.getEmailActivationToken());
+
+ try {
+ service.validateUserEmail(user.getId(), "fakeToken");
+ Assert.fail();
+ } catch (UserInvalidEmailActiviationTokenException e) {
+ Assert.assertTrue(true);
+ }
+
+ Assert.assertFalse(savedUser.isEmailActivated());
+
+ service.validateUserEmail(user.getId(), savedUser.getEmailActivationToken());
+
+
+
+ PollenUser reloadedUser = service.getUser(this.user.getId());
+ Assert.assertTrue(reloadedUser.isEmailActivated());
+
+ }
+}
Modified: branches/pollen-2.0/pom.xml
===================================================================
--- branches/pollen-2.0/pom.xml 2013-06-12 18:00:23 UTC (rev 3822)
+++ branches/pollen-2.0/pom.xml 2013-06-14 09:12:59 UTC (rev 3823)
@@ -130,13 +130,10 @@
</contributors>
<modules>
- <!--module>pollen-votecounting-api</module>
- <module>pollen-votecounting-aggregator</module-->
- <!--module>pollen-persistence</module>
- <module>pollen-services</module>
- <module>pollen-ui-struts2</module-->
+ <module>pollen-votecounting-api</module>
+ <module>pollen-votecounting-aggregator</module>
<module>pollen-persistence</module>
- <module>pollen-service</module>
+ <module>pollen-services</module>
<module>pollen-rest-api</module>
</modules>
@@ -291,6 +288,7 @@
<groupId>org.debux.webmotion</groupId>
<artifactId>webmotion-unittest</artifactId>
<version>${webmotionVersion}</version>
+ <scope>test</scope>
</dependency>
<dependency>
1
0
r3822 - in branches/pollen-2.0/pollen-ui-js/src/main/webapp: . css img js/controls js/libs js/models views
by kmorin@users.chorem.org 12 Jun '13
by kmorin@users.chorem.org 12 Jun '13
12 Jun '13
Author: kmorin
Date: 2013-06-12 20:00:23 +0200 (Wed, 12 Jun 2013)
New Revision: 3822
Url: http://chorem.org/projects/pollen/repository/revisions/3822
Log:
JS UI (con't)
Added:
branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons_050_link.png
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/date.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/jquery.scrollto.js
Modified:
branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css
branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css
branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css 2013-06-12 18:00:23 UTC (rev 3822)
@@ -6,4 +6,869 @@
* http://www.apache.org/licenses/LICENSE-2.0
*
* Designed and built with all the love in the world @twitter by @mdo and @fat.
- */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}
+ */
+.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;}
+.clearfix:after{clear:both;}
+.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}
+.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
+article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
+audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
+audio:not([controls]){display:none;}
+html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
+a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
+a:hover,a:active{outline:0;}
+sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
+sup{top:-0.5em;}
+sub{bottom:-0.25em;}
+img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}
+#map_canvas img,.google-maps img{max-width:none;}
+button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
+button,input{*overflow:visible;line-height:normal;}
+button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
+button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}
+label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer;}
+input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;}
+input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
+textarea{overflow:auto;vertical-align:top;}
+@media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important;} a,a:visited{text-decoration:underline;} a[href]:after{content:" (" attr(href) ")";} abbr[title]:after{content:" (" attr(title) ")";} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:"";} pre,blockquote{border:1px solid #999;page-break-inside:avoid;} thead{display:table-header-group;} tr,img{page-break-inside:avoid;} img{max-width:100% !important;} @page {margin:0.5cm;}p,h2,h3{orphans:3;widows:3;} h2,h3{page-break-after:avoid;}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333333;background-color:#ffffff;}
+a{color:#0088cc;text-decoration:none;}
+a:hover,a:focus{color:#005580;text-decoration:underline;}
+.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
+.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);}
+.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px;}
+.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;}
+.row:after{clear:both;}
+[class*="span"]{float:left;min-height:1px;margin-left:20px;}
+.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
+.span12{width:940px;}
+.span11{width:860px;}
+.span10{width:780px;}
+.span9{width:700px;}
+.span8{width:620px;}
+.span7{width:540px;}
+.span6{width:460px;}
+.span5{width:380px;}
+.span4{width:300px;}
+.span3{width:220px;}
+.span2{width:140px;}
+.span1{width:60px;}
+.offset12{margin-left:980px;}
+.offset11{margin-left:900px;}
+.offset10{margin-left:820px;}
+.offset9{margin-left:740px;}
+.offset8{margin-left:660px;}
+.offset7{margin-left:580px;}
+.offset6{margin-left:500px;}
+.offset5{margin-left:420px;}
+.offset4{margin-left:340px;}
+.offset3{margin-left:260px;}
+.offset2{margin-left:180px;}
+.offset1{margin-left:100px;}
+.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;}
+.row-fluid:after{clear:both;}
+.row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;}
+.row-fluid [class*="span"]:first-child{margin-left:0;}
+.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%;}
+.row-fluid .span12{width:100%;*width:99.94680851063829%;}
+.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;}
+.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;}
+.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;}
+.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;}
+.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;}
+.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;}
+.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;}
+.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;}
+.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;}
+.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;}
+.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;}
+.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;}
+.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%;}
+.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%;}
+.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%;}
+.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%;}
+.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%;}
+.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%;}
+.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%;}
+.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%;}
+.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%;}
+.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%;}
+.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%;}
+.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%;}
+.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%;}
+.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%;}
+.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%;}
+.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%;}
+.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%;}
+.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%;}
+.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%;}
+.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%;}
+.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%;}
+.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%;}
+.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;}
+[class*="span"].hide,.row-fluid [class*="span"].hide{display:none;}
+[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right;}
+.container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";line-height:0;}
+.container:after{clear:both;}
+.container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0;}
+.container-fluid:after{clear:both;}
+p{margin:0 0 10px;}
+.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;}
+small{font-size:85%;}
+strong{font-weight:bold;}
+em{font-style:italic;}
+cite{font-style:normal;}
+.muted{color:#999999;}
+a.muted:hover,a.muted:focus{color:#808080;}
+.text-warning{color:#c09853;}
+a.text-warning:hover,a.text-warning:focus{color:#a47e3c;}
+.text-error{color:#b94a48;}
+a.text-error:hover,a.text-error:focus{color:#953b39;}
+.text-info{color:#3a87ad;}
+a.text-info:hover,a.text-info:focus{color:#2d6987;}
+.text-success{color:#468847;}
+a.text-success:hover,a.text-success:focus{color:#356635;}
+.text-left{text-align:left;}
+.text-right{text-align:right;}
+.text-center{text-align:center;}
+h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999999;}
+h1,h2,h3{line-height:40px;}
+h1{font-size:38.5px;}
+h2{font-size:31.5px;}
+h3{font-size:24.5px;}
+h4{font-size:17.5px;}
+h5{font-size:14px;}
+h6{font-size:11.9px;}
+h1 small{font-size:24.5px;}
+h2 small{font-size:17.5px;}
+h3 small{font-size:14px;}
+h4 small{font-size:14px;}
+.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;}
+ul,ol{padding:0;margin:0 0 10px 25px;}
+ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
+li{line-height:20px;}
+ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
+ul.inline,ol.inline{margin-left:0;list-style:none;}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px;}
+dl{margin-bottom:20px;}
+dt,dd{line-height:20px;}
+dt{font-weight:bold;}
+dd{margin-left:10px;}
+.dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0;}
+.dl-horizontal:after{clear:both;}
+.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
+.dl-horizontal dd{margin-left:180px;}
+hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
+abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;}
+abbr.initialism{font-size:90%;text-transform:uppercase;}
+blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25;}
+blockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
+blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
+blockquote.pull-right small:before{content:'';}
+blockquote.pull-right small:after{content:'\00A0 \2014';}
+q:before,q:after,blockquote:before,blockquote:after{content:"";}
+address{display:block;margin-bottom:20px;font-style:normal;line-height:20px;}
+code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap;}
+pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:20px;}
+pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0;}
+.pre-scrollable{max-height:340px;overflow-y:scroll;}
+.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;}
+.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.badge{padding-left:9px;padding-right:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}
+.label:empty,.badge:empty{display:none;}
+a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer;}
+.label-important,.badge-important{background-color:#b94a48;}
+.label-important[href],.badge-important[href]{background-color:#953b39;}
+.label-warning,.badge-warning{background-color:#f89406;}
+.label-warning[href],.badge-warning[href]{background-color:#c67605;}
+.label-success,.badge-success{background-color:#468847;}
+.label-success[href],.badge-success[href]{background-color:#356635;}
+.label-info,.badge-info{background-color:#3a87ad;}
+.label-info[href],.badge-info[href]{background-color:#2d6987;}
+.label-inverse,.badge-inverse{background-color:#333333;}
+.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;}
+.btn .label,.btn .badge{position:relative;top:-1px;}
+.btn-mini .label,.btn-mini .badge{top:0;}
+table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}
+.table{width:100%;margin-bottom:20px;}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;}
+.table th{font-weight:bold;}
+.table thead th{vertical-align:bottom;}
+.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;}
+.table tbody+tbody{border-top:2px solid #dddddd;}
+.table .table{background-color:#ffffff;}
+.table-condensed th,.table-condensed td{padding:4px 5px;}
+.table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}
+.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}
+.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;}
+.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;}
+.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
+.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
+.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0;}
+.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0;}
+.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;}
+.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;}
+.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9;}
+.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5;}
+table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0;}
+.table td.span1,.table th.span1{float:none;width:44px;margin-left:0;}
+.table td.span2,.table th.span2{float:none;width:124px;margin-left:0;}
+.table td.span3,.table th.span3{float:none;width:204px;margin-left:0;}
+.table td.span4,.table th.span4{float:none;width:284px;margin-left:0;}
+.table td.span5,.table th.span5{float:none;width:364px;margin-left:0;}
+.table td.span6,.table th.span6{float:none;width:444px;margin-left:0;}
+.table td.span7,.table th.span7{float:none;width:524px;margin-left:0;}
+.table td.span8,.table th.span8{float:none;width:604px;margin-left:0;}
+.table td.span9,.table th.span9{float:none;width:684px;margin-left:0;}
+.table td.span10,.table th.span10{float:none;width:764px;margin-left:0;}
+.table td.span11,.table th.span11{float:none;width:844px;margin-left:0;}
+.table td.span12,.table th.span12{float:none;width:924px;margin-left:0;}
+.table tbody tr.success>td{background-color:#dff0d8;}
+.table tbody tr.error>td{background-color:#f2dede;}
+.table tbody tr.warning>td{background-color:#fcf8e3;}
+.table tbody tr.info>td{background-color:#d9edf7;}
+.table-hover tbody tr.success:hover>td{background-color:#d0e9c6;}
+.table-hover tbody tr.error:hover>td{background-color:#ebcccc;}
+.table-hover tbody tr.warning:hover>td{background-color:#faf2cc;}
+.table-hover tbody tr.info:hover>td{background-color:#c4e3f3;}
+form{margin:0 0 20px;}
+fieldset{padding:0;margin:0;border:0;}
+legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;}
+label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px;}
+input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
+label{display:block;margin-bottom:5px;}
+select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle;}
+input,textarea,.uneditable-input{width:206px;}
+textarea{height:auto;}
+textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);}
+input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal;}
+input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;}
+select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px;}
+select{width:220px;border:1px solid #cccccc;background-color:#ffffff;}
+select[multiple],select[size]{height:auto;}
+select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
+.uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
+.uneditable-input{overflow:hidden;white-space:nowrap;}
+.uneditable-textarea{width:auto;height:auto;}
+input:-moz-placeholder,textarea:-moz-placeholder{color:#999999;}
+input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;}
+input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;}
+.radio,.checkbox{min-height:20px;padding-left:20px;}
+.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px;}
+.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
+.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
+.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
+.input-mini{width:60px;}
+.input-small{width:90px;}
+.input-medium{width:150px;}
+.input-large{width:210px;}
+.input-xlarge{width:270px;}
+.input-xxlarge{width:530px;}
+input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0;}
+.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block;}
+input,textarea,.uneditable-input{margin-left:0;}
+.controls-row [class*="span"]+[class*="span"]{margin-left:20px;}
+input.span12,textarea.span12,.uneditable-input.span12{width:926px;}
+input.span11,textarea.span11,.uneditable-input.span11{width:846px;}
+input.span10,textarea.span10,.uneditable-input.span10{width:766px;}
+input.span9,textarea.span9,.uneditable-input.span9{width:686px;}
+input.span8,textarea.span8,.uneditable-input.span8{width:606px;}
+input.span7,textarea.span7,.uneditable-input.span7{width:526px;}
+input.span6,textarea.span6,.uneditable-input.span6{width:446px;}
+input.span5,textarea.span5,.uneditable-input.span5{width:366px;}
+input.span4,textarea.span4,.uneditable-input.span4{width:286px;}
+input.span3,textarea.span3,.uneditable-input.span3{width:206px;}
+input.span2,textarea.span2,.uneditable-input.span2{width:126px;}
+input.span1,textarea.span1,.uneditable-input.span1{width:46px;}
+.controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0;}
+.controls-row:after{clear:both;}
+.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left;}
+.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px;}
+input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;}
+input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;}
+.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
+.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;}
+.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;}
+.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
+.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
+.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;}
+.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;}
+.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
+.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
+.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;}
+.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;}
+.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
+.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad;}
+.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad;}
+.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;}
+.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad;}
+input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
+.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0;}
+.form-actions:after{clear:both;}
+.help-block,.help-inline{color:#595959;}
+.help-block{display:block;margin-bottom:10px;}
+.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;}
+.input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap;}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px;}
+.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2;}
+.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#eeeeee;border:1px solid #ccc;}
+.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;}
+.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;}
+.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
+.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
+.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px;}
+.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
+.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
+.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
+.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
+.input-prepend.input-append .btn-group:first-child{margin-left:0;}
+input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
+.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
+.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
+.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
+.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
+.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle;}
+.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
+.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;}
+.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;}
+.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;}
+.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0;}
+.control-group{margin-bottom:10px;}
+legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;}
+.form-horizontal .control-group{margin-bottom:20px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0;}
+.form-horizontal .control-group:after{clear:both;}
+.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;}
+.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;}
+.form-horizontal .help-block{margin-bottom:0;}
+.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px;}
+.form-horizontal .form-actions{padding-left:180px;}
+.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #cccccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;}
+.btn:active,.btn.active{background-color:#cccccc \9;}
+.btn:first-child{*margin-left:0;}
+.btn:hover,.btn:focus{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
+.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
+.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);}
+.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
+.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px;}
+.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0;}
+.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px;}
+.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
+.btn-block+.btn-block{margin-top:5px;}
+input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%;}
+.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);}
+.btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;}
+.btn-primary:active,.btn-primary.active{background-color:#003399 \9;}
+.btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;}
+.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
+.btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;}
+.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
+.btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;}
+.btn-success:active,.btn-success.active{background-color:#408140 \9;}
+.btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;}
+.btn-info:active,.btn-info.active{background-color:#24748c \9;}
+.btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;}
+.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;}
+button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
+button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}
+button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}
+button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}
+.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+.btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent;}
+.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333333;text-decoration:none;}
+[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px;}
+.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png");}
+.icon-glass{background-position:0 0;}
+.icon-music{background-position:-24px 0;}
+.icon-search{background-position:-48px 0;}
+.icon-envelope{background-position:-72px 0;}
+.icon-heart{background-position:-96px 0;}
+.icon-star{background-position:-120px 0;}
+.icon-star-empty{background-position:-144px 0;}
+.icon-user{background-position:-168px 0;}
+.icon-film{background-position:-192px 0;}
+.icon-th-large{background-position:-216px 0;}
+.icon-th{background-position:-240px 0;}
+.icon-th-list{background-position:-264px 0;}
+.icon-ok{background-position:-288px 0;}
+.icon-remove{background-position:-312px 0;}
+.icon-zoom-in{background-position:-336px 0;}
+.icon-zoom-out{background-position:-360px 0;}
+.icon-off{background-position:-384px 0;}
+.icon-signal{background-position:-408px 0;}
+.icon-cog{background-position:-432px 0;}
+.icon-trash{background-position:-456px 0;}
+.icon-home{background-position:0 -24px;}
+.icon-file{background-position:-24px -24px;}
+.icon-time{background-position:-48px -24px;}
+.icon-road{background-position:-72px -24px;}
+.icon-download-alt{background-position:-96px -24px;}
+.icon-download{background-position:-120px -24px;}
+.icon-upload{background-position:-144px -24px;}
+.icon-inbox{background-position:-168px -24px;}
+.icon-play-circle{background-position:-192px -24px;}
+.icon-repeat{background-position:-216px -24px;}
+.icon-refresh{background-position:-240px -24px;}
+.icon-list-alt{background-position:-264px -24px;}
+.icon-lock{background-position:-287px -24px;}
+.icon-flag{background-position:-312px -24px;}
+.icon-headphones{background-position:-336px -24px;}
+.icon-volume-off{background-position:-360px -24px;}
+.icon-volume-down{background-position:-384px -24px;}
+.icon-volume-up{background-position:-408px -24px;}
+.icon-qrcode{background-position:-432px -24px;}
+.icon-barcode{background-position:-456px -24px;}
+.icon-tag{background-position:0 -48px;}
+.icon-tags{background-position:-25px -48px;}
+.icon-book{background-position:-48px -48px;}
+.icon-bookmark{background-position:-72px -48px;}
+.icon-print{background-position:-96px -48px;}
+.icon-camera{background-position:-120px -48px;}
+.icon-font{background-position:-144px -48px;}
+.icon-bold{background-position:-167px -48px;}
+.icon-italic{background-position:-192px -48px;}
+.icon-text-height{background-position:-216px -48px;}
+.icon-text-width{background-position:-240px -48px;}
+.icon-align-left{background-position:-264px -48px;}
+.icon-align-center{background-position:-288px -48px;}
+.icon-align-right{background-position:-312px -48px;}
+.icon-align-justify{background-position:-336px -48px;}
+.icon-list{background-position:-360px -48px;}
+.icon-indent-left{background-position:-384px -48px;}
+.icon-indent-right{background-position:-408px -48px;}
+.icon-facetime-video{background-position:-432px -48px;}
+.icon-picture{background-position:-456px -48px;}
+.icon-pencil{background-position:0 -72px;}
+.icon-map-marker{background-position:-24px -72px;}
+.icon-adjust{background-position:-48px -72px;}
+.icon-tint{background-position:-72px -72px;}
+.icon-edit{background-position:-96px -72px;}
+.icon-share{background-position:-120px -72px;}
+.icon-check{background-position:-144px -72px;}
+.icon-move{background-position:-168px -72px;}
+.icon-step-backward{background-position:-192px -72px;}
+.icon-fast-backward{background-position:-216px -72px;}
+.icon-backward{background-position:-240px -72px;}
+.icon-play{background-position:-264px -72px;}
+.icon-pause{background-position:-288px -72px;}
+.icon-stop{background-position:-312px -72px;}
+.icon-forward{background-position:-336px -72px;}
+.icon-fast-forward{background-position:-360px -72px;}
+.icon-step-forward{background-position:-384px -72px;}
+.icon-eject{background-position:-408px -72px;}
+.icon-chevron-left{background-position:-432px -72px;}
+.icon-chevron-right{background-position:-456px -72px;}
+.icon-plus-sign{background-position:0 -96px;}
+.icon-minus-sign{background-position:-24px -96px;}
+.icon-remove-sign{background-position:-48px -96px;}
+.icon-ok-sign{background-position:-72px -96px;}
+.icon-question-sign{background-position:-96px -96px;}
+.icon-info-sign{background-position:-120px -96px;}
+.icon-screenshot{background-position:-144px -96px;}
+.icon-remove-circle{background-position:-168px -96px;}
+.icon-ok-circle{background-position:-192px -96px;}
+.icon-ban-circle{background-position:-216px -96px;}
+.icon-arrow-left{background-position:-240px -96px;}
+.icon-arrow-right{background-position:-264px -96px;}
+.icon-arrow-up{background-position:-289px -96px;}
+.icon-arrow-down{background-position:-312px -96px;}
+.icon-share-alt{background-position:-336px -96px;}
+.icon-resize-full{background-position:-360px -96px;}
+.icon-resize-small{background-position:-384px -96px;}
+.icon-plus{background-position:-408px -96px;}
+.icon-minus{background-position:-433px -96px;}
+.icon-asterisk{background-position:-456px -96px;}
+.icon-exclamation-sign{background-position:0 -120px;}
+.icon-gift{background-position:-24px -120px;}
+.icon-leaf{background-position:-48px -120px;}
+.icon-fire{background-position:-72px -120px;}
+.icon-eye-open{background-position:-96px -120px;}
+.icon-eye-close{background-position:-120px -120px;}
+.icon-warning-sign{background-position:-144px -120px;}
+.icon-plane{background-position:-168px -120px;}
+.icon-calendar{background-position:-192px -120px;}
+.icon-random{background-position:-216px -120px;width:16px;}
+.icon-comment{background-position:-240px -120px;}
+.icon-magnet{background-position:-264px -120px;}
+.icon-chevron-up{background-position:-288px -120px;}
+.icon-chevron-down{background-position:-313px -119px;}
+.icon-retweet{background-position:-336px -120px;}
+.icon-shopping-cart{background-position:-360px -120px;}
+.icon-folder-close{background-position:-384px -120px;width:16px;}
+.icon-folder-open{background-position:-408px -120px;width:16px;}
+.icon-resize-vertical{background-position:-432px -119px;}
+.icon-resize-horizontal{background-position:-456px -118px;}
+.icon-hdd{background-position:0 -144px;}
+.icon-bullhorn{background-position:-24px -144px;}
+.icon-bell{background-position:-48px -144px;}
+.icon-certificate{background-position:-72px -144px;}
+.icon-thumbs-up{background-position:-96px -144px;}
+.icon-thumbs-down{background-position:-120px -144px;}
+.icon-hand-right{background-position:-144px -144px;}
+.icon-hand-left{background-position:-168px -144px;}
+.icon-hand-up{background-position:-192px -144px;}
+.icon-hand-down{background-position:-216px -144px;}
+.icon-circle-arrow-right{background-position:-240px -144px;}
+.icon-circle-arrow-left{background-position:-264px -144px;}
+.icon-circle-arrow-up{background-position:-288px -144px;}
+.icon-circle-arrow-down{background-position:-312px -144px;}
+.icon-globe{background-position:-336px -144px;}
+.icon-wrench{background-position:-360px -144px;}
+.icon-tasks{background-position:-384px -144px;}
+.icon-filter{background-position:-408px -144px;}
+.icon-briefcase{background-position:-432px -144px;}
+.icon-fullscreen{background-position:-456px -144px;}
+.btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em;}.btn-group:first-child{*margin-left:0;}
+.btn-group+.btn-group{margin-left:5px;}
+.btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px;}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px;}
+.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.btn-group>.btn+.btn{margin-left:-1px;}
+.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px;}
+.btn-group>.btn-mini{font-size:10.5px;}
+.btn-group>.btn-small{font-size:11.9px;}
+.btn-group>.btn-large{font-size:17.5px;}
+.btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
+.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
+.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
+.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
+.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;}
+.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
+.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px;}
+.btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;}
+.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;}
+.btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;}
+.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);}
+.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;}
+.btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;}
+.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;}
+.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;}
+.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;}
+.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;}
+.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;}
+.btn .caret{margin-top:8px;margin-left:0;}
+.btn-large .caret{margin-top:6px;}
+.btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;}
+.btn-mini .caret,.btn-small .caret{margin-top:8px;}
+.dropup .btn-large .caret{border-bottom-width:5px;}
+.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
+.btn-group-vertical{display:inline-block;*display:inline;*zoom:1;}
+.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px;}
+.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
+.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
+.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;}
+.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
+.nav{margin-left:0;margin-bottom:20px;list-style:none;}
+.nav>li>a{display:block;}
+.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eeeeee;}
+.nav>li>a>img{max-width:none;}
+.nav>.pull-right{float:right;}
+.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}
+.nav li+.nav-header{margin-top:9px;}
+.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;}
+.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}
+.nav-list>li>a{padding:3px 15px;}
+.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}
+.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px;}
+.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}
+.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0;}
+.nav-tabs:after,.nav-pills:after{clear:both;}
+.nav-tabs>li,.nav-pills>li{float:left;}
+.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
+.nav-tabs{border-bottom:1px solid #ddd;}
+.nav-tabs>li{margin-bottom:-1px;}
+.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #dddddd;}
+.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
+.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
+.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#ffffff;background-color:#0088cc;}
+.nav-stacked>li{float:none;}
+.nav-stacked>li>a{margin-right:0;}
+.nav-tabs.nav-stacked{border-bottom:0;}
+.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;}
+.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
+.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2;}
+.nav-pills.nav-stacked>li>a{margin-bottom:3px;}
+.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
+.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
+.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
+.nav .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;}
+.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580;}
+.nav-tabs .dropdown-toggle .caret{margin-top:8px;}
+.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff;}
+.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;}
+.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer;}
+.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#ffffff;background-color:#999999;border-color:#999999;}
+.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
+.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999999;}
+.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0;}
+.tabbable:after{clear:both;}
+.tab-content{overflow:auto;}
+.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;}
+.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
+.tab-content>.active,.pill-content>.active{display:block;}
+.tabs-below>.nav-tabs{border-top:1px solid #ddd;}
+.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;}
+.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd;}
+.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd;}
+.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;}
+.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
+.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
+.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
+.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
+.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
+.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
+.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
+.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
+.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
+.nav>.disabled>a{color:#999999;}
+.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default;}
+.navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2;}
+.navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);*zoom:1;}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0;}
+.navbar-inner:after{clear:both;}
+.navbar .container{width:auto;}
+.nav-collapse.collapse{height:auto;overflow:visible;}
+.navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff;}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none;}
+.navbar-text{margin-bottom:0;line-height:40px;color:#777777;}
+.navbar-link{color:#777777;}.navbar-link:hover,.navbar-link:focus{color:#333333;}
+.navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #ffffff;}
+.navbar .btn,.navbar .btn-group{margin-top:5px;}
+.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0;}
+.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0;}
+.navbar-form:after{clear:both;}
+.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}
+.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0;}
+.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;}
+.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;}
+.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0;}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
+.navbar-static-top{position:static;margin-bottom:0;}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;}
+.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px;}
+.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0;}
+.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
+.navbar-fixed-top{top:0;}
+.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1);}
+.navbar-fixed-bottom{bottom:0;}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1);}
+.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}
+.navbar .nav.pull-right{float:right;margin-right:0;}
+.navbar .nav>li{float:left;}
+.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff;}
+.navbar .nav .dropdown-toggle .caret{margin-top:8px;}
+.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333333;text-decoration:none;}
+.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);}
+.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9;}
+.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#cccccc \9;}
+.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);}
+.btn-navbar .icon-bar+.icon-bar{margin-top:3px;}
+.navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;}
+.navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}
+.navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;}
+.navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;}
+.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333333;border-bottom-color:#333333;}
+.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555555;}
+.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777777;border-bottom-color:#777777;}
+.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;}
+.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0;}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px;}
+.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px;}
+.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
+.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525;}
+.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#ffffff;}
+.navbar-inverse .brand{color:#999999;}
+.navbar-inverse .navbar-text{color:#999999;}
+.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#ffffff;}
+.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#ffffff;background-color:#111111;}
+.navbar-inverse .navbar-link{color:#999999;}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#ffffff;}
+.navbar-inverse .divider-vertical{border-left-color:#111111;border-right-color:#222222;}
+.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111111;color:#ffffff;}
+.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
+.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999999;border-bottom-color:#999999;}
+.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
+.navbar-inverse .navbar-search .search-query{color:#ffffff;background-color:#515151;border-color:#111111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none;}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#cccccc;}
+.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#cccccc;}
+.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;}
+.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;}
+.navbar-inverse .btn-navbar{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000;}
+.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000000 \9;}
+.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;}.breadcrumb>li>.divider{padding:0 5px;color:#ccc;}
+.breadcrumb>.active{color:#999999;}
+.pagination{margin:20px 0;}
+.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
+.pagination ul>li{display:inline;}
+.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0;}
+.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5;}
+.pagination ul>.active>a,.pagination ul>.active>span{color:#999999;cursor:default;}
+.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999999;background-color:transparent;cursor:default;}
+.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
+.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
+.pagination-centered{text-align:center;}
+.pagination-right{text-align:right;}
+.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px;}
+.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
+.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
+.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px;}
+.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px;}
+.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px;}
+.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px;}
+.pager{margin:20px 0;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";line-height:0;}
+.pager:after{clear:both;}
+.pager li{display:inline;}
+.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
+.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5;}
+.pager .next>a,.pager .next>span{float:right;}
+.pager .previous>a,.pager .previous>span{float:left;}
+.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999999;background-color:#fff;cursor:default;}
+.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0;}
+.thumbnails:after{clear:both;}
+.row-fluid .thumbnails{margin-left:0;}
+.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px;}
+.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;}
+a.thumbnail:hover,a.thumbnail:focus{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);}
+.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}
+.thumbnail .caption{padding:9px;color:#555555;}
+.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.alert,.alert h4{color:#c09853;}
+.alert h4{margin:0;}
+.alert .close{position:relative;top:-2px;right:-21px;line-height:20px;}
+.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;}
+.alert-success h4{color:#468847;}
+.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;}
+.alert-danger h4,.alert-error h4{color:#b94a48;}
+.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;}
+.alert-info h4{color:#3a87ad;}
+.alert-block{padding-top:14px;padding-bottom:14px;}
+.alert-block>p,.alert-block>ul{margin-bottom:0;}
+.alert-block p+p{margin-top:5px;}
+@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-o-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.progress .bar{width:0%;height:100%;color:#ffffff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}
+.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);}
+.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;}
+.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;}
+.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);}
+.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);}
+.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);}
+.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);}
+.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;}
+.hero-unit li{line-height:30px;}
+.media,.media-body{overflow:hidden;*overflow:visible;zoom:1;}
+.media,.media .media{margin-top:15px;}
+.media:first-child{margin-top:0;}
+.media-object{display:block;}
+.media-heading{margin:0 0 5px;}
+.media>.pull-left{margin-right:10px;}
+.media>.pull-right{margin-left:10px;}
+.media-list{margin-left:0;list-style:none;}
+.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}
+.tooltip.top{margin-top:-3px;padding:5px 0;}
+.tooltip.right{margin-left:3px;padding:0 5px;}
+.tooltip.bottom{margin-top:3px;padding:5px 0;}
+.tooltip.left{margin-left:-3px;padding:0 5px;}
+.tooltip-inner{max-width:200px;padding:8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;}
+.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000;}
+.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000;}
+.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000;}
+.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000;}
+.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#ffffff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);white-space:normal;}.popover.top{margin-top:-10px;}
+.popover.right{margin-left:10px;}
+.popover.bottom{margin-top:10px;}
+.popover.left{margin-left:-10px;}
+.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}.popover-title:empty{display:none;}
+.popover-content{padding:9px 14px;}
+.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid;}
+.popover .arrow{border-width:11px;}
+.popover .arrow:after{border-width:10px;content:"";}
+.popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0, 0, 0, 0.25);bottom:-11px;}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff;}
+.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0, 0, 0, 0.25);}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff;}
+.popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0, 0, 0, 0.25);top:-11px;}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff;}
+.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0, 0, 0, 0.25);}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px;}
+.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
+.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
+.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
+.modal.fade.in{top:10%;}
+.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
+.modal-header h3{margin:0;line-height:30px;}
+.modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px;}
+.modal-form{margin-bottom:0;}
+.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0;}
+.modal-footer:after{clear:both;}
+.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;}
+.modal-footer .btn-group .btn+.btn{margin-left:-1px;}
+.modal-footer .btn-block+.btn-block{margin-left:0;}
+.dropup,.dropdown{position:relative;}
+.dropdown-toggle{*margin-bottom:-3px;}
+.dropdown-toggle:active,.open .dropdown-toggle{outline:0;}
+.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";}
+.dropdown .caret{margin-top:8px;margin-left:2px;}
+.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;}.dropdown-menu.pull-right{right:0;left:auto;}
+.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}
+.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap;}
+.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#ffffff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}
+.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}
+.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999999;}
+.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default;}
+.open{*z-index:1000;}.open>.dropdown-menu{display:block;}
+.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990;}
+.pull-right>.dropdown-menu{right:0;left:auto;}
+.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"";}
+.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;}
+.dropdown-submenu{position:relative;}
+.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}
+.dropdown-submenu:hover>.dropdown-menu{display:block;}
+.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0;}
+.dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;}
+.dropdown-submenu:hover>a:after{border-left-color:#ffffff;}
+.dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
+.dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px;}
+.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.accordion{margin-bottom:20px;}
+.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.accordion-heading{border-bottom:0;}
+.accordion-heading .accordion-toggle{display:block;padding:8px 15px;}
+.accordion-toggle{cursor:pointer;}
+.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}
+.carousel{position:relative;margin-bottom:20px;line-height:1;}
+.carousel-inner{overflow:hidden;width:100%;position:relative;}
+.carousel-inner>.item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1;}
+.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block;}
+.carousel-inner>.active{left:0;}
+.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%;}
+.carousel-inner>.next{left:100%;}
+.carousel-inner>.prev{left:-100%;}
+.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0;}
+.carousel-inner>.active.left{left:-100%;}
+.carousel-inner>.active.right{left:100%;}
+.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}
+.carousel-control:hover,.carousel-control:focus{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}
+.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none;}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255, 255, 255, 0.25);border-radius:5px;}
+.carousel-indicators .active{background-color:#fff;}
+.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75);}
+.carousel-caption h4,.carousel-caption p{color:#ffffff;line-height:20px;}
+.carousel-caption h4{margin:0 0 5px;}
+.carousel-caption p{margin-bottom:0;}
+.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
+.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
+.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);}
+button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;}
+.pull-right{float:right;}
+.pull-left{float:left;}
+.hide{display:none;}
+.show{display:block;}
+.invisible{visibility:hidden;}
+.affix{position:fixed;}
+.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;}
+.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;}
+@-ms-viewport{width:device-width;}.hidden{display:none;visibility:hidden;}
+.visible-phone{display:none !important;}
+.visible-tablet{display:none !important;}
+.hidden-desktop{display:none !important;}
+.visible-desktop{display:inherit !important;}
+@media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important ;} .visible-tablet{display:inherit !important;} .hidden-tablet{display:none !important;}}@media (max-width:767px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important;} .visible-phone{display:inherit !important;} .hidden-phone{display:none !important;}}.visible-print{display:none !important;}
+@media print{.visible-print{display:inherit !important;} .hidden-print{display:none !important;}}@media (max-width:767px){body{padding-left:20px;padding-right:20px;} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px;} .container-fluid{padding:0;} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left;} .dl-horizontal dd{margin-left:0;} .container{width:auto;} .row-fluid{width:100%;} .row,.thumbnails{margin-left:0;} .thumbnails>li{float:none;margin-left:0;} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .row-fluid [class*="offset"]:first-child{margin-left:0;} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto;} .controls-row [class*="span"]+[class*="span"]{margin-left:0;} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0;}.modal.fade{top:-100px;} .modal.fade.in{top:20px;}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:20px;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px;} .media-object{margin-right:0;margin-left:0;} .modal{top:10px;left:10px;right:10px;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:20px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%;} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%;} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%;} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%;} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%;} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%;} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%;} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%;} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%;} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%;} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%;} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%;} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%;} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%;} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%;} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%;} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%;} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%;} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%;} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%;} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%;} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%;} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%;} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%;} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%;} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%;} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%;} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%;} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%;} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%;} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%;} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%;} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%;} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%;} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:20px;} input.span12,textarea.span12,.uneditable-input.span12{width:710px;} input.span11,textarea.span11,.uneditable-input.span11{width:648px;} input.span10,textarea.span10,.uneditable-input.span10{width:586px;} input.span9,textarea.span9,.uneditable-input.span9{width:524px;} input.span8,textarea.span8,.uneditable-input.span8{width:462px;} input.span7,textarea.span7,.uneditable-input.span7{width:400px;} input.span6,textarea.span6,.uneditable-input.span6{width:338px;} input.span5,textarea.span5,.uneditable-input.span5{width:276px;} input.span4,textarea.span4,.uneditable-input.span4{width:214px;} input.span3,textarea.span3,.uneditable-input.span3{width:152px;} input.span2,textarea.span2,.uneditable-input.span2{width:90px;} input.span1,textarea.span1,.uneditable-input.span1{width:28px;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:30px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%;} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%;} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%;} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%;} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%;} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%;} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%;} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%;} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%;} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%;} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%;} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%;} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%;} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%;} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%;} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%;} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%;} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%;} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%;} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%;} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%;} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%;} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%;} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%;} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%;} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%;} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%;} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%;} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%;} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%;} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%;} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%;} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%;} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%;} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:30px;} input.span12,textarea.span12,.uneditable-input.span12{width:1156px;} input.span11,textarea.span11,.uneditable-input.span11{width:1056px;} input.span10,textarea.span10,.uneditable-input.span10{width:956px;} input.span9,textarea.span9,.uneditable-input.span9{width:856px;} input.span8,textarea.span8,.uneditable-input.span8{width:756px;} input.span7,textarea.span7,.uneditable-input.span7{width:656px;} input.span6,textarea.span6,.uneditable-input.span6{width:556px;} input.span5,textarea.span5,.uneditable-input.span5{width:456px;} input.span4,textarea.span4,.uneditable-input.span4{width:356px;} input.span3,textarea.span3,.uneditable-input.span3{width:256px;} input.span2,textarea.span2,.uneditable-input.span2{width:156px;} input.span1,textarea.span1,.uneditable-input.span1{width:56px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;} .row-fluid .thumbnails{margin-left:0;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top,.navbar-fixed-bottom{position:static;} .navbar-fixed-top{margin-bottom:20px;} .navbar-fixed-bottom{margin-top:20px;} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .nav-collapse{clear:both;} .nav-collapse .nav{float:none;margin:0 0 10px;} .nav-collapse .nav>li{float:none;} .nav-collapse .nav>li>a{margin-bottom:2px;} .nav-collapse .nav>.divider-vertical{display:none;} .nav-collapse .nav .nav-header{color:#777777;text-shadow:none;} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px;} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2;} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999999;} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111111;} .nav-collapse.in .btn-group{margin-top:5px;padding:0;} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .nav-collapse .open>.dropdown-menu{display:block;} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none;} .nav-collapse .dropdown-menu .divider{display:none;} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none;} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111111;border-bottom-color:#111111;} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0;} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0;} .navbar .btn-navbar{display:block;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;overflow:visible !important;}}
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css 2013-06-12 18:00:23 UTC (rev 3822)
@@ -1,11 +1,61 @@
+.noListStyle {
+ list-style-type: none;
+}
+
+.noListStyle i {
+ margin-right: 5px;
+}
+
+.link {
+ cursor: pointer;
+}
+
+.icon-link {
+ background-image: url(../img/glyphicons_050_link.png);
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 12px 14px;
+}
+
+i.bigger {
+ width: 24px;
+ height: 24px;
+ background-size: 21px 23px;
+}
+
+i.icon-collapse {
+ background-position: -288px -120px;
+}
+
+.collapsed i.icon-collapse {
+ background-position: -313px -119px;
+}
+
#content >div {
- display: none;
+ display: none;
}
-.noListStyle {
- list-style-type: none;
+#choicesSummary {
+ padding: 20px;
+ margin-bottom: 30px;
+ background-color: rgb(238, 238, 238);
+ border-radius: 6px 6px 6px 6px;
}
-.noListStyle i {
- margin-right: 5px;
+#voteForm .choice {
+ background-position: center;
+ background-repeat: no-repeat;
+ text-align: center;
+}
+
+#voteForm .selected {
+ background-color: #6f6;
+}
+
+#voteForm .notSelected {
+ background-color: #f66;
+}
+
+#voteForm .voteBeforeChoice {
+ background-color: #ff6;
}
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons_050_link.png
===================================================================
(Binary files differ)
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons_050_link.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html 2013-06-12 18:00:23 UTC (rev 3822)
@@ -1,4 +1,5 @@
-<html>
+<!DOCTYPE html>
+<html lang="fr">
<head>
<meta charset="utf-8">
<title>Pollen</title>
@@ -8,18 +9,23 @@
<body>
- <div class='container-fluid'>
- <div class="row-fluid">
- <div id="menu" class="span2"></div>
-
- <div class="span10" id="content">
- <!--Body content-->
- <div id="pollForm"></div>
- <div id="pollSummary"></div>
- <div id="vote"></div>
+ <div class="navbar navbar-inverse navbar navbar-static-top">
+ <div class="navbar-inner">
+ <div class='container'>
+ <a class="brand" href="#">Pollen</a>
+ <ul class="nav" id="menu">
+ </ul>
</div>
</div>
+ </div>
+ <div class='container' id="content">
+
+ <!--Body content-->
+ <div id="pollForm"></div>
+ <div id="pollSummary"></div>
+ <div id="vote"></div>
+
</div>
@@ -30,6 +36,8 @@
<script src="js/libs/can.fixture.js"></script>
<script src="js/libs/can.observe.attributes.js"></script>
<script src="js/libs/can.observe.delegate.js"></script>
+ <script src="js/libs/jquery.scrollto.js"></script>
+ <script src="js/libs/date.js"></script>
<script src="js/models/polls.js"></script>
<script src="js/models/comments.js"></script>
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js 2013-06-12 18:00:23 UTC (rev 3822)
@@ -63,9 +63,14 @@
updatePoll: function() {
var form = this.element.find('form'),
- values = can.deparam(form.serialize());
+ values = can.deparam(form.serialize()),
+ self = this;
- this.options.poll.attr(values).save();
+ this.options.poll.attr(values).save(function(data) {
+ if (data.id) {
+// self.options.poll.id = data.id;
+ }
+ });
},
editPoll: function(poll) {
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js 2013-06-12 18:00:23 UTC (rev 3822)
@@ -23,6 +23,7 @@
},
showSummary: function(poll) {
+ this.options.poll = poll;
this.element.html(can.view('views/summary.ejs', {
poll: poll
}));
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js 2013-06-12 18:00:23 UTC (rev 3822)
@@ -1,5 +1,7 @@
var PollVote = can.Control({
+ // route
+
'{can.route} change': function(data, ev, prop, how, newVal, oldVal ) {
if (prop === "type" && (how === "set" || how === "add")) {
if (newVal != "poll") {
@@ -24,13 +26,102 @@
}
},
+ // click events
+
+ '#voteSummary click': function() {
+ this.scrollToComponent($("#voteTable"));
+ },
+
+ '#commentSummary click': function() {
+ this.scrollToComponent($("#comments"));
+ },
+
+ '#voteForm submit': function(form) {
+ var voteToChoices = [];
+ var choices = this.options.poll.choices;
+ for (var i = 0 ; i < choices.length ; i++) {
+ var choice = choices[i];
+ var voteValue = form.find("[name='" + i + "']").is(':checked');
+ voteToChoices.push({ voteValue: voteValue, choice: choice.id });
+ }
+
+ var voteAttributes = {
+ voterListMember: {
+ name: form.find("[name='userName']").val()
+ },
+ voteToChoices: voteToChoices
+ };
+
+ var vote = new Vote(voteAttributes);
+ var self = this;
+ vote.save({ pollId: this.options.poll.id },
+ function(saved) {
+ self.options.votes.push(vote);
+ });
+
+ form[0].reset();
+
+ return false;
+ },
+
+ '#addChoiceForm submit': function(form) {
+ var choices = this.options.poll.choices;
+ var name = form.find("[name='name']").val();
+ var desc = form.find("[name='description']").val();
+ choices.push({ name: name, description: desc });
+
+ form[0].reset();
+
+ return false;
+ },
+
+ '#addCommentForm submit': function(form) {
+ var comments = this.options.poll.comments;
+ var author = form.find("[name='author']").val();
+ var message = form.find("[name='message']").val();
+
+ var comment = new Comment({ author: author, text: message });
+ var self = this;
+ comment.save({ pollId: this.options.poll.id },
+ function(data) {
+ if (data.id) {
+ comment.attr('id', data.id);
+ }
+ self.options.comments.push(comment);
+ self.scrollToComponent(form);
+ });
+
+ form[0].reset();
+
+ return false;
+ },
+
+ 'th mouseover': function(element) {
+ element.popover('show');
+ },
+
+ 'th mouseout': function(element) {
+ element.popover('hide');
+ },
+
+ // other functions
+
showPoll: function(poll, comments, votes) {
+ this.options.poll = poll;
+ this.options.votes = votes;
+ this.options.comments = comments;
+
this.element.html(can.view('views/vote.ejs', {
poll: poll,
comments: comments,
votes: votes
}));
this.element.show();
+ },
+
+ scrollToComponent: function(component) {
+ var position = component.position();
+ $('html, body').scrollTo(position.left, position.top);
}
});
\ No newline at end of file
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js 2013-06-12 18:00:23 UTC (rev 3822)
@@ -1,6 +1,7 @@
-/*!
+/**
* Bootstrap.js by @fat & @mdo
+* plugins: bootstrap-transition.js, bootstrap-modal.js, bootstrap-dropdown.js, bootstrap-scrollspy.js, bootstrap-tab.js, bootstrap-tooltip.js, bootstrap-popover.js, bootstrap-affix.js, bootstrap-alert.js, bootstrap-button.js, bootstrap-collapse.js, bootstrap-carousel.js, bootstrap-typeahead.js
* Copyright 2012 Twitter, Inc.
* http://www.apache.org/licenses/LICENSE-2.0.txt
*/
-!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('<div class="dropdown-backdrop"/>').insertBefore(e(this)).on("click",r),s.toggleClass("open")),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f<s.length-1&&f++,~f||(f=0),s.eq(f).focus()}};var s=e.fn.dropdown;e.fn.dropdown=function(t){return this.each(function(){var r=e(this),i=r.data("dropdown");i||r.data("dropdown",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.dropdown.Constructor=n,e.fn.dropdown.noConflict=function(){return e.fn.dropdown=s,this},e(document).on("click.dropdown.data-api",r).on("click.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("click.dropdown.data-api",t,n.prototype.toggle).on("keydown.dropdown.data-api",t+", [role=menu]",n.prototype.keydown)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=n,this.$element=e(t).delegate('[data-dismiss="modal"]',"click.dismiss.modal",e.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};t.prototype={constructor:t,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var t=this,n=e.Event("show");this.$element.trigger(n);if(this.isShown||n.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var n=e.support.transition&&t.$element.hasClass("fade");t.$element.parent().length||t.$element.appendTo(document.body),t.$element.show(),n&&t.$element[0].offsetWidth,t.$element.addClass("in").attr("aria-hidden",!1),t.enforceFocus(),n?t.$element.one(e.support.transition.end,function(){t.$element.focus().trigger("shown")}):t.$element.focus().trigger("shown")})},hide:function(t){t&&t.preventDefault();var n=this;t=e.Event("hide"),this.$element.trigger(t);if(!this.isShown||t.isDefaultPrevented())return;this.isShown=!1,this.escape(),e(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),e.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var t=this;e(document).on("focusin.modal",function(e){t.$element[0]!==e.target&&!t.$element.has(e.target).length&&t.$element.focus()})},escape:function(){var e=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(t){t.which==27&&e.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var t=this,n=setTimeout(function(){t.$element.off(e.support.transition.end),t.hideModal()},500);this.$element.one(e.support.transition.end,function(){clearTimeout(n),t.hideModal()})},hideModal:function(){var e=this;this.$element.hide(),this.backdrop(function(){e.removeBackdrop(),e.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(t){var n=this,r=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var i=e.support.transition&&r;this.$backdrop=e('<div class="modal-backdrop '+r+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e.fn[this.type].defaults,r={},i;this._options&&e.each(this._options,function(e,t){n[e]!=t&&(r[e]=t)},this),i=e(t.currentTarget)[this.type](r).data(this.type);if(!i.options.delay||!i.options.delay.show)return i.show();clearTimeout(this.timeout),i.hoverState="in",this.timeout=setTimeout(function(){i.hoverState=="in"&&i.show()},i.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
\ No newline at end of file
+!function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?a.proxy(this.$element[0].focus,this.$element[0]):a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!b)return;e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b):b()):b&&b()}};var c=a.fn.modal;a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f).one("hide",function(){c.focus()})})}(window.jQuery),!function(a){function d(){a(".dropdown-backdrop").remove(),a(b).each(function(){e(a(this)).removeClass("open")})}function e(b){var c=b.attr("data-target"),d;c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,"")),d=c&&a(c);if(!d||!d.length)d=b.parent();return d}var b="[data-toggle=dropdown]",c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),f,g;if(c.is(".disabled, :disabled"))return;return f=e(c),g=f.hasClass("open"),d(),g||("ontouchstart"in document.documentElement&&a('<div class="dropdown-backdrop"/>').insertBefore(a(this)).on("click",d),f.toggleClass("open")),c.focus(),!1},keydown:function(c){var d,f,g,h,i,j;if(!/(38|40|27)/.test(c.keyCode))return;d=a(this),c.preventDefault(),c.stopPropagation();if(d.is(".disabled, :disabled"))return;h=e(d),i=h.hasClass("open");if(!i||i&&c.keyCode==27)return c.which==27&&h.find(b).focus(),d.click();f=a("[role=menu] li:not(.divider):visible a",h);if(!f.length)return;j=f.index(f.filter(":focus")),c.keyCode==38&&j>0&&j--,c.keyCode==40&&j<f.length-1&&j++,~j||(j=0),f.eq(j).focus()}};var f=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=f,this},a(document).on("click.dropdown.data-api",d).on("click.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle).on("keydown.dropdown.data-api",b+", [role=menu]",c.prototype.keydown)}(window.jQuery),!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll-spy.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var c=a(this),d=c.data("target")||c.attr("href"),e=/^#\w/.test(d)&&a(d);return e&&e.length&&[[e.position().top+(!a.isWindow(b.$scrollElement.get(0))&&b.$scrollElement.scrollTop()),d]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu").length&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),!function(a){var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active:last a")[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(window.jQuery),!function(a){var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f,g,h,i;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,g=this.options.trigger.split(" ");for(i=g.length;i--;)h=g[i],h=="click"?this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this)):h!="manual"&&(e=h=="hover"?"mouseenter":"focus",f=h=="hover"?"mouseleave":"blur",this.$element.on(e+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f+"."+this.type,this.options.selector,a.proxy(this.leave,this)));this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,this.$element.data(),b),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a.fn[this.type].defaults,d={},e;this._options&&a.each(this._options,function(a,b){c[a]!=b&&(d[a]=b)},this),e=a(b.currentTarget)[this.type](d).data(this.type);if(!e.options.delay||!e.options.delay.show)return e.show();clearTimeout(this.timeout),e.hoverState="in",this.timeout=setTimeout(function(){e.hoverState=="in"&&e.show()},e.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!c.options.delay||!c.options.delay.hide)return c.hide();c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var b,c,d,e,f,g,h=a.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(h);if(h.isDefaultPrevented())return;b=this.tip(),this.setContent(),this.options.animation&&b.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,b[0],this.$element[0]):this.options.placement,b.detach().css({top:0,left:0,display:"block"}),this.options.container?b.appendTo(this.options.container):b.insertAfter(this.$element),c=this.getPosition(),d=b[0].offsetWidth,e=b[0].offsetHeight;switch(f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}this.applyPlacement(g,f),this.$element.trigger("shown")}},applyPlacement:function(a,b){var c=this.tip(),d=c[0].offsetWidth,e=c[0].offsetHeight,f,g,h,i;c.offset(a).addClass(b).addClass("in"),f=c[0].offsetWidth,g=c[0].offsetHeight,b=="top"&&g!=e&&(a.top=a.top+e-g,i=!0),b=="bottom"||b=="top"?(h=0,a.left<0&&(h=a.left*-2,a.left=0,c.offset(a),f=c[0].offsetWidth,g=c[0].offsetHeight),this.replaceArrow(h-d+f,f,"left")):this.replaceArrow(g-e,g,"top"),i&&c.offset(a)},replaceArrow:function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function e(){var b=setTimeout(function(){c.off(a.support.transition.end).detach()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.detach()})}var b=this,c=this.tip(),d=a.Event("hide");this.$element.trigger(d);if(d.isDefaultPrevented())return;return c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?e():c.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var b=this.$element[0];return a.extend({},typeof b.getBoundingClientRect=="function"?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(b){var c=b?a(b.currentTarget)[this.type](this._options).data(this.type):this;c.tip().hasClass("in")?c.hide():c.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(window.jQuery),!function(a){var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=(typeof c.content=="function"?c.content.call(b[0]):c.content)||b.attr("data-content"),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(window.jQuery),!function(a){var b=function(b,c){this.options=a.extend({},a.fn.affix.defaults,c),this.$window=a(window).on("scroll.affix.data-api",a.proxy(this.checkPosition,this)).on("click.affix.data-api",a.proxy(function(){setTimeout(a.proxy(this.checkPosition,this),1)},this)),this.$element=a(b),this.checkPosition()};b.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var b=a(document).height(),c=this.$window.scrollTop(),d=this.$element.offset(),e=this.options.offset,f=e.bottom,g=e.top,h="affix affix-top affix-bottom",i;typeof e!="object"&&(f=g=e),typeof g=="function"&&(g=e.top()),typeof f=="function"&&(f=e.bottom()),i=this.unpin!=null&&c+this.unpin<=d.top?!1:f!=null&&d.top+this.$element.height()>=b-f?"bottom":g!=null&&c<=g?"top":!1;if(this.affixed===i)return;this.affixed=i,this.unpin=i=="bottom"?d.top-c:null,this.$element.removeClass(h).addClass("affix"+(i?"-"+i:""))};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("affix"),f=typeof c=="object"&&c;e||d.data("affix",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.defaults={offset:0},a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(window.jQuery),!function(a){var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.alert.data-api",b,c.prototype.close)}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning||this.$element.hasClass("in"))return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),a.support.transition&&this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning||!this.$element.hasClass("in"))return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=a.extend({},a.fn.collapse.defaults,d.data(),typeof c=="object"&&c);e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();c[a(e).hasClass("in")?"addClass":"removeClass"]("collapsed"),a(e).collapse(f)})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(b){var c=this.getActiveIndex(),d=this;if(b>this.$items.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){d.to(b)}):c==b?this.pause().cycle():this.slide(b>c?"next":"prev",a(this.$items[b]))},pause:function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j;this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h](),j=a.Event("slide",{relatedTarget:e[0],direction:g});if(e.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")}));if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c),g=typeof c=="string"?c:f.slide;e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),c.data()),g;e.carousel(f),(g=c.attr("data-slide-to"))&&e.data("carousel").pause().to(g).cycle(),b.preventDefault()})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=a(this.options.menu),this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:b.top+b.height,left:b.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(c=a.isFunction(this.source)?this.source(this.query,a.proxy(this.process,this)):this.source,c?this.process(c):this)},process:function(b){var c=this;return b=a.grep(b,function(a){return c.matcher(a)}),b=this.sorter(b),b.length?this.render(b.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this))},eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b=typeof this.$element[a]=="function"),b},move:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:a.preventDefault(),this.prev();break;case 40:a.preventDefault(),this.next()}a.stopPropagation()},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.move(b)},keypress:function(a){if(this.suppressKeyPressRepeat)return;this.move(a)},keyup:function(a){switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},focus:function(a){this.focused=!0},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(a){a.stopPropagation(),a.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var c=a.fn.typeahead;a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;c.typeahead(c.data())})}(window.jQuery)
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/date.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/date.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/date.js 2013-06-12 18:00:23 UTC (rev 3822)
@@ -0,0 +1,104 @@
+/**
+ * Version: 1.0 Alpha-1
+ * Build Date: 13-Nov-2007
+ * Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/) All rights reserved.
+ * License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
+ */
+Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
+Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
+return-1;};Date.getDayNumberFromName=function(name){var n=Date.CultureInfo.dayNames,m=Date.CultureInfo.abbreviatedDayNames,o=Date.CultureInfo.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
+return-1;};Date.isLeapYear=function(year){return(((year%4===0)&&(year%100!==0))||(year%400===0));};Date.getDaysInMonth=function(year,month){return[31,(Date.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};Date.getTimezoneOffset=function(s,dst){return(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST[s.toUpperCase()]:Date.CultureInfo.abbreviatedTimeZoneStandard[s.toUpperCase()];};Date.getTimezoneAbbreviation=function(offset,dst){var n=(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST:Date.CultureInfo.abbreviatedTimeZoneStandard,p;for(p in n){if(n[p]===offset){return p;}}
+return null;};Date.prototype.clone=function(){return new Date(this.getTime());};Date.prototype.compareTo=function(date){if(isNaN(this)){throw new Error(this);}
+if(date instanceof Date&&!isNaN(date)){return(this>date)?1:(this<date)?-1:0;}else{throw new TypeError(date);}};Date.prototype.equals=function(date){return(this.compareTo(date)===0);};Date.prototype.between=function(start,end){var t=this.getTime();return t>=start.getTime()&&t<=end.getTime();};Date.prototype.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};Date.prototype.addSeconds=function(value){return this.addMilliseconds(value*1000);};Date.prototype.addMinutes=function(value){return this.addMilliseconds(value*60000);};Date.prototype.addHours=function(value){return this.addMilliseconds(value*3600000);};Date.prototype.addDays=function(value){return this.addMilliseconds(value*86400000);};Date.prototype.addWeeks=function(value){return this.addMilliseconds(value*604800000);};Date.prototype.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,this.getDaysInMonth()));return this;};Date.prototype.addYears=function(value){return this.addMonths(value*12);};Date.prototype.add=function(config){if(typeof config=="number"){this._orient=config;return this;}
+var x=config;if(x.millisecond||x.milliseconds){this.addMilliseconds(x.millisecond||x.milliseconds);}
+if(x.second||x.seconds){this.addSeconds(x.second||x.seconds);}
+if(x.minute||x.minutes){this.addMinutes(x.minute||x.minutes);}
+if(x.hour||x.hours){this.addHours(x.hour||x.hours);}
+if(x.month||x.months){this.addMonths(x.month||x.months);}
+if(x.year||x.years){this.addYears(x.year||x.years);}
+if(x.day||x.days){this.addDays(x.day||x.days);}
+return this;};Date._validate=function(value,min,max,name){if(typeof value!="number"){throw new TypeError(value+" is not a Number.");}else if(value<min||value>max){throw new RangeError(value+" is not a valid value for "+name+".");}
+return true;};Date.validateMillisecond=function(n){return Date._validate(n,0,999,"milliseconds");};Date.validateSecond=function(n){return Date._validate(n,0,59,"seconds");};Date.validateMinute=function(n){return Date._validate(n,0,59,"minutes");};Date.validateHour=function(n){return Date._validate(n,0,23,"hours");};Date.validateDay=function(n,year,month){return Date._validate(n,1,Date.getDaysInMonth(year,month),"days");};Date.validateMonth=function(n){return Date._validate(n,0,11,"months");};Date.validateYear=function(n){return Date._validate(n,1,9999,"seconds");};Date.prototype.set=function(config){var x=config;if(!x.millisecond&&x.millisecond!==0){x.millisecond=-1;}
+if(!x.second&&x.second!==0){x.second=-1;}
+if(!x.minute&&x.minute!==0){x.minute=-1;}
+if(!x.hour&&x.hour!==0){x.hour=-1;}
+if(!x.day&&x.day!==0){x.day=-1;}
+if(!x.month&&x.month!==0){x.month=-1;}
+if(!x.year&&x.year!==0){x.year=-1;}
+if(x.millisecond!=-1&&Date.validateMillisecond(x.millisecond)){this.addMilliseconds(x.millisecond-this.getMilliseconds());}
+if(x.second!=-1&&Date.validateSecond(x.second)){this.addSeconds(x.second-this.getSeconds());}
+if(x.minute!=-1&&Date.validateMinute(x.minute)){this.addMinutes(x.minute-this.getMinutes());}
+if(x.hour!=-1&&Date.validateHour(x.hour)){this.addHours(x.hour-this.getHours());}
+if(x.month!==-1&&Date.validateMonth(x.month)){this.addMonths(x.month-this.getMonth());}
+if(x.year!=-1&&Date.validateYear(x.year)){this.addYears(x.year-this.getFullYear());}
+if(x.day!=-1&&Date.validateDay(x.day,this.getFullYear(),this.getMonth())){this.addDays(x.day-this.getDate());}
+if(x.timezone){this.setTimezone(x.timezone);}
+if(x.timezoneOffset){this.setTimezoneOffset(x.timezoneOffset);}
+return this;};Date.prototype.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};Date.prototype.isLeapYear=function(){var y=this.getFullYear();return(((y%4===0)&&(y%100!==0))||(y%400===0));};Date.prototype.isWeekday=function(){return!(this.is().sat()||this.is().sun());};Date.prototype.getDaysInMonth=function(){return Date.getDaysInMonth(this.getFullYear(),this.getMonth());};Date.prototype.moveToFirstDayOfMonth=function(){return this.set({day:1});};Date.prototype.moveToLastDayOfMonth=function(){return this.set({day:this.getDaysInMonth()});};Date.prototype.moveToDayOfWeek=function(day,orient){var diff=(day-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};Date.prototype.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};Date.prototype.getDayOfYear=function(){return Math.floor((this-new Date(this.getFullYear(),0,1))/86400000);};Date.prototype.getWeekOfYear=function(firstDayOfWeek){var y=this.getFullYear(),m=this.getMonth(),d=this.getDate();var dow=firstDayOfWeek||Date.CultureInfo.firstDayOfWeek;var offset=7+1-new Date(y,0,1).getDay();if(offset==8){offset=1;}
+var daynum=((Date.UTC(y,m,d,0,0,0)-Date.UTC(y,0,1,0,0,0))/86400000)+1;var w=Math.floor((daynum-offset+7)/7);if(w===dow){y--;var prevOffset=7+1-new Date(y,0,1).getDay();if(prevOffset==2||prevOffset==8){w=53;}else{w=52;}}
+return w;};Date.prototype.isDST=function(){console.log('isDST');return this.toString().match(/(E|C|M|P)(S|D)T/)[2]=="D";};Date.prototype.getTimezone=function(){return Date.getTimezoneAbbreviation(this.getUTCOffset,this.isDST());};Date.prototype.setTimezoneOffset=function(s){var here=this.getTimezoneOffset(),there=Number(s)*-6/10;this.addMinutes(there-here);return this;};Date.prototype.setTimezone=function(s){return this.setTimezoneOffset(Date.getTimezoneOffset(s));};Date.prototype.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r[0]+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};Date.prototype.getDayName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedDayNames[this.getDay()]:Date.CultureInfo.dayNames[this.getDay()];};Date.prototype.getMonthName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedMonthNames[this.getMonth()]:Date.CultureInfo.monthNames[this.getMonth()];};Date.prototype._toString=Date.prototype.toString;Date.prototype.toString=function(format){var self=this;var p=function p(s){return(s.toString().length==1)?"0"+s:s;};return format?format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g,function(format){switch(format){case"hh":return p(self.getHours()<13?self.getHours():(self.getHours()-12));case"h":return self.getHours()<13?self.getHours():(self.getHours()-12);case"HH":return p(self.getHours());case"H":return self.getHours();case"mm":return p(self.getMinutes());case"m":return self.getMinutes();case"ss":return p(self.getSeconds());case"s":return self.getSeconds();case"yyyy":return self.getFullYear();case"yy":return self.getFullYear().toString().substring(2,4);case"dddd":return self.getDayName();case"ddd":return self.getDayName(true);case"dd":return p(self.getDate());case"d":return self.getDate().toString();case"MMMM":return self.getMonthName();case"MMM":return self.getMonthName(true);case"MM":return p((self.getMonth()+1));case"M":return self.getMonth()+1;case"t":return self.getHours()<12?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case"tt":return self.getHours()<12?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;case"zzz":case"zz":case"z":return"";}}):this._toString();};
+Date.now=function(){return new Date();};Date.today=function(){return Date.now().clearTime();};Date.prototype._orient=+1;Date.prototype.next=function(){this._orient=+1;return this;};Date.prototype.last=Date.prototype.prev=Date.prototype.previous=function(){this._orient=-1;return this;};Date.prototype._is=false;Date.prototype.is=function(){this._is=true;return this;};Number.prototype._dateElement="day";Number.prototype.fromNow=function(){var c={};c[this._dateElement]=this;return Date.now().add(c);};Number.prototype.ago=function(){var c={};c[this._dateElement]=this*-1;return Date.now().add(c);};(function(){var $D=Date.prototype,$N=Number.prototype;var dx=("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),mx=("january february march april may june july august september october november december").split(/\s/),px=("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),de;var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}
+return this.moveToDayOfWeek(n,this._orient);};};for(var i=0;i<dx.length;i++){$D[dx[i]]=$D[dx[i].substring(0,3)]=df(i);}
+var mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}
+return this.moveToMonth(n,this._orient);};};for(var j=0;j<mx.length;j++){$D[mx[j]]=$D[mx[j].substring(0,3)]=mf(j);}
+var ef=function(j){return function(){if(j.substring(j.length-1)!="s"){j+="s";}
+return this["add"+j](this._orient);};};var nf=function(n){return function(){this._dateElement=n;return this;};};for(var k=0;k<px.length;k++){de=px[k].toLowerCase();$D[de]=$D[de+"s"]=ef(px[k]);$N[de]=$N[de+"s"]=nf(de);}}());Date.prototype.toJSONString=function(){return this.toString("yyyy-MM-ddThh:mm:ssZ");};Date.prototype.toShortDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortDatePattern);};Date.prototype.toLongDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.longDatePattern);};Date.prototype.toShortTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortTimePattern);};Date.prototype.toLongTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.longTimePattern);};Date.prototype.getOrdinal=function(){switch(this.getDate()){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};
+(function(){Date.Parsing={Exception:function(s){this.message="Parse error at '"+s.substring(0,10)+" ...'";}};var $P=Date.Parsing;var _=$P.Operators={rtoken:function(r){return function(s){var mx=s.match(r);if(mx){return([mx[0],s.substring(mx[0].length)]);}else{throw new $P.Exception(s);}};},token:function(s){return function(s){return _.rtoken(new RegExp("^\s*"+s+"\s*"))(s);};},stoken:function(s){return _.rtoken(new RegExp("^"+s));},until:function(p){return function(s){var qx=[],rx=null;while(s.length){try{rx=p.call(this,s);}catch(e){qx.push(rx[0]);s=rx[1];continue;}
+break;}
+return[qx,s];};},many:function(p){return function(s){var rx=[],r=null;while(s.length){try{r=p.call(this,s);}catch(e){return[rx,s];}
+rx.push(r[0]);s=r[1];}
+return[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}
+return[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}
+throw new $P.Exception(s);};},ignore:function(p){return p?function(s){var r=null;r=p.call(this,s);return[null,r[1]];}:null;},product:function(){var px=arguments[0],qx=Array.prototype.slice.call(arguments,1),rx=[];for(var i=0;i<px.length;i++){rx.push(_.each(px[i],qx));}
+return rx;},cache:function(rule){var cache={},r=null;return function(s){try{r=cache[s]=(cache[s]||rule.call(this,s));}catch(e){r=cache[s]=e;}
+if(r instanceof $P.Exception){throw r;}else{return r;}};},any:function(){var px=arguments;return function(s){var r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
+try{r=(px[i].call(this,s));}catch(e){r=null;}
+if(r){return r;}}
+throw new $P.Exception(s);};},each:function(){var px=arguments;return function(s){var rx=[],r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
+try{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}
+rx.push(r[0]);s=r[1];}
+return[rx,s];};},all:function(){var px=arguments,_=_;return _.each(_.optional(px));},sequence:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;if(px.length==1){return px[0];}
+return function(s){var r=null,q=null;var rx=[];for(var i=0;i<px.length;i++){try{r=px[i].call(this,s);}catch(e){break;}
+rx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}
+s=q[1];}
+if(!r){throw new $P.Exception(s);}
+if(q){throw new $P.Exception(q[1]);}
+if(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}
+return[rx,(r?r[1]:s)];};},between:function(d1,p,d2){d2=d2||d1;var _fn=_.each(_.ignore(d1),p,_.ignore(d2));return function(s){var rx=_fn.call(this,s);return[[rx[0][0],r[0][2]],rx[1]];};},list:function(p,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return(p instanceof Array?_.each(_.product(p.slice(0,-1),_.ignore(d)),p.slice(-1),_.ignore(c)):_.each(_.many(_.each(p,_.ignore(d))),px,_.ignore(c)));},set:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return function(s){var r=null,p=null,q=null,rx=null,best=[[],s],last=false;for(var i=0;i<px.length;i++){q=null;p=null;r=null;last=(px.length==1);try{r=px[i].call(this,s);}catch(e){continue;}
+rx=[[r[0]],r[1]];if(r[1].length>0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;}
+if(!last&&q[1].length===0){last=true;}
+if(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}
+p=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}
+if(rx[1].length<best[1].length){best=rx;}
+if(best[1].length===0){break;}}
+if(best[0].length===0){return best;}
+if(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}
+best[1]=q[1];}
+return best;};},forward:function(gr,fname){return function(s){return gr[fname].call(this,s);};},replace:function(rule,repl){return function(s){var r=rule.call(this,s);return[repl,r[1]];};},process:function(rule,fn){return function(s){var r=rule.call(this,s);return[fn.call(this,r[0]),r[1]];};},min:function(min,rule){return function(s){var rx=rule.call(this,s);if(rx[0].length<min){throw new $P.Exception(s);}
+return rx;};}};var _generator=function(op){return function(){var args=null,rx=[];if(arguments.length>1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];}
+if(args){for(var i=0,px=args.shift();i<px.length;i++){args.unshift(px[i]);rx.push(op.apply(null,args));args.shift();return rx;}}else{return op.apply(null,arguments);}};};var gx="optional not ignore cache".split(/\s/);for(var i=0;i<gx.length;i++){_[gx[i]]=_generator(_[gx[i]]);}
+var _vector=function(op){return function(){if(arguments[0]instanceof Array){return op.apply(null,arguments[0]);}else{return op.apply(null,arguments);}};};var vx="each any all".split(/\s/);for(var j=0;j<vx.length;j++){_[vx[j]]=_vector(_[vx[j]]);}}());(function(){var flattenAndCompact=function(ax){var rx=[];for(var i=0;i<ax.length;i++){if(ax[i]instanceof Array){rx=rx.concat(flattenAndCompact(ax[i]));}else{if(ax[i]){rx.push(ax[i]);}}}
+return rx;};Date.Grammar={};Date.Translator={hour:function(s){return function(){this.hour=Number(s);};},minute:function(s){return function(){this.minute=Number(s);};},second:function(s){return function(){this.second=Number(s);};},meridian:function(s){return function(){this.meridian=s.slice(0,1).toLowerCase();};},timezone:function(s){return function(){var n=s.replace(/[^\d\+\-]/g,"");if(n.length){this.timezoneOffset=Number(n);}else{this.timezone=s.toLowerCase();}};},day:function(x){var s=x[0];return function(){this.day=Number(s.match(/\d+/)[0]);};},month:function(s){return function(){this.month=((s.length==3)?Date.getMonthNumberFromName(s):(Number(s)-1));};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<Date.CultureInfo.twoDigitYearMax)?2000:1900)));};},rday:function(s){return function(){switch(s){case"yesterday":this.days=-1;break;case"tomorrow":this.days=1;break;case"today":this.days=0;break;case"now":this.days=0;this.now=true;break;}};},finishExact:function(x){x=(x instanceof Array)?x:[x];var now=new Date();this.year=now.getFullYear();this.month=now.getMonth();this.day=1;this.hour=0;this.minute=0;this.second=0;for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}
+this.hour=(this.meridian=="p"&&this.hour<13)?this.hour+12:this.hour;if(this.day>Date.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");}
+var r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});}
+return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}
+for(var i=0;i<x.length;i++){if(typeof x[i]=="function"){x[i].call(this);}}
+if(this.now){return new Date();}
+var today=Date.today();var method=null;var expression=!!(this.days!=null||this.orient||this.operator);if(expression){var gap,mod,orient;orient=((this.orient=="past"||this.operator=="subtract")?-1:1);if(this.weekday){this.unit="day";gap=(Date.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}
+if(this.month){this.unit="month";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}
+if(!this.unit){this.unit="day";}
+if(this[this.unit+"s"]==null||this.operator!=null){if(!this.value){this.value=1;}
+if(this.unit=="week"){this.unit="day";this.value=this.value*7;}
+this[this.unit+"s"]=this.value*orient;}
+return today.add(this);}else{if(this.meridian&&this.hour){this.hour=(this.hour<13&&this.meridian=="p")?this.hour+12:this.hour;}
+if(this.weekday&&!this.day){this.day=(today.addDays((Date.getDayNumberFromName(this.weekday)-today.getDay()))).getDate();}
+if(this.month&&!this.day){this.day=1;}
+return today.set(this);}}};var _=Date.Parsing.Operators,g=Date.Grammar,t=Date.Translator,_fn;g.datePartDelimiter=_.rtoken(/^([\s\-\.\,\/\x27]+)/);g.timePartDelimiter=_.stoken(":");g.whiteSpace=_.rtoken(/^\s*/);g.generalDelimiter=_.rtoken(/^(([\s\,]|at|on)+)/);var _C={};g.ctoken=function(keys){var fn=_C[keys];if(!fn){var c=Date.CultureInfo.regexPatterns;var kx=keys.split(/\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}
+fn=_C[keys]=_.any.apply(null,px);}
+return fn;};g.ctoken2=function(key){return _.rtoken(Date.CultureInfo.regexPatterns[key]);};g.h=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/),t.hour));g.hh=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/),t.hour));g.H=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/),t.hour));g.HH=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/),t.hour));g.m=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.minute));g.mm=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.minute));g.s=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.second));g.ss=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.second));g.hms=_.cache(_.sequence([g.H,g.mm,g.ss],g.timePartDelimiter));g.t=_.cache(_.process(g.ctoken2("shortMeridian"),t.meridian));g.tt=_.cache(_.process(g.ctoken2("longMeridian"),t.meridian));g.z=_.cache(_.process(_.rtoken(/^(\+|\-)?\s*\d\d\d\d?/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^(\+|\-)\s*\d\d\d\d/),t.timezone));g.zzz=_.cache(_.process(g.ctoken2("timezone"),t.timezone));g.timeSuffix=_.each(_.ignore(g.whiteSpace),_.set([g.tt,g.zzz]));g.time=_.each(_.optional(_.ignore(_.stoken("T"))),g.hms,g.timeSuffix);g.d=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.dd=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.ddd=g.dddd=_.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),function(s){return function(){this.weekday=s;};}));g.M=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/),t.month));g.MM=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/),t.month));g.MMM=g.MMMM=_.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"),t.month));g.y=_.cache(_.process(_.rtoken(/^(\d\d?)/),t.year));g.yy=_.cache(_.process(_.rtoken(/^(\d\d)/),t.year));g.yyy=_.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/),t.year));g.yyyy=_.cache(_.process(_.rtoken(/^(\d\d\d\d)/),t.year));_fn=function(){return _.each(_.any.apply(null,arguments),_.not(g.ctoken2("timeContext")));};g.day=_fn(g.d,g.dd);g.month=_fn(g.M,g.MMM);g.year=_fn(g.yyyy,g.yy);g.orientation=_.process(g.ctoken("past future"),function(s){return function(){this.orient=s;};});g.operator=_.process(g.ctoken("add subtract"),function(s){return function(){this.operator=s;};});g.rday=_.process(g.ctoken("yesterday tomorrow today now"),t.rday);g.unit=_.process(g.ctoken("minute hour day week month year"),function(s){return function(){this.unit=s;};});g.value=_.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),function(s){return function(){this.value=s.replace(/\D/g,"");};});g.expression=_.set([g.rday,g.operator,g.value,g.unit,g.orientation,g.ddd,g.MMM]);_fn=function(){return _.set(arguments,g.datePartDelimiter);};g.mdy=_fn(g.ddd,g.month,g.day,g.year);g.ymd=_fn(g.ddd,g.year,g.month,g.day);g.dmy=_fn(g.ddd,g.day,g.month,g.year);g.date=function(s){return((g[Date.CultureInfo.dateElementOrder]||g.mdy).call(this,s));};g.format=_.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),function(fmt){if(g[fmt]){return g[fmt];}else{throw Date.Parsing.Exception(fmt);}}),_.process(_.rtoken(/^[^dMyhHmstz]+/),function(s){return _.ignore(_.stoken(s));}))),function(rules){return _.process(_.each.apply(null,rules),t.finishExact);});var _F={};var _get=function(f){return _F[f]=(_F[f]||g.format(f)[0]);};g.formats=function(fx){if(fx instanceof Array){var rx=[];for(var i=0;i<fx.length;i++){rx.push(_get(fx[i]));}
+return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["yyyy-MM-ddTHH:mm:ss","ddd, MMM dd, yyyy H:mm:ss tt","ddd MMM d yyyy HH:mm:ss zzz","d"]);g._start=_.process(_.set([g.date,g.time,g.expression],g.generalDelimiter,g.whiteSpace),t.finish);g.start=function(s){try{var r=g._formats.call({},s);if(r[1].length===0){return r;}}catch(e){}
+return g._start.call({},s);};}());Date._parse=Date.parse;Date.parse=function(s){var r=null;if(!s){return null;}
+try{r=Date.Grammar.start.call({},s);}catch(e){return null;}
+return((r[1].length===0)?r[0]:null);};Date.getParseFunction=function(fx){var fn=Date.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
+return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/jquery.scrollto.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/jquery.scrollto.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/jquery.scrollto.js 2013-06-12 18:00:23 UTC (rev 3822)
@@ -0,0 +1,32 @@
+/*!
+ * jquery.scrollto.js 0.0.1 - https://github.com/yckart/jquery.scrollto.js
+ * Scroll smooth to any element in your DOM.
+ *
+ * Copyright (c) 2012 Yannick Albert (http://yckart.com)
+ * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
+ * 2013/02/17
+ **/
+$.scrollTo = $.fn.scrollTo = function(x, y, options){
+ if (!(this instanceof $)) return $.fn.scrollTo.apply($('html, body'), arguments);
+
+ options = $.extend({}, {
+ gap: {
+ x: 0,
+ y: 0
+ },
+ animation: {
+ easing: 'swing',
+ duration: 600,
+ complete: $.noop,
+ step: $.noop
+ }
+ }, options);
+
+ return this.each(function(){
+ var elem = $(this);
+ elem.stop().animate({
+ scrollLeft: !isNaN(Number(x)) ? x : $(y).offset().left + options.gap.x,
+ scrollTop: !isNaN(Number(y)) ? y : $(y).offset().top + options.gap.y
+ }, options.animation);
+ });
+};
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js 2013-06-12 18:00:23 UTC (rev 3822)
@@ -9,21 +9,21 @@
var COMMENTS = [
[{
text: "This is the end of the world",
- author: "Maya",
- postDate: "21/12/12"
+ author: "Mayan guy",
+ postDate: 123456789123456789
},{
text: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.",
author: "Sacha",
- postDate: "03/12/11"
+ postDate: 999999999999999
}],
[{
text: "azztyuiopfghj",
author: "yyy",
- postDate: ""
+ postDate: 6666666666666
},{
text: "aqwxszedv",
author: "sdsqdqsdqsdqdqsd",
- postDate: ""
+ postDate: 66666666666666
}]
];
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js 2013-06-12 18:00:23 UTC (rev 3822)
@@ -6,15 +6,17 @@
destroy : "DELETE /polls/{id}"
},{});
+console.log("load polls")
var POLLS = [
{
id: 1,
title: 'Titre 1',
description: "Desc 1",
creatorName: "Kevin",
+ closed: true,
choices: [
{
- id: 1,
+ id: 1,
name: "Choix 1",
description: "desc du choix 1"
},
@@ -30,6 +32,11 @@
title: 'Lorem Ipsum',
description: "description très longue, mais vraiment très longue pour qu'elle passe en dessous. Enfin j'espère que ce sera assez long",
creatorName: "moi",
+ choiceAddAllowed: true,
+ beginChoiceDate: new Date().getTime(),
+ endChoiceDate: new Date().addMinutes(1).getTime(),
+ beginDate: new Date().addDays(-5).getTime(),
+ endDate: new Date().addDays(5).getTime(),
choices: [
{
id: 3,
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs 2013-06-12 18:00:23 UTC (rev 3822)
@@ -1,4 +1,2 @@
-<ul>
- <li><%== can.route.link('Sondage', { type: 'poll', action: 'edit' }) %></li>
- <li><%== can.route.link('Autre', { type: 'other', action: 'donothing' }) %></li>
-</ul>
\ No newline at end of file
+<li><%== can.route.link('Sondage', { type: 'poll', action: 'edit' }) %></li>
+<li><%== can.route.link('Autre', { type: 'other', action: 'donothing' }) %></li>
\ No newline at end of file
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs 2013-06-12 18:00:23 UTC (rev 3822)
@@ -3,6 +3,7 @@
<div class="control-group">
<label class="control-label" for='pollSummaryLink'>Lien pour participer</label>
<input type='url' id='pollSummaryLink' value="<%== window.location.href.split('#')[0] + can.route.url({ type: 'poll', action: 'vote', id: poll.id }) %>"/>
+ <%== can.route.link('<i class="icon-link bigger link"></i>', {type: 'poll', action: 'vote', id: poll.id}) %>
</div>
<div class='row-fluid'>
Modified: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs 2013-06-12 08:27:48 UTC (rev 3821)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs 2013-06-12 18:00:23 UTC (rev 3822)
@@ -1,21 +1,74 @@
<div class="page-header">
- <h1><%= poll.title %></h1>
- <p>Sondage lancé par <%= poll.creatorName %>
- | <i class='icon-user'></i> 0
- | <i class='icon-comment'></i> 0
- | <i class='icon-time'></i> il y a 2 minutes</p>
- <p><%= poll.description %></p>
+
+ <h1><%= poll.attr('title') %></h1>
+
+ <p>
+ Sondage lancé par <%= poll.attr('creatorName') %>
+ <!-- number of votes -->
+ | <a id="voteSummary" class='link'><i class='icon-user'></i> <%= votes.attr('length') %></a>
+ <!-- number of comments-->
+ | <a id="commentSummary" class='link'><i class='icon-comment'></i> <%= comments.attr('length') %></a>
+ <!-- poll dates -->
+ <% if (poll.attr('beginDate') && poll.attr('endDate')) { %>
+ | <i class='icon-time'></i> du <%= new Date(poll.attr('beginDate')).toString("dd/MM/yyyy") %> au <%= new Date(poll.attr('endDate')).toString("dd/MM/yyyy") %>
+ <% } else if (poll.attr('beginDate')) { %>
+ | <i class='icon-time'></i> à partir du <%= new Date(poll.attr('beginDate')).toString("dd/MM/yyyy") %>
+ <% } else if (poll.attr('endDate')) { %>
+ | <i class='icon-time'></i> jusqu'au <%= new Date(poll.attr('endDate')).toString("dd/MM/yyyy") %>
+ <% } %>
+ </p>
+
+ <p><%= poll.attr('description') %></p>
+
</div>
-<form>
+<!-- alert if the poll is closed -->
+<% if (poll.attr('closed')) { %>
+<div class="alert fade in">
+ <button type="button" class="close" data-dismiss="alert">×</button>
+ <strong>Ce sondage est clos.</strong> Vous ne pouvez plus voter.
+</div>
+<% } %>
- <table class="table table-bordered table-striped">
+<!-- list of the choices -->
+<div id='choicesSummary'>
+
+ <h3>Propositions</h3>
+
+ <ol>
+ <% poll.choices.each(function(choice) { %>
+ <li><strong><%= choice.attr('name') %></strong> : <%= choice.attr('description') %></li>
+ <% }); %>
+ </ol>
+ <% var now = new Date().getTime();
+ if (poll.attr('choiceAddAllowed') && poll.attr('beginChoiceDate') <= now && poll.attr('endChoiceDate') > now) {%>
+
+ <!-- link to show/hide the new choice form -->
+ <button class="collapsed btn btn-link" data-toggle="collapse" data-target="#addChoiceForm">
+ Ajouter un choix <i class="icon-collapse"></i>
+ </button>
+
+ <!-- form to add a new choice to the poll -->
+ <form id="addChoiceForm" class="collapse">
+ <input type="text" name="name" placeholder="Nom"/>
+ <textarea name="description" placeholder="Description"></textarea>
+ <button type="submit" class="btn btn-primary">Valider</button>
+ </form>
+<% } %>
+</div>
+
+<!-- table of the votes -->
+<form id="voteForm">
+
+ <table id="voteTable" class="table table-bordered table-striped">
<caption>Votes</caption>
<thead>
<tr>
<th>Votant</th>
<% poll.choices.each(function(choice) { %>
- <th><%= choice.attr('name') %></th>
+ <th data-container='body' data-placement='top' title='<%= choice.attr("description") %>'>
+ <%= choice.attr('name') %>
+ </th>
<% }); %>
</tr>
</thead>
@@ -23,31 +76,66 @@
<% votes.each(function(vote) { %>
<tr>
<td><%= vote.attr('voterListMember.name') %></td>
- <% vote.voteToChoices.each(function(choice) { %>
- <td><%= choice.attr('voteValue') %></td>
- <% }); %>
+ <%
+ poll.choices.each(function(choice, i) {
+ var voteChoice = vote.voteToChoices.attr(i);
+ if (voteChoice == null) {
+ %>
+ <td class='choice voteBeforeChoice'></td>
+ <% } else { %>
+ <td class='choice <%= voteChoice.attr("voteValue") ? "selected" : "notSelected" %>'>
+ <%= voteChoice.attr("voteValue") ? "OK" : "" %>
+ </td>
+ <%
+ }
+ });
+ %>
</tr>
- <% }); %>
- <tr>
- <td><input type='text'/></td>
- <% poll.choices.each(function(choice) { %>
- <td><input type='checkbox'/></td>
- <% }); %>
- </tr>
+ <%
+ });
+ if (!poll.attr('closed')) {
+ %>
+ <tr>
+ <td><input name="userName" type='text'/></td>
+ <%poll.choices.each(function(choice, i) { %>
+ <td><input name="<%= i %>" type='checkbox'/></td>
+ <% }); %>
+ </tr>
+ <% } %>
</tbody>
</table>
- <div class="form-actions">
- <button class="btn btn-primary">Voter</button>
- </div>
+ <% if (!poll.attr('closed')) { %>
+ <div class="form-actions">
+ <button type="submit" id="voteButton" class="btn btn-primary">Voter</button>
+ </div>
+ <% } %>
</form>
-<div>
-<h2>Commentaires</h2>
-<% comments.each(function(comment) { %>
+<!-- Comments -->
+<div id="comments">
+ <h2>Commentaires</h2>
-<p><strong><%= comment.attr('author') %></strong> : <%= comment.attr('text') %></p>
+ <button class="collapsed btn btn-link" data-toggle="collapse" data-target="#addCommentForm">
+ Ajouter un commentaire <i class="icon-collapse"></i>
+ </button>
-<% }); %>
+ <form id="addCommentForm" class="collapse">
+ <input type="text" name="author" placeholder="Votre nom"/>
+ <textarea name="message" placeholder="Entrez votre message"></textarea>
+ <button type="submit" class="btn btn-primary">Valider</button>
+ </form>
+
+ <dl>
+ <% comments.each(function(comment) { %>
+
+ <dt><%= comment.attr('author') %> - <em><%= new Date(comment.attr('postDate')).toString("dd/MM/yyyy hh:mm") %></em></dt>
+ <dd>
+ <%= comment.attr('text') %>
+ </dd>
+ </div>
+
+ <% }); %>
+ </dl>
</div>
\ No newline at end of file
1
0
12 Jun '13
Author: tchemit
Date: 2013-06-12 10:27:48 +0200 (Wed, 12 Jun 2013)
New Revision: 3821
Url: http://chorem.org/projects/pollen/repository/revisions/3821
Log:
implements nice id generator
Added:
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenEntityIdFactory.java
Removed:
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaEntityIdFactoryIfNotEmpty.java
Modified:
branches/pollen-2.0/pollen-persistence/pom.xml
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaPollenPersistenceContext.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java
branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties
branches/pollen-2.0/pollen-persistence/src/test/java/org/chorem/pollen/persistence/entity/PollenEntitiesTest.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java
branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml
branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java
branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java
branches/pollen-2.0/pom.xml
Modified: branches/pollen-2.0/pollen-persistence/pom.xml
===================================================================
--- branches/pollen-2.0/pollen-persistence/pom.xml 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-persistence/pom.xml 2013-06-12 08:27:48 UTC (rev 3821)
@@ -41,6 +41,10 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ </dependency>
<!--dependency>
<groupId>org.nuiton</groupId>
<artifactId>nuiton-utils</artifactId>
Deleted: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaEntityIdFactoryIfNotEmpty.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaEntityIdFactoryIfNotEmpty.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaEntityIdFactoryIfNotEmpty.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -1,48 +0,0 @@
-package org.chorem.pollen.persistence;
-
-/*
- * #%L
- * Pollen :: Persistence
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2009 - 2013 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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 Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * #L%
- */
-
-import org.apache.commons.lang3.StringUtils;
-import org.nuiton.jpa.api.DefaultJpaEntityIdFactory;
-import org.nuiton.jpa.api.JpaEntity;
-
-/**
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-public class JpaEntityIdFactoryIfNotEmpty extends DefaultJpaEntityIdFactory {
-
- @Override
- public String newId(JpaEntity entity) {
- String result;
- boolean notEmpty = StringUtils.isNotEmpty(entity.getId());
-
- if (notEmpty) {
- result = entity.getId();
- } else {
- result = super.newId(entity);
- }
- return result;
- }
-}
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaPollenPersistenceContext.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaPollenPersistenceContext.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaPollenPersistenceContext.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -38,7 +38,7 @@
public class JpaPollenPersistenceContext extends AbstractJpaPollenPersistenceContext {
public JpaPollenPersistenceContext(EntityManager entityManager) {
- super(entityManager);
+ this(new PollenEntityIdFactory(), entityManager);
}
public JpaPollenPersistenceContext(JpaEntityIdFactory idGenerator,
Added: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenEntityIdFactory.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenEntityIdFactory.java (rev 0)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenEntityIdFactory.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -0,0 +1,22 @@
+package org.chorem.pollen.persistence;
+
+import com.google.common.base.Preconditions;
+import org.chorem.pollen.persistence.entity.PollenEntities;
+import org.nuiton.jpa.api.JpaEntity;
+import org.nuiton.jpa.api.JpaEntityIdFactory;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class PollenEntityIdFactory implements JpaEntityIdFactory {
+
+ @Override
+ public String newId(JpaEntity entity) {
+ Preconditions.checkNotNull(entity);
+
+ return entity.getClass().getName() + '#' + PollenEntities.generateId();
+ }
+}
Property changes on: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenEntityIdFactory.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -23,9 +23,14 @@
* #L%
*/
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.nuiton.jpa.api.JpaEntity;
+import java.util.UUID;
+
/**
* TODO
*
@@ -35,13 +40,13 @@
public class PollenEntities {
public static boolean isSimpleId(String id) {
- return !id.contains("_");
+ return !id.contains("#");
}
public static String getSimpleId(JpaEntity e) {
String result = e.getId();
if (result != null) {
- result = StringUtils.substringAfter(result, "_").replaceAll("-", "");
+ result = StringUtils.substringAfter(result, "#");
}
return result;
}
@@ -49,13 +54,27 @@
public static <E extends JpaEntity> String getEntityId(Class<E> type,
String simpleId) {
StringBuilder result = new StringBuilder(type.getName());
- result.append("_");
- result.append(simpleId.substring(0, 8)).append('-');
- result.append(simpleId.substring(8, 12)).append('-');
- result.append(simpleId.substring(12, 16)).append('-');
- result.append(simpleId.substring(16, 20)).append('-');
- result.append(simpleId.substring(20));
+ result.append('#');
+ result.append(simpleId);
return result.toString();
}
+ public static String generateId() {
+ // get uuid
+ String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+
+ // decode in hexa decimal (reduce by 2 size of it)
+ byte[] decode;
+ try {
+ decode = Hex.decodeHex(uuid.toCharArray());
+ } catch (DecoderException e) {
+ // can't happen!
+ throw new RuntimeException(e);
+ }
+
+ // encode it in base64 (url safe version)
+ String result = Base64.encodeBase64URLSafeString(decode);
+ return result;
+ }
+
}
Modified: branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties 2013-06-12 08:27:48 UTC (rev 3821)
@@ -19,8 +19,9 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# #L%
-###
+###m
model.tagValue.idFactory=true
+model.tagValue.generatePropertyChangeListeners=true
model.tagvalue.version=2.0
model.tagvalue.entitySuperClass=org.chorem.pollen.persistence.entity.AbstractJpaPollenEntity
Modified: branches/pollen-2.0/pollen-persistence/src/test/java/org/chorem/pollen/persistence/entity/PollenEntitiesTest.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/test/java/org/chorem/pollen/persistence/entity/PollenEntitiesTest.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-persistence/src/test/java/org/chorem/pollen/persistence/entity/PollenEntitiesTest.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -23,9 +23,9 @@
* #L%
*/
+import org.chorem.pollen.persistence.PollenEntityIdFactory;
import org.junit.Assert;
import org.junit.Test;
-import org.nuiton.jpa.api.DefaultJpaEntityIdFactory;
import org.nuiton.jpa.api.JpaEntityIdFactoryResolver;
/**
@@ -37,7 +37,7 @@
@Test
public void getSimpleId() {
- JpaEntityIdFactoryResolver.setFactory(new DefaultJpaEntityIdFactory());
+ JpaEntityIdFactoryResolver.setFactory(new PollenEntityIdFactory());
try {
Poll poll = new Poll();
@@ -53,6 +53,5 @@
} finally {
JpaEntityIdFactoryResolver.setFactory(null);
}
-
}
}
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -59,8 +59,8 @@
return serviceContext.getNow();
}
- protected String generateId() {
- return serviceContext.generateUUID();
+ protected String generateToken() {
+ return serviceContext.generateToken();
}
protected PollenPersistenceContext getPersistenceContext() {
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -57,7 +57,7 @@
SessionTokenJpaDao dao = getPersistenceContext().getSessionTokenDao();
SessionToken sessionToken = dao.newInstance();
- String token = serviceContext.generateUUID();
+ String token = serviceContext.generateToken();
String encodedToken = serviceContext.encodePassword(token);
sessionToken.setPollenUser(user);
sessionToken.setToken(encodedToken);
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -25,13 +25,13 @@
import org.apache.commons.lang3.RandomStringUtils;
import org.chorem.pollen.persistence.PollenPersistenceContext;
+import org.chorem.pollen.persistence.entity.PollenEntities;
import org.chorem.pollen.service.config.PollenServiceConfig;
import org.nuiton.util.StringUtil;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
-import java.util.UUID;
public class DefaultPollenServiceContext implements PollenServiceContext {
@@ -53,8 +53,8 @@
}
@Override
- public String generateUUID() {
- return UUID.randomUUID().toString();
+ public String generateToken() {
+ return PollenEntities.generateId();
}
@Override
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -34,7 +34,7 @@
*/
public interface PollenServiceContext {
- String generateUUID();
+ String generateToken();
Date getNow();
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -81,7 +81,7 @@
PollenUser toCreate = dao.newInstance();
// add a emailValidationToken
- String emailValidationToken = generateId();
+ String emailValidationToken = generateToken();
String password;
if (generatePassword) {
@@ -134,7 +134,7 @@
}
// add a new emailValidationtoken
- String emailValidationToken = generateId();
+ String emailValidationToken = generateToken();
persisted.setEmailActivationToken(emailValidationToken);
}
Modified: branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml 2013-06-12 08:27:48 UTC (rev 3821)
@@ -1,6 +1,5 @@
tony:
&tony !user
- id: pollen_user_tony
login: tony
password: fake
name: T
@@ -9,7 +8,6 @@
jean:
&jean !user
- id: pollen_user_jean
login: jean
password: fake
name: J
@@ -18,7 +16,6 @@
julien:
&julien !user
- id: pollen_user_julien
login: julien
password: fake
name: J
Modified: branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -23,7 +23,6 @@
* #L%
*/
-import org.chorem.pollen.persistence.JpaEntityIdFactoryIfNotEmpty;
import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
import org.chorem.pollen.service.config.PollenServiceConfig;
import org.junit.Rule;
@@ -66,8 +65,9 @@
EntityManager entityManager = getJpaEntityManagerRule().getEntityManager();
- JpaEntityIdFactoryIfNotEmpty idGenerator = new JpaEntityIdFactoryIfNotEmpty();
- JpaPollenPersistenceContext persistenceContext = new JpaPollenPersistenceContext(idGenerator, entityManager);
+// JpaEntityIdFactoryIfNotEmpty idGenerator = new JpaEntityIdFactoryIfNotEmpty();
+// JpaPollenPersistenceContext persistenceContext = new JpaPollenPersistenceContext(idGenerator, entityManager);
+ JpaPollenPersistenceContext persistenceContext = new JpaPollenPersistenceContext(entityManager);
serviceContext.setPersistenceContext(persistenceContext);
}
Modified: branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java 2013-06-12 08:27:48 UTC (rev 3821)
@@ -81,7 +81,7 @@
Assert.assertTrue(true);
}
- PollenUser user = service.getUser("pollen_user_tony");
+ PollenUser user = service.getUser(this.user.getId());
Assert.assertNotNull(user);
Assert.assertEquals(this.user, user);
@@ -134,7 +134,7 @@
@Test
public void testEditUser() throws EntityNotFoundException, UserInvalidPasswordException, UserEmailAlreadyUsedException {
- PollenUser user = service.getUser("pollen_user_tony");
+ PollenUser user = service.getUser(this.user.getId());
Assert.assertNotNull(user);
Assert.assertNull(user.getEmailActivationToken());
@@ -165,7 +165,7 @@
@Test
public void testValidateEmail() throws EntityNotFoundException, UserInvalidPasswordException, UserEmailAlreadyUsedException, UserInvalidEmailActiviationTokenException {
- PollenUser user = service.getUser("pollen_user_tony");
+ PollenUser user = service.getUser(this.user.getId());
Assert.assertNotNull(user);
Assert.assertNull(user.getEmailActivationToken());
@@ -194,7 +194,7 @@
- PollenUser reloadedUser = service.getUser("pollen_user_tony");
+ PollenUser reloadedUser = service.getUser(this.user.getId());
Assert.assertTrue(reloadedUser.isEmailActivated());
}
Modified: branches/pollen-2.0/pom.xml
===================================================================
--- branches/pollen-2.0/pom.xml 2013-06-11 09:05:14 UTC (rev 3820)
+++ branches/pollen-2.0/pom.xml 2013-06-12 08:27:48 UTC (rev 3821)
@@ -379,8 +379,6 @@
<version>1.0</version>
</dependency>
-
-
<!-- Logging -->
<dependency>
@@ -393,6 +391,12 @@
<!-- Others -->
<dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.6</version>
+ </dependency>
+
+ <dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
1
0
Author: tchemit
Date: 2013-06-11 11:05:14 +0200 (Tue, 11 Jun 2013)
New Revision: 3820
Url: http://chorem.org/projects/pollen/repository/revisions/3820
Log:
continue...
Added:
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/AbstractJpaPollenEntity.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/JpaPollenEntity.java
branches/pollen-2.0/pollen-rest-api/src/jetty/
branches/pollen-2.0/pollen-rest-api/src/jetty/jetty-context.xml
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenRender.java
branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/
branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/
branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/AbstractPollenRestApiTest.java
branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/FakePollenServiceContext.java
branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/UserServiceTest.java
branches/pollen-2.0/pollen-rest-api/src/test/resources/pollen.properties
Removed:
branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/service/
Modified:
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/BookmarkableEntity.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java
branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties
branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.zargo
branches/pollen-2.0/pollen-rest-api/pom.xml
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenJpaTransactionFilter.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java
branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping
branches/pollen-2.0/pollen-rest-api/src/main/webapp/WEB-INF/web.xml
branches/pollen-2.0/pollen-rest-api/src/test/resources/log4j.properties
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java
branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css
branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css
branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings-white.png
branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings.png
branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/menu.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.fixture.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.min.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.object.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.attributes.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.delegate.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/votes.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/route.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/poll_form.ejs
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs
branches/pollen-2.0/pom.xml
Added: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/AbstractJpaPollenEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/AbstractJpaPollenEntity.java (rev 0)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/AbstractJpaPollenEntity.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -0,0 +1,44 @@
+package org.chorem.pollen.persistence.entity;
+
+/*
+ * #%L
+ * Pollen :: Persistence
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.nuiton.jpa.api.AbstractJpaEntity;
+
+import java.io.Serializable;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public abstract class AbstractJpaPollenEntity extends AbstractJpaEntity implements JpaPollenEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public String getSimpleId() {
+ return PollenEntities.getSimpleId(this);
+ }
+}
Property changes on: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/AbstractJpaPollenEntity.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/BookmarkableEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/BookmarkableEntity.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/BookmarkableEntity.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -35,7 +35,7 @@
String getSimpleId();
- PollenUser getPollenUser();
+// PollenUser getPollenUser();
- void setPollenUser(PollenUser pollenUser);
+// void setPollenUser(PollenUser pollenUser);
}
Added: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/JpaPollenEntity.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/JpaPollenEntity.java (rev 0)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/JpaPollenEntity.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -0,0 +1,38 @@
+package org.chorem.pollen.persistence.entity;
+
+/*
+ * #%L
+ * Pollen :: Persistence
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.nuiton.jpa.api.JpaEntity;
+
+import java.io.Serializable;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public interface JpaPollenEntity extends JpaEntity, Serializable {
+ String getSimpleId();
+}
Property changes on: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/JpaPollenEntity.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenEntities.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -34,9 +34,15 @@
*/
public class PollenEntities {
+ public static boolean isSimpleId(String id) {
+ return !id.contains("_");
+ }
+
public static String getSimpleId(JpaEntity e) {
- String id = e.getId();
- String result = StringUtils.substringAfter(id, "_").replaceAll("-", "");
+ String result = e.getId();
+ if (result != null) {
+ result = StringUtils.substringAfter(result, "_").replaceAll("-", "");
+ }
return result;
}
Modified: branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.properties 2013-06-11 09:05:14 UTC (rev 3820)
@@ -22,7 +22,7 @@
###
model.tagValue.idFactory=true
model.tagvalue.version=2.0
-model.tagvalue.constantPrefix=PROPERTY_
+model.tagvalue.entitySuperClass=org.chorem.pollen.persistence.entity.AbstractJpaPollenEntity
org.chorem.pollen.persistence.entity.Poll.attribute.choice.stereotype=ordered
org.chorem.pollen.persistence.entity.Poll.attribute.voterList.stereotype=ordered
Modified: branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.zargo
===================================================================
(Binary files differ)
Modified: branches/pollen-2.0/pollen-rest-api/pom.xml
===================================================================
--- branches/pollen-2.0/pollen-rest-api/pom.xml 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/pom.xml 2013-06-11 09:05:14 UTC (rev 3820)
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@@ -10,6 +12,7 @@
<groupId>org.chorem.pollen</groupId>
<artifactId>pollen-rest-api</artifactId>
+ <packaging>war</packaging>
<name>Pollen :: Rest Api</name>
<description>Pollen Rest Api</description>
@@ -59,10 +62,15 @@
</dependency>
<dependency>
+ <groupId>javax</groupId>
+ <artifactId>javaee-api</artifactId>
+ </dependency>
+
+ <!--dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
- </dependency>
+ </dependency-->
<dependency>
<groupId>commons-logging</groupId>
@@ -121,7 +129,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
- <scope>test</scope>
+ <scope>runtime</scope>
</dependency>
<dependency>
@@ -138,4 +146,80 @@
</dependencies>
+ <properties>
+ <defaultWebContextPath>pollen</defaultWebContextPath>
+ <defaultLogDir>${basedir}/target</defaultLogDir>
+ <defaultDbDir>${basedir}/target</defaultDbDir>
+ </properties>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <configuration>
+ <stopKey>B</stopKey>
+ <stopPort>1270</stopPort>
+ <contextXml>${basedir}/src/jetty/jetty-context.xml</contextXml>
+ <webAppConfig>
+ <contextPath>/${defaultWebContextPath}</contextPath>
+ </webAppConfig>
+ <systemProperties>
+ <systemProperty>
+ <name>testDirectory</name>
+ <value>${defaultLogDir}</value>
+ </systemProperty>
+ <systemProperty>
+ <name>testDirectory</name>
+ <value>${defaultDbDir}</value>
+ </systemProperty>
+ </systemProperties>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.tomcat.maven</groupId>
+ <artifactId>tomcat7-maven-plugin</artifactId>
+ <configuration>
+ <path>/${defaultWebContextPath}</path>
+ <systemProperties>
+ <testDirectory>${defaultDbDir}</testDirectory>
+ <pollen.log.dir>${defaultLogDir}</pollen.log.dir>
+ </systemProperties>
+ <uriEncoding>UTF-8</uriEncoding>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>test</id>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/test/resources</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ </build>
+ <properties>
+
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-jcl</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ </profiles>
+
</project>
Added: branches/pollen-2.0/pollen-rest-api/src/jetty/jetty-context.xml
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/jetty/jetty-context.xml (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/jetty/jetty-context.xml 2013-06-11 09:05:14 UTC (rev 3820)
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ #%L
+ Pollen :: UI (struts2)
+ $Id$
+ $HeadURL$
+ %%
+ Copyright (C) 2009 - 2012 CodeLutin, Tony Chemit
+ %%
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (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 Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ #L%
+ -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Call name="setAttribute">
+ <Arg>org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</Arg>
+ <Arg>.*/.*jsp-api-[^/]\.jar$|./.*jsp-[^/]\.jar$|./.*taglibs[^/]*\.jar$</Arg>
+ </Call>
+</Configure>
\ No newline at end of file
Property changes on: branches/pollen-2.0/pollen-rest-api/src/jetty/jetty-context.xml
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenJpaTransactionFilter.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenJpaTransactionFilter.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenJpaTransactionFilter.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -50,10 +50,20 @@
log.info("Init JPA Filter");
}
- applicationContext = PollenServices.getApplicationContext(
- filterConfig.getServletContext());
+// applicationContext = PollenServices.getApplicationContext(
+// filterConfig.getServletContext());
+//
+// Preconditions.checkNotNull(applicationContext, "Could not find application context at ServletContext#pollen_PollenApplicationContext");
+ }
- Preconditions.checkNotNull(applicationContext, "Could not find application context at ServletContext#pollen_PollenApplicationContext");
+ protected PollenApplicationContext getApplicationContext(ServletRequest request) {
+ if (applicationContext == null) {
+ applicationContext = PollenServices.getApplicationContext(
+ request.getServletContext());
+
+ Preconditions.checkNotNull(applicationContext, "Could not find application context at ServletContext#pollen_PollenApplicationContext");
+ }
+ return applicationContext;
}
@Override
@@ -63,7 +73,7 @@
try {
- entityManager = applicationContext.newEntityManager();
+ entityManager = getApplicationContext(request).newEntityManager();
} catch (PersistenceException e) {
Added: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenRender.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenRender.java (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenRender.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -0,0 +1,243 @@
+package org.chorem.pollen.rest;
+
+/*
+ * #%L
+ * Pollen :: Rest Api
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.gson.Gson;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.chorem.pollen.persistence.entity.JpaPollenEntity;
+import org.debux.webmotion.server.call.Call;
+import org.debux.webmotion.server.call.HttpContext;
+import org.debux.webmotion.server.mapping.Mapping;
+import org.debux.webmotion.server.render.Render;
+import org.nuiton.jpa.api.JpaEntity;
+import org.nuiton.util.ObjectUtil;
+import org.nuiton.util.beans.Binder;
+import org.nuiton.util.beans.BinderFactory;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * To render
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class PollenRender<T> extends Render {
+
+
+ /**
+ * To specify entity collections to include in binded entities.
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ public @interface ExposeCollection {
+
+ public String[] values() default {};
+ }
+
+ protected T model;
+
+ public PollenRender(T model) {
+ this.model = model;
+ }
+
+ @Override
+ public void create(Mapping mapping, Call call) throws IOException, ServletException {
+
+ HttpContext context = call.getContext();
+ HttpServletResponse response = context.getResponse();
+ response.setContentType("application/json");
+
+ String[] includeCollection = null;
+ ExposeCollection annotation = call.getCurrent().getMethod().getAnnotation(ExposeCollection.class);
+ if (annotation != null) {
+ includeCollection = annotation.values();
+ }
+ Object map = toMap(model, includeCollection);
+
+ Gson gson = new Gson();
+ String json = gson.toJson(map);
+ PrintWriter out = context.getOut();
+ out.print(json);
+ }
+
+ protected <M> Object toMap(M model, String... includeCollection) {
+ if (model instanceof Iterable<?>) {
+
+ // collection of objects
+ Iterable<?> objects = (Iterable<?>) model;
+ List<Object> result = Lists.newArrayList();
+ for (Object object : objects) {
+ Object objectMap = toMap(object, includeCollection);
+ result.add(objectMap);
+ }
+ return result;
+ }
+
+ // single object
+
+ if (model instanceof JpaPollenEntity) {
+
+ // entity need to transform it
+
+ JpaPollenEntity jpaEntity = (JpaPollenEntity) model;
+
+ PollenEntityBinder<JpaPollenEntity> binder = BinderFactory.newBinder(jpaEntity.getClass(), jpaEntity.getClass(), null, PollenEntityBinder.class);
+ Map<String, Object> map = binder.obtainProperties(jpaEntity);
+ Map<String, Object> result = Maps.newTreeMap();
+
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
+ String propertyName = entry.getKey();
+ Object propertyValue = entry.getValue();
+ if (propertyValue instanceof JpaPollenEntity) {
+ result.put(propertyName, toMap(propertyValue));
+ continue;
+ }
+
+ result.put(propertyName, propertyValue);
+ }
+
+ // replace id to simpleId
+ result.put(JpaEntity.PROPERTY_ID, jpaEntity.getSimpleId());
+
+ // treat collections
+
+ if (includeCollection != null) {
+ for (String propertyName : includeCollection) {
+ Iterable<?> collectionValue = binder.getCollectionValue(jpaEntity, propertyName);
+ result.put(propertyName, toMap(collectionValue));
+
+ }
+ }
+ return result;
+
+ }
+
+ return model;
+
+
+ }
+
+ protected static class PollenEntityBinder<E extends JpaPollenEntity> extends Binder<E, E> {
+
+ /** Logger. */
+ private static final Log log =
+ LogFactory.getLog(PollenEntityBinder.class);
+
+ private static final long serialVersionUID = 1L;
+
+ protected List<String> simpleProperties;
+
+ public PollenEntityBinder() {
+
+ }
+
+ @Override
+ protected void setModel(BinderModel<E, E> model) {
+ super.setModel(model);
+ this.simpleProperties = Lists.newArrayList();
+ for (String property : model.getSourceDescriptors()) {
+ if (model.getCollectionType(property)==null) {
+ simpleProperties.add(property);
+ }
+ }
+ }
+
+ /**
+ * Obtain from the given object all properties registered in the binder
+ * model.
+ *
+ * @param source the bean to read
+ * @return the map of properties obtained indexed by their property name,
+ * or an empty map is the given {@code from} is {@code null}.
+ * @since 2.3
+ */
+ public Map<String, Object> obtainProperties(E source) {
+ if (source == null) {
+ // special limit case
+ return Collections.emptyMap();
+ }
+
+ Map<String, Object> result = Maps.newTreeMap();
+ for (String sourceProperty : simpleProperties) {
+
+
+ try {
+ Object read;
+ Method readMethod = model.getSourceReadMethod(sourceProperty);
+ read = readMethod.invoke(source);
+ if (log.isDebugEnabled()) {
+ log.debug("property " + sourceProperty + ", type : " +
+ readMethod.getReturnType() + ", value = " + read);
+ }
+ if (readMethod.getReturnType().isPrimitive() &&
+ ObjectUtil.getNullValue(
+ readMethod.getReturnType()).equals(read)) {
+ // for primitive type case, force nullity
+ read = null;
+ }
+
+ if (read != null) {
+ result.put(sourceProperty, read);
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return result;
+ }
+
+ public Iterable<?> getCollectionValue(E source, String sourceProperty) {
+ try {
+ Method readMethod = model.getSourceReadMethod(sourceProperty);
+ Object result = readMethod.invoke(source);
+ return (Iterable<?>) result;
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
Property changes on: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenRender.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -23,18 +23,28 @@
* #L%
*/
+import com.google.common.collect.Maps;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.chorem.pollen.persistence.entity.Comment;
+import org.chorem.pollen.persistence.entity.Poll;
+import org.chorem.pollen.persistence.entity.PollenEntities;
+import org.chorem.pollen.persistence.entity.PollenUser;
import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.exception.UserEmailAlreadyUsedException;
+import org.chorem.pollen.service.exception.UserLoginAlreadyUsedException;
import org.debux.webmotion.server.WebMotionServerListener;
import org.debux.webmotion.server.call.Call;
import org.debux.webmotion.server.call.HttpContext;
import org.debux.webmotion.server.call.ServerContext;
import org.debux.webmotion.server.handler.ExecutorParametersInjectorHandler;
import org.debux.webmotion.server.mapping.Mapping;
+import org.nuiton.jpa.api.JpaEntity;
+import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;
+import java.util.Map;
/**
* TODO
@@ -52,6 +62,7 @@
public void onStart(Mapping mapping, ServerContext serverContext) {
serverContext.addInjector(new PollenServiceContextInjector());
+ serverContext.addInjector(new PollenIdInjector());
// Create application context
PollenApplicationContext applicationContext =
@@ -60,6 +71,19 @@
// push it in context
PollenServices.setApplicationContext(
serverContext.getServletContext(), applicationContext);
+
+ EntityManager entityManager = applicationContext.newEntityManager();
+
+ try {
+ PollenServiceContext serviceContext = applicationContext.newServiceContext(entityManager);
+ serviceContext.getUserService().createDefaultUsers();
+ } catch (UserEmailAlreadyUsedException e) {
+ //Can't happen
+ } catch (UserLoginAlreadyUsedException e) {
+ //Can't happen
+ } finally {
+ entityManager.close();
+ }
}
@Override
@@ -78,7 +102,7 @@
protected static class PollenServiceContextInjector implements ExecutorParametersInjectorHandler.Injector {
@Override
- public Object getValue(Mapping mapping, Call call, Class<?> type, Type generic) {
+ public Object getValue(Mapping mapping, Call call, String name, Class<?> type, Type generic) {
if (PollenServiceContext.class.isAssignableFrom(type)) {
HttpContext httpContext = call.getContext();
HttpServletRequest request = httpContext.getRequest();
@@ -87,4 +111,45 @@
return null;
}
}
+
+ protected static class PollenIdInjector implements ExecutorParametersInjectorHandler.Injector {
+
+ final Map<String, Class<? extends JpaEntity>> paramMapping;
+
+ public PollenIdInjector() {
+ paramMapping = Maps.newTreeMap();
+ paramMapping.put("userId", PollenUser.class);
+ paramMapping.put("pollId", Poll.class);
+ paramMapping.put("commentId", Comment.class);
+ }
+
+ @Override
+ public Object getValue(Mapping mapping,
+ Call call,
+ String name,
+ Class<?> type,
+ Type generic) {
+
+ if (String.class.isAssignableFrom(type) && paramMapping.containsKey(name)) {
+
+ Class<? extends JpaEntity> entityType = paramMapping.get(name);
+
+ Call.ParameterTree parameterTree = call.getParameterTree();
+ Map<String, Call.ParameterTree> tree = parameterTree.getTree();
+
+ Call.ParameterTree paramValue = tree.get(name);
+ if (paramValue != null) {
+ String id = String.valueOf(((String[]) paramValue.getValue())[0]);
+ if (PollenEntities.isSimpleId(id)) {
+
+ // get the full id
+ String fullId = PollenEntities.getEntityId(
+ entityType, id);
+ return fullId;
+ }
+ }
+ }
+ return null;
+ }
+ }
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -38,9 +38,9 @@
*/
public class CommentService extends WebMotionController {
- public Comment[] getComments(PollenServiceContext context, String pollId) throws EntityNotFoundException {
+ public List<Comment> getComments(PollenServiceContext context, String pollId) throws EntityNotFoundException {
List<Comment> comments = context.getCommentService().getComments(pollId);
- return comments.toArray(new Comment[comments.size()]);
+ return comments;
}
public Comment getComment(PollenServiceContext context, String commentId) throws EntityNotFoundException {
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -39,9 +39,9 @@
*/
public class FavoriteListService extends WebMotionController {
- public FavoriteList[] getFavoriteLists(PollenServiceContext context, String userId) throws EntityNotFoundException {
+ public List<FavoriteList> getFavoriteLists(PollenServiceContext context, String userId) throws EntityNotFoundException {
List<FavoriteList> favoriteLists = context.getFavoriteListService().getFavoriteLists(userId);
- return favoriteLists.toArray(new FavoriteList[favoriteLists.size()]);
+ return favoriteLists;
}
public FavoriteList getFavoriteList(PollenServiceContext context, String favoriteListId) throws EntityNotFoundException {
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -29,6 +29,7 @@
import org.chorem.pollen.service.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
+import javax.servlet.annotation.WebFilter;
import java.io.File;
import java.util.List;
import java.util.Set;
@@ -41,19 +42,24 @@
*/
public class PollService extends WebMotionController {
- public Poll[] getCreatedPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
+ public Set<Poll> getPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
+ Set<Poll> polls = context.getPollService().getPolls(userId);
+ return polls;
+ }
+
+ public Set<Poll> getCreatedPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
Set<Poll> polls = context.getPollService().getCreatedPolls(userId);
- return polls.toArray(new Poll[polls.size()]);
+ return polls;
}
- public Poll[] getInvitedPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
+ public Set<Poll> getInvitedPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
Set<Poll> polls = context.getPollService().getInvitedPolls(userId);
- return polls.toArray(new Poll[polls.size()]);
+ return polls;
}
- public Poll[] getParticipatedPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
+ public Set<Poll> getParticipatedPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
Set<Poll> polls = context.getPollService().getParticipatedPolls(userId);
- return polls.toArray(new Poll[polls.size()]);
+ return polls;
}
public Poll createPoll(PollenServiceContext context, String userId, Poll poll) throws EntityNotFoundException {
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -42,9 +42,9 @@
*/
public class UserService extends WebMotionController {
- public PollenUser[] getUsers(PollenServiceContext context) {
+ public List<PollenUser> getUsers(PollenServiceContext context) {
List<PollenUser> users = context.getUserService().getUsers();
- return users.toArray(new PollenUser[users.size()]);
+ return users;
}
public PollenUser getUser(PollenServiceContext context,
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -38,9 +38,9 @@
*/
public class VoteService extends WebMotionController {
- public Vote[] getVotes(PollenServiceContext context, String pollId) throws EntityNotFoundException {
+ public List<Vote> getVotes(PollenServiceContext context, String pollId) throws EntityNotFoundException {
List<Vote> votes = context.getVoteService().getVotes(pollId);
- return votes.toArray(new Vote[votes.size()]);
+ return votes;
}
public Vote getVote(PollenServiceContext context, String voteId) throws EntityNotFoundException {
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -44,9 +44,9 @@
return context.getVoterListService().importFavoriteList(pollId, favoriteListId);
}
- public VoterList[] getVoterLists(PollenServiceContext context, String pollId) throws EntityNotFoundException {
+ public List<VoterList> getVoterLists(PollenServiceContext context, String pollId) throws EntityNotFoundException {
List<VoterList> voterLists = context.getVoterListService().getVoterLists(pollId);
- return voterLists.toArray(new VoterList[voterLists.size()]);
+ return voterLists;
}
public VoterList getVoterList(PollenServiceContext context, String voterListId) throws EntityNotFoundException {
Modified: branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping 2013-06-11 09:05:14 UTC (rev 3820)
@@ -1,101 +1,104 @@
[config]
package.filters=org.chorem.pollen.rest
package.actions=org.chorem.pollen.rest.api
+package.errors=org.chorem.pollen.rest.api
server.listener.class=org.chorem.pollen.rest.PollenServiceListener
+default.render=org.chorem.pollen.rest.PollenRender
[filters]
* /* PollenServiceContextFilter.inject
-* /* PollenIdOrTokenInjector.inject
-* /* PollenSecurityFilter.inject (prend le param auth pour retrouver le PollenUser)
+#* /* PollenIdOrTokenInjector.inject
+#* /* PollenSecurityFilter.inject (prend le param auth pour retrouver le PollenUser)
#- une fois un object lié à PollenUser, c'est immuable.
[errors]
-org.chorem.pollen.service.exception.EntityNotFoundException action:ErrorAction.on402
-org.chorem.pollen.service.exception.UserEmailAlreadyUsedException action:ErrorAction.on500
-org.chorem.pollen.service.exception.UserLoginAlreadyUsedException action:ErrorAction.on500
-org.chorem.pollen.service.exception.UserInvalidPasswordException action:ErrorAction.on500
-org.chorem.pollen.service.exception.UserInvalidEmailActiviationTokenException action:ErrorAction.on500
+org.chorem.pollen.service.exception.EntityNotFoundException ErrorAction.on404
+org.chorem.pollen.service.exception.UserEmailAlreadyUsedException ErrorAction.on500
+org.chorem.pollen.service.exception.UserLoginAlreadyUsedException ErrorAction.on500
+org.chorem.pollen.service.exception.UserInvalidPasswordException ErrorAction.on500
+org.chorem.pollen.service.exception.UserInvalidEmailActiviationTokenException ErrorAction.on500
[actions]
# AuthService
-PUT /login action:AuthService.login
-GET /lostpassword/{token} action:AuthService.lostPassword
-GET /logout action:AuthService.logout
+PUT /login AuthService.login
+GET /lostpassword/{token} AuthService.lostPassword
+GET /logout AuthService.logout
# CommentService
-GET /polls/{pollId}/comments action:CommentService.getComments
-POST /polls/{pollId}/comments action:CommentService.addComment
-GET /comments/{commentId} action:CommentService.getComment
-PUT /comments action:CommentService.editComment
-DELETE /polls/{pollId}/comments/{commentId} action:CommentService.deleteComment
+GET /polls/{pollId}/comments CommentService.getComments
+POST /polls/{pollId}/comments CommentService.addComment
+GET /comments/{commentId} CommentService.getComment
+PUT /comments CommentService.editComment
+DELETE /polls/{pollId}/comments/{commentId} CommentService.deleteComment
# FavoriteListService
-GET /favoriteLists action:FavoriteList.getFavoriteLists
-GET /favoriteLists/{flId} action:FavoriteList.getFavoriteList
-POST /favoriteLists action:FavoriteList.createFavoriteList
-PUT /favoriteLists action:FavoriteList.editFavoriteList
-DELETE /favoriteLists/{flId} action:FavoriteList.deleteFavoriteList
-GET /favoriteLists/{flId}/members action:FavoriteList.getMembers
-GET /favoriteListMembers/{mId} action:FavoriteList.getMember
-POST /favoriteLists/{flId}/members action:FavoriteList.addMember
-PUT /favoriteListMembers action:FavoriteList.editMember
-DELETE /favoriteLists/{flId}/members/{mId} action:FavoriteList.removeMember
+GET /favoriteLists FavoriteListService.getFavoriteLists
+GET /favoriteLists/{flId} FavoriteListService.getFavoriteList
+POST /favoriteLists FavoriteListService.createFavoriteList
+PUT /favoriteLists FavoriteListService.editFavoriteList
+DELETE /favoriteLists/{flId} FavoriteListService.deleteFavoriteList
+GET /favoriteLists/{flId}/members FavoriteListService.getMembers
+GET /favoriteListMembers/{mId} FavoriteListService.getMember
+POST /favoriteLists/{flId}/members FavoriteListService.addMember
+PUT /favoriteListMembers FavoriteListService.editMember
+DELETE /favoriteLists/{flId}/members/{mId} FavoriteListService.removeMember
# PollService
-GET /polls action:PollService.getPolls
-GET /polls/created action:PollService.getCreatedPolls
-GET /polls/invited action:PollService.getInvitedPolls
-GET /polls/participated action:PollService.getParticipatedPolls
-PUT /polls action:PollService.createPoll
-PUT /polls action:PollService.editPoll
-DELETE /polls/{pollOrTokenId} action:PollService.deletePoll
-POST /polls/{pollId} action:PollService.clonePoll
-GET /polls/{pollId}/export action:PollService.exportPoll
-PUT /polls/{pollId}/close action:PollService.closePoll
+GET /polls PollService.getPolls
+GET /polls/created PollService.getCreatedPolls
+GET /polls/invited PollService.getInvitedPolls
+GET /polls/participated PollService.getParticipatedPolls
+POST /polls PollService.createPoll
+PUT /polls PollService.editPoll
+GET /polls/{pollId} PollService.getPoll
+DELETE /polls/{pollId} PollService.deletePoll
+POST /polls/{pollId} PollService.clonePoll
+GET /polls/{pollId}/export PollService.exportPoll
+PUT /polls/{pollId}/close PollService.closePoll
-GET /polls/{pollId}/choices action:PollService.getChoices
-POST /polls/{pollId}/choices action:PollService.addChoice
-GET /choices/{choiceId} action:PollService.getChoice
-PUT /choices action:PollService.editChoice
-DELETE /polls/{pollId}/choices/{choiceId} action:PollService.deleteChoice
+GET /polls/{pollId}/choices PollService.getChoices
+POST /polls/{pollId}/choices PollService.addChoice
+GET /choices/{choiceId} PollService.getChoice
+PUT /choices PollService.editChoice
+DELETE /polls/{pollId}/choices/{choiceId} PollService.deleteChoice
# UserService
-GET /users action:UserService.getUsers
-GET /users/{userId} action:UserService.getUser
-POST /users action:UserService.createUser
-PUT /users action:UserService.editUser
-GET /validateemail/{token} action:UserService.validateUserEmail
+GET /users UserService.getUsers
+GET /users/{userId} UserService.getUser
+POST /users UserService.createUser
+PUT /users UserService.editUser
+PUT /users/{userId}?token={} UserService.validateUserEmail
# VoteCountingService
-GET /polls/{pollId}/results action:VoteCountingService.getResult
+GET /polls/{pollId}/results VoteCountingService.getResult
# VoterListService
-PUT /polls/{pollId}/favoriteLists/{flId} action:VoterListService.importFavoriteList
-GET /polls/{pollId}/voterLists action:VoterListService.getVoterLists
-GET /voterLists/{vlId} action:VoterListService.getVoterList
-PUT /voterLists/{vlId} action:VoterListService.editVoterList
-DELETE /polls/{pollId}/voterLists/{vlId} action:VoterListService.deleteVoterList
+PUT /polls/{pollId}/favoriteLists/{flId} VoterListService.importFavoriteList
+GET /polls/{pollId}/voterLists VoterListService.getVoterLists
+GET /voterLists/{vlId} VoterListService.getVoterList
+PUT /voterLists/{vlId} VoterListService.editVoterList
+DELETE /polls/{pollId}/voterLists/{vlId} VoterListService.deleteVoterList
-GET /voterLists/{vlId}/members action:VoterListService.getMembers
-GET /voterListMembers/{mId} action:VoterListService.getMember
-POST /voterLists/{vlId}/members action:VoterListService.addMember
-PUT /voterListMembers action:VoterListService.editMember
-DELETE /voterLists/{vlId}/members/{mId} action:VoterListService.deleteMember
+GET /voterLists/{vlId}/members VoterListService.getMembers
+GET /voterListMembers/{mId} VoterListService.getMember
+POST /voterLists/{vlId}/members VoterListService.addMember
+PUT /voterListMembers VoterListService.editMember
+DELETE /voterLists/{vlId}/members/{mId} VoterListService.deleteMember
# VoteService
-GET /polls/{pollId}/votes action:VoteService.getVotes
-PUT /polls/{pollId}/votes action:VoteService.addVote
-GET /votes/{voteId} action:VoteService.getVote
-PUT /votes action:VoteService.editVote
-DELETE /polls/{pollId}/votes/{voteId} action:VoteService.deleteVote
+GET /polls/{pollId}/votes VoteService.getVotes
+PUT /polls/{pollId}/votes VoteService.addVote
+GET /votes/{voteId} VoteService.getVote
+PUT /votes VoteService.editVote
+DELETE /polls/{pollId}/votes/{voteId} VoteService.deleteVote
Modified: branches/pollen-2.0/pollen-rest-api/src/main/webapp/WEB-INF/web.xml
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/webapp/WEB-INF/web.xml 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/main/webapp/WEB-INF/web.xml 2013-06-11 09:05:14 UTC (rev 3820)
@@ -22,17 +22,22 @@
#L%
-->
-<web-app version="3.0"
+<web-app version="3.0" id="pollen"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
- <!-- workarround for webmotion bug http://projects.debux.org/issues/293 -->
- <!--session-config>
- <tracking-mode>COOKIE</tracking-mode>
- </session-config-->
+ <display-name>Pollen REST Api</display-name>
+ <listener>
+ <listener-class>org.apache.commons.fileupload.servlet.FileCleanerCleanup</listener-class>
+ </listener>
+
+ <listener>
+ <listener-class>org.debux.webmotion.server.WebMotionServletContextListener</listener-class>
+ </listener>
+
<filter>
<filter-name>jpaTransaction</filter-name>
<filter-class>
@@ -40,8 +45,24 @@
</filter-class>
</filter>
+ <filter>
+ <filter-name>WebMotionServer</filter-name>
+ <filter-class>org.debux.webmotion.server.WebMotionServer</filter-class>
+ <async-supported>true</async-supported>
+ </filter>
+
<filter-mapping>
<filter-name>jpaTransaction</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
+
+ <filter-mapping>
+ <filter-name>WebMotionServer</filter-name>
+ <url-pattern>/*</url-pattern>
+ <dispatcher>REQUEST</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>ERROR</dispatcher>
+ </filter-mapping>
+
</web-app>
\ No newline at end of file
Added: branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/AbstractPollenRestApiTest.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/AbstractPollenRestApiTest.java (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/AbstractPollenRestApiTest.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -0,0 +1,121 @@
+package org.chorem.pollen.rest.api;
+
+/*
+ * #%L
+ * Pollen :: Rest Api
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
+import org.chorem.pollen.rest.PollenApplicationContext;
+import org.chorem.pollen.service.FixturesService;
+import org.chorem.pollen.service.PollenFixtures;
+import org.chorem.pollen.service.PollenServiceContext;
+import org.debux.webmotion.unittest.WebMotionTest;
+import org.junit.Before;
+import org.junit.Rule;
+import org.nuiton.jpa.junit.JpaEntityManagerRule;
+
+import javax.persistence.EntityManager;
+import java.util.Map;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class AbstractPollenRestApiTest extends WebMotionTest {
+
+ protected JpaEntityManagerRule jpaEntityManagerRule;
+
+ protected PollenFixtures fixtures;
+
+ protected PollenApplicationContext applicationContext;
+
+ public PollenApplicationContext getApplicationContext() {
+ if (applicationContext == null) {
+ applicationContext =
+ new PollenApplicationContext() {
+ @Override
+ public EntityManager newEntityManager() {
+ return getJpaEntityManagerRule().getEntityManager();
+ }
+
+ @Override
+ public PollenServiceContext newServiceContext(EntityManager entityManager) {
+
+ FakePollenServiceContext serviceContext = new FakePollenServiceContext();
+
+ JpaPollenPersistenceContext jpaMagaliePersistenceContext =
+ new JpaPollenPersistenceContext(entityManager);
+
+ serviceContext.setPersistenceContext(jpaMagaliePersistenceContext);
+
+ serviceContext.setPollenServiceConfig(applicationConfig);
+
+ return serviceContext;
+
+ }
+ };
+ }
+ return applicationContext;
+ }
+
+ @Rule
+ public JpaEntityManagerRule getJpaEntityManagerRule() {
+
+ if (jpaEntityManagerRule == null) {
+
+ Map<String, String> jpaParameters = getApplicationContext().getPollenServiceConfig().getJpaParameters();
+
+ jpaEntityManagerRule = new JpaEntityManagerRule("pollenPersistenceUnit", jpaParameters);
+ }
+
+ return jpaEntityManagerRule;
+ }
+
+ protected PollenServiceContext getServiceContext() {
+
+ EntityManager entityManager = getJpaEntityManagerRule().getEntityManager();
+
+ PollenServiceContext result = applicationContext.newServiceContext(entityManager);
+ return result;
+ }
+
+ protected void loadFixtures(String fixturesSetName) {
+
+ FixturesService fixturesService = getServiceContext().getFixturesService();
+
+ fixtures = fixturesService.loadFixtures(fixturesSetName);
+
+ }
+
+ protected <E> E fixture(String id) {
+
+ return fixtures.fixture(id);
+
+ }
+
+ @Before
+ public void launchServer() throws Exception {
+ runServer();
+ }
+}
Property changes on: branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/AbstractPollenRestApiTest.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Copied: branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/FakePollenServiceContext.java (from rev 3817, branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/FakePollenServiceContext.java)
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/FakePollenServiceContext.java (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/FakePollenServiceContext.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -0,0 +1,53 @@
+package org.chorem.pollen.rest.api;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.chorem.pollen.service.DefaultPollenServiceContext;
+
+import java.util.Date;
+
+public class FakePollenServiceContext extends DefaultPollenServiceContext {
+
+ private static final Log log =
+ LogFactory.getLog(FakePollenServiceContext.class);
+
+ protected Date date;
+
+ @Override
+ public Date getNow() {
+ Preconditions.checkState(date != null, "you must provide a date before running service test");
+ if (log.isTraceEnabled()) {
+ log.trace("injecting fake date in service: " + date);
+ }
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+}
Added: branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/UserServiceTest.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/UserServiceTest.java (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/UserServiceTest.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -0,0 +1,84 @@
+package org.chorem.pollen.rest.api;
+
+/*
+ * #%L
+ * Pollen :: Rest Api
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.apache.http.client.fluent.Request;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+@Ignore
+public class UserServiceTest extends AbstractPollenRestApiTest {
+
+
+ @Before
+ public void setUp() throws Exception {
+
+ loadFixtures("fixtures");
+ }
+
+ @Test
+ public void testGetUsers() throws Exception {
+
+ Request request = createRequest("/users").Get();
+ String result = request.execute().returnContent().asString();
+
+ assertTrue(result.contains("users"));
+
+
+ }
+
+// @Test
+// public void testGetUser() throws Exception {
+//
+// }
+//
+// @Test
+// public void testCreateUser() throws Exception {
+//
+// }
+//
+// @Test
+// public void testEditUser() throws Exception {
+//
+// }
+//
+// @Test
+// public void testValidateUserEmail() throws Exception {
+//
+// }
+//
+// @Test
+// public void testChangePassword() throws Exception {
+//
+// }
+}
Property changes on: branches/pollen-2.0/pollen-rest-api/src/test/java/org/chorem/pollen/rest/api/UserServiceTest.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-rest-api/src/test/resources/log4j.properties
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/test/resources/log4j.properties 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-rest-api/src/test/resources/log4j.properties 2013-06-11 09:05:14 UTC (rev 3820)
@@ -20,12 +20,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# #L%
###
-log4j.rootCategory=ERROR, console
+log4j.rootCategory=DEBUG, console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{hh:mm:ss} %5p (%F:%L) %m%n
-# log4j.logger.org.chorem.pollen=TRACE
+log4j.logger.org.chorem.pollen=TRACE
+log4j.logger.org.debux=TRACE
# log4j.logger.org.hibernate.tool.hbm2ddl.SchemaExport=FATAL
Added: branches/pollen-2.0/pollen-rest-api/src/test/resources/pollen.properties
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/test/resources/pollen.properties (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/test/resources/pollen.properties 2013-06-11 09:05:14 UTC (rev 3820)
@@ -0,0 +1,9 @@
+javax.persistence.jdbc.driver=org.h2.Driver
+javax.persistence.jdbc.url=jdbc:h2:file:${testDirectory}/pollen/h2data
+javax.persistence.jdbc.user=sa
+javax.persistence.jdbc.password=
+hibernate.dialect=org.hibernate.dialect.H2Dialect
+hibernate.hbm2ddl.auto=update
+hibernate.show_sql=false
+hibernate.format_sql=true
+hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
Property changes on: branches/pollen-2.0/pollen-rest-api/src/test/resources/pollen.properties
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -118,11 +118,16 @@
}
@Override
+ public FixturesService getFixturesService() {
+ return newService(FixturesService.class);
+ }
+
+ @Override
public String encodePassword(String password) {
return StringUtil.encodeMD5(password);
}
- protected <E extends PollenServiceSupport> E newService(Class<E> serviceClass) {
+ public <E extends PollenServiceSupport> E newService(Class<E> serviceClass) {
E service;
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -24,6 +24,7 @@
*/
import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
import org.chorem.pollen.persistence.entity.Choice;
import org.chorem.pollen.persistence.entity.Poll;
import org.chorem.pollen.persistence.entity.PollenUser;
@@ -197,4 +198,8 @@
getPersistenceContext().commit();
}
+
+ public Set<Poll> getPolls(String userId) throws EntityNotFoundException {
+ return Sets.newHashSet(getPersistenceContext().getPollDao().findAll());
+ }
}
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -60,6 +60,8 @@
EmailService getEmailService();
+ FixturesService getFixturesService();
+
String generatePassword();
String encodePassword(String password);
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java 2013-06-11 09:05:14 UTC (rev 3820)
@@ -199,6 +199,18 @@
getPersistenceContext().commit();
}
+ public void createDefaultUsers() throws UserEmailAlreadyUsedException, UserLoginAlreadyUsedException {
+
+ PollenUser user = getPollenUserDao().newInstance();
+
+ user.setAdministrator(true);
+ String login = "admin";
+ user.setLogin(login);
+ user.setEmail("admin(a)pollen.org");
+ user.setPassword("admin");
+ createUser(user, false);
+ }
+
protected void notifyUserCreated(PollenUser user) {
//TODO
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings-white.png
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings.png
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/menu.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.fixture.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.min.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.object.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.attributes.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.delegate.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/votes.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/route.js
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/poll_form.ejs
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pom.xml
===================================================================
--- branches/pollen-2.0/pom.xml 2013-06-08 12:12:35 UTC (rev 3819)
+++ branches/pollen-2.0/pom.xml 2013-06-11 09:05:14 UTC (rev 3820)
@@ -169,7 +169,7 @@
<nuitonI18nVersion>2.5.1</nuitonI18nVersion>
<nuitonWebVersion>1.13</nuitonWebVersion>
- <nuitonUtilsVersion>2.6.12</nuitonUtilsVersion>
+ <nuitonUtilsVersion>2.6.13-SNAPSHOT</nuitonUtilsVersion>
<h2Version>1.3.172</h2Version>
<postgresqlVersion>9.1-901-1.jdbc4</postgresqlVersion>
<!--<struts2Version>2.3.14.2</struts2Version>-->
@@ -406,6 +406,13 @@
</dependency>
<dependency>
+ <groupId>javax</groupId>
+ <artifactId>javaee-api</artifactId>
+ <version>6.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-runner</artifactId>
<version>${jettyVersion}</version>
1
0
r3819 - in branches/pollen-2.0/pollen-ui-js/src/main/webapp: . js js/controls js/libs js/models views
by kmorin@users.chorem.org 08 Jun '13
by kmorin@users.chorem.org 08 Jun '13
08 Jun '13
Author: kmorin
Date: 2013-06-08 14:12:35 +0200 (Sat, 08 Jun 2013)
New Revision: 3819
Url: http://chorem.org/projects/pollen/repository/revisions/3819
Log:
second commit
Added:
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/menu.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.fixture.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.min.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.object.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.attributes.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.delegate.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/votes.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/route.js
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/poll_form.ejs
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs
branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/menu.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/menu.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/menu.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,5 @@
+var Menu = can.Control({
+ init: function() {
+ this.element.html(can.view('views/menu.ejs'));
+ },
+});
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_form.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,87 @@
+var PollForm = can.Control({
+
+ defaults: {
+ poll: new Poll()
+ }
+
+}, {
+ init: function() {
+
+ this.element.html(can.view('views/poll_form.ejs', {
+ poll: this.options.poll
+ }));
+
+ },
+
+ '{can.route} change': function(data, ev, prop, how, newVal, oldVal ) {
+ if (prop === "type" && (how === "set" || how === "add")) {
+ if (newVal != "poll") {
+ this.element.hide();
+ }
+ } else if (prop === "action" && (how === "set" || how === "add")) {
+ if (newVal != "edit") {
+ this.element.hide();
+ }
+ }
+ },
+
+ ':type/:action route': function(data) {
+ if (data.type === "poll" && data.action === "edit") {
+ this.editPoll(new Poll());
+ }
+ },
+
+ ':type/:id/:action route': function(data) {
+ if (data.type === "poll" && data.action === "edit") {
+ var self = this;
+ $.when(Poll.findOne({id: data.id})).then(
+ function(poll) {
+ self.editPoll(poll);
+ });
+ }
+ },
+
+ '.save click': function() {
+ this.updatePoll();
+ },
+
+ '.create click': function() {
+ can.route.attr({ type: "poll", action: "edit" }, true);
+ },
+
+ '[data-id] click': function(el, ev) {
+ can.route.attr({ type: "poll", action: "edit", id: el.data('id') });
+ },
+
+ '{poll} created': function(data) {
+ can.route.attr({ type: "poll", action: "summary", id: data.id });
+ },
+
+ '{poll} updated': function(data) {
+ can.route.attr({ type: "poll", action: "summary", id: data.id });
+ },
+
+ updatePoll: function() {
+ var form = this.element.find('form'),
+ values = can.deparam(form.serialize());
+
+ this.options.poll.attr(values).save();
+ },
+
+ editPoll: function(poll) {
+ console.log("edit poll " + poll.id + " : " + poll.description);
+ this.options.poll = poll;
+ this.on();
+ this.refreshForm();
+ this.element.show();
+ },
+
+ refreshForm: function() {
+ var form = this.element.find('form');
+ form[0].reset();
+ for (var k in this.options.poll._data) {
+ form.find("[name=" + k + "]").val(this.options.poll[k]);
+ }
+ }
+
+});
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/poll_summary.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,32 @@
+var PollSummary = can.Control({
+
+ '{can.route} change': function(data, ev, prop, how, newVal, oldVal ) {
+ if (prop === "type" && (how === "set" || how === "add")) {
+ if (newVal != "poll") {
+ this.element.hide();
+ }
+ } else if (prop === "action" && (how === "set" || how === "add")) {
+ if (newVal != "summary") {
+ this.element.hide();
+ }
+ }
+ },
+
+ ':type/:id/:action route': function(data) {
+ if (data.type === "poll" && data.action === "summary") {
+ var self = this;
+ $.when(Poll.findOne({id: data.id})).then(
+ function(poll) {
+ self.showSummary(poll);
+ });
+ }
+ },
+
+ showSummary: function(poll) {
+ this.element.html(can.view('views/summary.ejs', {
+ poll: poll
+ }));
+ this.element.show();
+ }
+
+});
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/controls/vote.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,36 @@
+var PollVote = can.Control({
+
+ '{can.route} change': function(data, ev, prop, how, newVal, oldVal ) {
+ if (prop === "type" && (how === "set" || how === "add")) {
+ if (newVal != "poll") {
+ this.element.hide();
+ }
+ } else if (prop === "action" && (how === "set" || how === "add")) {
+ if (newVal != "vote") {
+ this.element.hide();
+ }
+ }
+ },
+
+ ':type/:id/:action route': function(data) {
+ if (data.type === "poll" && data.action === "vote") {
+ var self = this;
+ $.when(Poll.findOne({id: data.id}),
+ Comment.findAll({pollId: data.id}),
+ Vote.findAll({pollId: data.id})).then(
+ function(poll, comments, votes) {
+ self.showPoll(poll, comments, votes);
+ });
+ }
+ },
+
+ showPoll: function(poll, comments, votes) {
+ this.element.html(can.view('views/vote.ejs', {
+ poll: poll,
+ comments: comments,
+ votes: votes
+ }));
+ this.element.show();
+ }
+
+});
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/bootstrap.min.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,6 @@
+/*!
+* Bootstrap.js by @fat & @mdo
+* Copyright 2012 Twitter, Inc.
+* http://www.apache.org/licenses/LICENSE-2.0.txt
+*/
+!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('<div class="dropdown-backdrop"/>').insertBefore(e(this)).on("click",r),s.toggleClass("open")),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f<s.length-1&&f++,~f||(f=0),s.eq(f).focus()}};var s=e.fn.dropdown;e.fn.dropdown=function(t){return this.each(function(){var r=e(this),i=r.data("dropdown");i||r.data("dropdown",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.dropdown.Constructor=n,e.fn.dropdown.noConflict=function(){return e.fn.dropdown=s,this},e(document).on("click.dropdown.data-api",r).on("click.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("click.dropdown.data-api",t,n.prototype.toggle).on("keydown.dropdown.data-api",t+", [role=menu]",n.prototype.keydown)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=n,this.$element=e(t).delegate('[data-dismiss="modal"]',"click.dismiss.modal",e.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};t.prototype={constructor:t,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var t=this,n=e.Event("show");this.$element.trigger(n);if(this.isShown||n.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var n=e.support.transition&&t.$element.hasClass("fade");t.$element.parent().length||t.$element.appendTo(document.body),t.$element.show(),n&&t.$element[0].offsetWidth,t.$element.addClass("in").attr("aria-hidden",!1),t.enforceFocus(),n?t.$element.one(e.support.transition.end,function(){t.$element.focus().trigger("shown")}):t.$element.focus().trigger("shown")})},hide:function(t){t&&t.preventDefault();var n=this;t=e.Event("hide"),this.$element.trigger(t);if(!this.isShown||t.isDefaultPrevented())return;this.isShown=!1,this.escape(),e(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),e.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var t=this;e(document).on("focusin.modal",function(e){t.$element[0]!==e.target&&!t.$element.has(e.target).length&&t.$element.focus()})},escape:function(){var e=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(t){t.which==27&&e.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var t=this,n=setTimeout(function(){t.$element.off(e.support.transition.end),t.hideModal()},500);this.$element.one(e.support.transition.end,function(){clearTimeout(n),t.hideModal()})},hideModal:function(){var e=this;this.$element.hide(),this.backdrop(function(){e.removeBackdrop(),e.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(t){var n=this,r=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var i=e.support.transition&&r;this.$backdrop=e('<div class="modal-backdrop '+r+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e.fn[this.type].defaults,r={},i;this._options&&e.each(this._options,function(e,t){n[e]!=t&&(r[e]=t)},this),i=e(t.currentTarget)[this.type](r).data(this.type);if(!i.options.delay||!i.options.delay.show)return i.show();clearTimeout(this.timeout),i.hoverState="in",this.timeout=setTimeout(function(){i.hoverState=="in"&&i.show()},i.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.fixture.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.fixture.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.fixture.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,614 @@
+/*!
+ * CanJS - 1.1.6
+ * http://canjs.us/
+ * Copyright (c) 2013 Bitovi
+ * Wed, 29 May 2013 18:59:29 GMT
+ * Licensed MIT
+ * Includes: can/util/fixture
+ * Download from: http://canjs.com
+ */
+(function(can) {
+
+ // Get the URL from old Steal root, new Steal config or can.fixture.rootUrl
+ var getUrl = function(url) {
+ if (typeof steal !== 'undefined') {
+ if (can.isFunction(steal.config)) {
+ return steal.config().root.mapJoin(url).toString();
+ }
+ return steal.root.join(url).toString();
+ }
+ return (can.fixture.rootUrl || '') + url;
+ }
+
+ var updateSettings = function(settings, originalOptions) {
+ if (!can.fixture.on) {
+ return;
+ }
+
+ //simple wrapper for logging
+ var _logger = function(type, arr) {
+ if (console.log.apply) {
+ Function.prototype.call.apply(console[type], [console].concat(arr));
+ // console[type].apply(console, arr)
+ } else {
+ console[type](arr)
+ }
+ },
+ log = function() {
+ if (typeof steal !== 'undefined' && steal.dev) {
+ steal.dev.log('fixture INFO: ' + Array.prototype.slice.call(arguments).join(' '));
+ }
+ }
+
+ // We always need the type which can also be called method, default to GET
+ settings.type = settings.type || settings.method || 'GET';
+
+ // add the fixture option if programmed in
+ var data = overwrite(settings);
+
+ // if we don't have a fixture, do nothing
+ if (!settings.fixture) {
+ if (window.location.protocol === "file:") {
+ log("ajax request to " + settings.url + ", no fixture found");
+ }
+ return;
+ }
+
+ //if referencing something else, update the fixture option
+ if (typeof settings.fixture === "string" && can.fixture[settings.fixture]) {
+ settings.fixture = can.fixture[settings.fixture];
+ }
+
+ // if a string, we just point to the right url
+ if (typeof settings.fixture == "string") {
+ var url = settings.fixture;
+
+ if (/^\/\//.test(url)) {
+ // this lets us use rootUrl w/o having steal...
+ url = getUrl(settings.fixture.substr(2));
+ }
+
+ if (data) {
+ // Template static fixture URLs
+ url = can.sub(url, data);
+ }
+
+ delete settings.fixture;
+
+
+
+ settings.url = url;
+ settings.data = null;
+ settings.type = "GET";
+ if (!settings.error) {
+ settings.error = function(xhr, error, message) {
+ throw "fixtures.js Error " + error + " " + message;
+ };
+ }
+ } else {
+
+
+ //it's a function ... add the fixture datatype so our fixture transport handles it
+ // TODO: make everything go here for timing and other fun stuff
+ // add to settings data from fixture ...
+ settings.dataTypes && settings.dataTypes.splice(0, 0, "fixture");
+
+ if (data && originalOptions) {
+ can.extend(originalOptions.data, data)
+ }
+ }
+ },
+ // A helper function that takes what's called with response
+ // and moves some common args around to make it easier to call
+ extractResponse = function(status, statusText, responses, headers) {
+ // if we get response(RESPONSES, HEADERS)
+ if (typeof status != "number") {
+ headers = statusText;
+ responses = status;
+ statusText = "success"
+ status = 200;
+ }
+ // if we get response(200, RESPONSES, HEADERS)
+ if (typeof statusText != "string") {
+ headers = responses;
+ responses = statusText;
+ statusText = "success";
+ }
+ if (status >= 400 && status <= 599) {
+ this.dataType = "text"
+ }
+ return [status, statusText, extractResponses(this, responses), headers];
+ },
+ // If we get data instead of responses,
+ // make sure we provide a response type that matches the first datatype (typically json)
+ extractResponses = function(settings, responses) {
+ var next = settings.dataTypes ? settings.dataTypes[0] : (settings.dataType || 'json');
+ if (!responses || !responses[next]) {
+ var tmp = {}
+ tmp[next] = responses;
+ responses = tmp;
+ }
+ return responses;
+ };
+
+ //used to check urls
+ // check if jQuery
+ if (can.ajaxPrefilter && can.ajaxTransport) {
+
+ // the pre-filter needs to re-route the url
+ can.ajaxPrefilter(updateSettings);
+
+ can.ajaxTransport("fixture", function(s, original) {
+ // remove the fixture from the datatype
+ s.dataTypes.shift();
+
+ //we'll return the result of the next data type
+ var timeout, stopped = false;
+
+ return {
+ send: function(headers, callback) {
+ // we'll immediately wait the delay time for all fixtures
+ timeout = setTimeout(function() {
+ // if the user wants to call success on their own, we allow it ...
+ var success = function() {
+ if (stopped === false) {
+ callback.apply(null, extractResponse.apply(s, arguments));
+ }
+ },
+ // get the result form the fixture
+ result = s.fixture(original, success, headers, s);
+ if (result !== undefined) {
+ // make sure the result has the right dataType
+ callback(200, "success", extractResponses(s, result), {});
+ }
+ }, can.fixture.delay);
+ },
+ abort: function() {
+ stopped = true;
+ clearTimeout(timeout)
+ }
+ };
+ });
+ } else {
+ var AJAX = can.ajax;
+ can.ajax = function(settings) {
+ updateSettings(settings, settings);
+ if (settings.fixture) {
+ var timeout, d = new can.Deferred(),
+ stopped = false;
+
+ //TODO this should work with response
+ d.getResponseHeader = function() {}
+
+ // call success and fail
+ d.then(settings.success, settings.fail);
+
+ // abort should stop the timeout and calling success
+ d.abort = function() {
+ clearTimeout(timeout);
+ stopped = true;
+ d.reject(d)
+ }
+ // set a timeout that simulates making a request ....
+ timeout = setTimeout(function() {
+ // if the user wants to call success on their own, we allow it ...
+ var success = function() {
+ var response = extractResponse.apply(settings, arguments),
+ status = response[0];
+
+ if ((status >= 200 && status < 300 || status === 304) && stopped === false) {
+ d.resolve(response[2][settings.dataType])
+ } else {
+ // TODO probably resolve better
+ d.reject(d, 'error', response[1]);
+ }
+ },
+ // get the result form the fixture
+ result = settings.fixture(settings, success, settings.headers, settings);
+ if (result !== undefined) {
+ d.resolve(result)
+ }
+ }, can.fixture.delay);
+
+ return d;
+ } else {
+ return AJAX(settings);
+ }
+ }
+ }
+
+ var typeTest = /^(script|json|text|jsonp)$/,
+ // a list of 'overwrite' settings object
+ overwrites = [],
+ // returns the index of an overwrite function
+ find = function(settings, exact) {
+ for (var i = 0; i < overwrites.length; i++) {
+ if ($fixture._similar(settings, overwrites[i], exact)) {
+ return i;
+ }
+ }
+ return -1;
+ },
+ // overwrites the settings fixture if an overwrite matches
+ overwrite = function(settings) {
+ var index = find(settings);
+ if (index > -1) {
+ settings.fixture = overwrites[index].fixture;
+ return $fixture._getData(overwrites[index].url, settings.url)
+ }
+
+ },
+ // Makes an attempt to guess where the id is at in the url and returns it.
+ getId = function(settings) {
+ var id = settings.data.id;
+
+ if (id === undefined && typeof settings.data === "number") {
+ id = settings.data;
+ }
+
+
+
+ if (id === undefined) {
+ settings.url.replace(/\/(\d+)(\/|$|\.)/g, function(all, num) {
+ id = num;
+ });
+ }
+
+ if (id === undefined) {
+ id = settings.url.replace(/\/(\w+)(\/|$|\.)/g, function(all, num) {
+ if (num != 'update') {
+ id = num;
+ }
+ })
+ }
+
+ if (id === undefined) { // if still not set, guess a random number
+ id = Math.round(Math.random() * 1000)
+ }
+
+ return id;
+ };
+
+ var $fixture = can.fixture = function(settings, fixture) {
+ // if we provide a fixture ...
+ if (fixture !== undefined) {
+ if (typeof settings == 'string') {
+ // handle url strings
+ var matches = settings.match(/(GET|POST|PUT|DELETE) (.+)/i);
+ if (!matches) {
+ settings = {
+ url: settings
+ };
+ } else {
+ settings = {
+ url: matches[2],
+ type: matches[1]
+ };
+ }
+
+ }
+
+ //handle removing. An exact match if fixture was provided, otherwise, anything similar
+ var index = find(settings, !! fixture);
+ if (index > -1) {
+ overwrites.splice(index, 1)
+ }
+ if (fixture == null) {
+ return
+ }
+ settings.fixture = fixture;
+ overwrites.push(settings)
+ } else {
+ can.each(settings, function(fixture, url) {
+ $fixture(url, fixture);
+ })
+ }
+ };
+ var replacer = can.replacer;
+
+ can.extend(can.fixture, {
+ // given ajax settings, find an overwrite
+ _similar: function(settings, overwrite, exact) {
+ if (exact) {
+ return can.Object.same(settings, overwrite, {
+ fixture: null
+ })
+ } else {
+ return can.Object.subset(settings, overwrite, can.fixture._compare)
+ }
+ },
+ _compare: {
+ url: function(a, b) {
+ return !!$fixture._getData(b, a)
+ },
+ fixture: null,
+ type: "i"
+ },
+ // gets data from a url like "/todo/{id}" given "todo/5"
+ _getData: function(fixtureUrl, url) {
+ var order = [],
+ fixtureUrlAdjusted = fixtureUrl.replace('.', '\\.').replace('?', '\\?'),
+ res = new RegExp(fixtureUrlAdjusted.replace(replacer, function(whole, part) {
+ order.push(part)
+ return "([^\/]+)"
+ }) + "$").exec(url),
+ data = {};
+
+ if (!res) {
+ return null;
+ }
+ res.shift();
+ can.each(order, function(name) {
+ data[name] = res.shift()
+ })
+ return data;
+ },
+
+ store: function(types, count, make, filter) {
+
+ var items = [], // TODO: change this to a hash
+ currentId = 0,
+ findOne = function(id) {
+ for (var i = 0; i < items.length; i++) {
+ if (id == items[i].id) {
+ return items[i];
+ }
+ }
+ },
+ methods = {};
+
+ if (typeof types === "string") {
+ types = [types + "s", types]
+ } else if (!can.isArray(types)) {
+ filter = make;
+ make = count;
+ count = types;
+ }
+
+ // make all items
+ can.extend(methods, {
+
+ findAll: function(request) {
+ request = request || {}
+ //copy array of items
+ var retArr = items.slice(0);
+ request.data = request.data || {};
+ //sort using order
+ //order looks like ["age ASC","gender DESC"]
+ can.each((request.data.order || []).slice(0).reverse(), function(name) {
+ var split = name.split(" ");
+ retArr = retArr.sort(function(a, b) {
+ if (split[1].toUpperCase() !== "ASC") {
+ if (a[split[0]] < b[split[0]]) {
+ return 1;
+ } else if (a[split[0]] == b[split[0]]) {
+ return 0
+ } else {
+ return -1;
+ }
+ } else {
+ if (a[split[0]] < b[split[0]]) {
+ return -1;
+ } else if (a[split[0]] == b[split[0]]) {
+ return 0
+ } else {
+ return 1;
+ }
+ }
+ });
+ });
+
+ //group is just like a sort
+ can.each((request.data.group || []).slice(0).reverse(), function(name) {
+ var split = name.split(" ");
+ retArr = retArr.sort(function(a, b) {
+ return a[split[0]] > b[split[0]];
+ });
+ });
+
+ var offset = parseInt(request.data.offset, 10) || 0,
+ limit = parseInt(request.data.limit, 10) || (items.length - offset),
+ i = 0;
+
+ //filter results if someone added an attr like parentId
+ for (var param in request.data) {
+ i = 0;
+ if (request.data[param] !== undefined && // don't do this if the value of the param is null (ignore it)
+ (param.indexOf("Id") != -1 || param.indexOf("_id") != -1)) {
+ while (i < retArr.length) {
+ if (request.data[param] != retArr[i][param]) {
+ retArr.splice(i, 1);
+ } else {
+ i++;
+ }
+ }
+ }
+ }
+
+ if (filter) {
+ i = 0;
+ while (i < retArr.length) {
+ if (!filter(retArr[i], request)) {
+ retArr.splice(i, 1);
+ } else {
+ i++;
+ }
+ }
+ }
+
+ //return data spliced with limit and offset
+ return {
+ "count": retArr.length,
+ "limit": request.data.limit,
+ "offset": request.data.offset,
+ "data": retArr.slice(offset, offset + limit)
+ };
+ },
+
+ findOne: function(request, response) {
+ var item = findOne(getId(request));
+ response(item ? item : undefined);
+ },
+
+ update: function(request, response) {
+ var id = getId(request);
+
+ // TODO: make it work with non-linear ids ..
+ can.extend(findOne(id), request.data);
+ response({
+ id: getId(request)
+ }, {
+ location: request.url || "/" + getId(request)
+ });
+ },
+
+ destroy: function(request) {
+ var id = getId(request);
+ for (var i = 0; i < items.length; i++) {
+ if (items[i].id == id) {
+ items.splice(i, 1);
+ break;
+ }
+ }
+
+ // TODO: make it work with non-linear ids ..
+ can.extend(findOne(id) || {}, request.data);
+ return {};
+ },
+
+ create: function(settings, response) {
+ var item = make(items.length, items);
+
+ can.extend(item, settings.data);
+
+ if (!item.id) {
+ item.id = currentId++;
+ }
+
+ items.push(item);
+ response({
+ id: item.id
+ }, {
+ location: settings.url + "/" + item.id
+ })
+ }
+ });
+
+ var reset = function() {
+ items = [];
+ for (var i = 0; i < (count); i++) {
+ //call back provided make
+ var item = make(i, items);
+
+ if (!item.id) {
+ item.id = i;
+ }
+ currentId = Math.max(item.id + 1, currentId + 1) || items.length;
+ items.push(item);
+ }
+ if (can.isArray(types)) {
+ can.fixture["~" + types[0]] = items;
+ can.fixture["-" + types[0]] = methods.findAll;
+ can.fixture["-" + types[1]] = methods.findOne;
+ can.fixture["-" + types[1] + "Update"] = methods.update;
+ can.fixture["-" + types[1] + "Destroy"] = methods.destroy;
+ can.fixture["-" + types[1] + "Create"] = methods.create;
+ }
+
+ }
+ reset()
+ // if we have types given add them to can.fixture
+
+
+ return can.extend({
+ getId: getId,
+
+ find: function(settings) {
+ return findOne(getId(settings));
+ },
+
+ reset: reset
+ }, methods);
+ },
+
+ rand: function(arr, min, max) {
+ if (typeof arr == 'number') {
+ if (typeof min == 'number') {
+ return arr + Math.floor(Math.random() * (min - arr));
+ } else {
+ return Math.floor(Math.random() * arr);
+ }
+
+ }
+ var rand = arguments.callee;
+ // get a random set
+ if (min === undefined) {
+ return rand(arr, rand(arr.length + 1))
+ }
+ // get a random selection of arr
+ var res = [];
+ arr = arr.slice(0);
+ // set max
+ if (!max) {
+ max = min;
+ }
+ //random max
+ max = min + Math.round(rand(max - min))
+ for (var i = 0; i < max; i++) {
+ res.push(arr.splice(rand(arr.length), 1)[0])
+ }
+ return res;
+ },
+
+ xhr: function(xhr) {
+ return can.extend({}, {
+ abort: can.noop,
+ getAllResponseHeaders: function() {
+ return "";
+ },
+ getResponseHeader: function() {
+ return "";
+ },
+ open: can.noop,
+ overrideMimeType: can.noop,
+ readyState: 4,
+ responseText: "",
+ responseXML: null,
+ send: can.noop,
+ setRequestHeader: can.noop,
+ status: 200,
+ statusText: "OK"
+ }, xhr);
+ },
+
+ on: true
+ });
+
+ can.fixture.delay = 200;
+
+
+ can.fixture.rootUrl = getUrl('');
+
+ can.fixture["-handleFunction"] = function(settings) {
+ if (typeof settings.fixture === "string" && can.fixture[settings.fixture]) {
+ settings.fixture = can.fixture[settings.fixture];
+ }
+ if (typeof settings.fixture == "function") {
+ setTimeout(function() {
+ if (settings.success) {
+ settings.success.apply(null, settings.fixture(settings, "success"));
+ }
+ if (settings.complete) {
+ settings.complete.apply(null, settings.fixture(settings, "complete"));
+ }
+ }, can.fixture.delay);
+ return true;
+ }
+ return false;
+ };
+
+ //Expose this for fixture debugging
+ can.fixture.overwrites = overwrites;
+ can.fixture.make = can.fixture.store;
+ return can.fixture;
+ })(can);
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,4367 @@
+/*!
+ * CanJS - 1.1.6
+ * http://canjs.us/
+ * Copyright (c) 2013 Bitovi
+ * Wed, 29 May 2013 18:59:27 GMT
+ * Licensed MIT
+ * Includes: can/construct,can/observe,can/observe/compute,can/model,can/view,can/view/ejs,can/control,can/route,can/control/route
+ * Download from: http://canjs.com
+ */
+(function(undefined) {
+
+ // ## util/can.js
+ var __m5 = (function() {
+ var can = window.can || {};
+ if (typeof GLOBALCAN === 'undefined' || GLOBALCAN !== false) {
+ window.can = can;
+ }
+
+ can.isDeferred = function(obj) {
+ var isFunction = this.isFunction;
+ // Returns `true` if something looks like a deferred.
+ return obj && isFunction(obj.then) && isFunction(obj.pipe);
+ };
+
+ var cid = 0;
+ can.cid = function(object, name) {
+ if (object._cid) {
+ return object._cid
+ } else {
+ return object._cid = (name || "") + (++cid)
+ }
+ }
+ can.VERSION = '@EDGE';
+ return can;
+ })();
+
+ // ## util/array/each.js
+ var __m6 = (function(can) {
+ can.each = function(elements, callback, context) {
+ var i = 0,
+ key;
+ if (elements) {
+ if (typeof elements.length === 'number' && elements.pop) {
+ if (elements.attr) {
+ elements.attr('length');
+ }
+ for (key = elements.length; i < key; i++) {
+ if (callback.call(context || elements[i], elements[i], i, elements) === false) {
+ break;
+ }
+ }
+ } else if (elements.hasOwnProperty) {
+ for (key in elements) {
+ if (elements.hasOwnProperty(key)) {
+ if (callback.call(context || elements[key], elements[key], key, elements) === false) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return elements;
+ };
+
+ return can;
+ })(__m5);
+
+ // ## util/jquery/jquery.js
+ var __m3 = (function($, can) {
+ // _jQuery node list._
+ $.extend(can, $, {
+ trigger: function(obj, event, args) {
+ if (obj.trigger) {
+ obj.trigger(event, args);
+ } else {
+ $.event.trigger(event, args, obj, true);
+ }
+ },
+ addEvent: function(ev, cb) {
+ $([this]).bind(ev, cb);
+ return this;
+ },
+ removeEvent: function(ev, cb) {
+ $([this]).unbind(ev, cb);
+ return this;
+ },
+ // jquery caches fragments, we always needs a new one
+ buildFragment: function(elems, context) {
+ var oldFragment = $.buildFragment,
+ ret;
+
+ elems = [elems];
+ // Set context per 1.8 logic
+ context = context || document;
+ context = !context.nodeType && context[0] || context;
+ context = context.ownerDocument || context;
+
+ ret = oldFragment.call(jQuery, elems, context);
+
+ return ret.cacheable ? $.clone(ret.fragment) : ret.fragment || ret;
+ },
+ $: $,
+ each: can.each
+ });
+
+ // Wrap binding functions.
+ $.each(['bind', 'unbind', 'undelegate', 'delegate'], function(i, func) {
+ can[func] = function() {
+ var t = this[func] ? this : $([this]);
+ t[func].apply(t, arguments);
+ return this;
+ };
+ });
+
+ // Wrap modifier functions.
+ $.each(["append", "filter", "addClass", "remove", "data", "get"], function(i, name) {
+ can[name] = function(wrapped) {
+ return wrapped[name].apply(wrapped, can.makeArray(arguments).slice(1));
+ };
+ });
+
+ // Memory safe destruction.
+ var oldClean = $.cleanData;
+
+ $.cleanData = function(elems) {
+ $.each(elems, function(i, elem) {
+ if (elem) {
+ can.trigger(elem, "destroyed", [], false);
+ }
+ });
+ oldClean(elems);
+ };
+
+ return can;
+ })(jQuery, __m5, __m6);
+
+ // ## util/string/string.js
+ var __m2 = (function(can) {
+ // ##string.js
+ // _Miscellaneous string utility functions._
+
+ // Several of the methods in this plugin use code adapated from Prototype
+ // Prototype JavaScript framework, version 1.6.0.1.
+ // © 2005-2007 Sam Stephenson
+ var strUndHash = /_|-/,
+ strColons = /\=\=/,
+ strWords = /([A-Z]+)([A-Z][a-z])/g,
+ strLowUp = /([a-z\d])([A-Z])/g,
+ strDash = /([a-z\d])([A-Z])/g,
+ strReplacer = /\{([^\}]+)\}/g,
+ strQuote = /"/g,
+ strSingleQuote = /'/g,
+
+ // Returns the `prop` property from `obj`.
+ // If `add` is true and `prop` doesn't exist in `obj`, create it as an
+ // empty object.
+ getNext = function(obj, prop, add) {
+ var result = obj[prop];
+
+ if (result === undefined && add === true) {
+ result = obj[prop] = {}
+ }
+ return result
+ },
+
+ // Returns `true` if the object can have properties (no `null`s).
+ isContainer = function(current) {
+ return (/^f|^o/).test(typeof current);
+ };
+
+ can.extend(can, {
+ // Escapes strings for HTML.
+
+ esc: function(content) {
+ // Convert bad values into empty strings
+ var isInvalid = content === null || content === undefined || (isNaN(content) && ("" + content === 'NaN'));
+ return ("" + (isInvalid ? '' : content))
+ .replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(strQuote, '"')
+ .replace(strSingleQuote, "'");
+ },
+
+
+ getObject: function(name, roots, add) {
+
+ // The parts of the name we are looking up
+ // `['App','Models','Recipe']`
+ var parts = name ? name.split('.') : [],
+ length = parts.length,
+ current,
+ r = 0,
+ i, container, rootsLength;
+
+ // Make sure roots is an `array`.
+ roots = can.isArray(roots) ? roots : [roots || window];
+
+ rootsLength = roots.length
+
+ if (!length) {
+ return roots[0];
+ }
+
+ // For each root, mark it as current.
+ for (r; r < rootsLength; r++) {
+ current = roots[r];
+ container = undefined;
+
+ // Walk current to the 2nd to last object or until there
+ // is not a container.
+ for (i = 0; i < length && isContainer(current); i++) {
+ container = current;
+ current = getNext(container, parts[i]);
+ }
+
+ // If we found property break cycle
+ if (container !== undefined && current !== undefined) {
+ break
+ }
+ }
+
+ // Remove property from found container
+ if (add === false && current !== undefined) {
+ delete container[parts[i - 1]]
+ }
+
+ // When adding property add it to the first root
+ if (add === true && current === undefined) {
+ current = roots[0]
+
+ for (i = 0; i < length && isContainer(current); i++) {
+ current = getNext(current, parts[i], true);
+ }
+ }
+
+ return current;
+ },
+ // Capitalizes a string.
+
+ capitalize: function(s, cache) {
+ // Used to make newId.
+ return s.charAt(0).toUpperCase() + s.slice(1);
+ },
+
+ // Underscores a string.
+
+ underscore: function(s) {
+ return s
+ .replace(strColons, '/')
+ .replace(strWords, '$1_$2')
+ .replace(strLowUp, '$1_$2')
+ .replace(strDash, '_')
+ .toLowerCase();
+ },
+ // Micro-templating.
+
+ sub: function(str, data, remove) {
+ var obs = [];
+
+ str = str || '';
+
+ obs.push(str.replace(strReplacer, function(whole, inside) {
+
+ // Convert inside to type.
+ var ob = can.getObject(inside, data, remove === true ? false : undefined);
+
+ if (ob === undefined) {
+ obs = null;
+ return "";
+ }
+
+ // If a container, push into objs (which will return objects found).
+ if (isContainer(ob) && obs) {
+ obs.push(ob);
+ return "";
+ }
+
+ return "" + ob;
+ }));
+
+ return obs === null ? obs : (obs.length <= 1 ? obs[0] : obs);
+ },
+
+ // These regex's are used throughout the rest of can, so let's make
+ // them available.
+ replacer: strReplacer,
+ undHash: strUndHash
+ });
+ return can;
+ })(__m3);
+
+ // ## construct/construct.js
+ var __m1 = (function(can) {
+
+ // ## construct.js
+ // `can.Construct`
+ // _This is a modified version of
+ // [John Resig's class](http://ejohn.org/blog/simple-javascript-inheritance/).
+ // It provides class level inheritance and callbacks._
+
+ // A private flag used to initialize a new class instance without
+ // initializing it's bindings.
+ var initializing = 0;
+
+
+ can.Construct = function() {
+ if (arguments.length) {
+ return can.Construct.extend.apply(can.Construct, arguments);
+ }
+ };
+
+
+ can.extend(can.Construct, {
+
+ newInstance: function() {
+ // Get a raw instance object (`init` is not called).
+ var inst = this.instance(),
+ arg = arguments,
+ args;
+
+ // Call `setup` if there is a `setup`
+ if (inst.setup) {
+ args = inst.setup.apply(inst, arguments);
+ }
+
+ // Call `init` if there is an `init`
+ // If `setup` returned `args`, use those as the arguments
+ if (inst.init) {
+ inst.init.apply(inst, args || arguments);
+ }
+
+ return inst;
+ },
+ // Overwrites an object with methods. Used in the `super` plugin.
+ // `newProps` - New properties to add.
+ // `oldProps` - Where the old properties might be (used with `super`).
+ // `addTo` - What we are adding to.
+ _inherit: function(newProps, oldProps, addTo) {
+ can.extend(addTo || newProps, newProps || {})
+ },
+ // used for overwriting a single property.
+ // this should be used for patching other objects
+ // the super plugin overwrites this
+ _overwrite: function(what, oldProps, propName, val) {
+ what[propName] = val;
+ },
+ // Set `defaults` as the merger of the parent `defaults` and this
+ // object's `defaults`. If you overwrite this method, make sure to
+ // include option merging logic.
+
+ setup: function(base, fullName) {
+ this.defaults = can.extend(true, {}, base.defaults, this.defaults);
+ },
+ // Create's a new `class` instance without initializing by setting the
+ // `initializing` flag.
+ instance: function() {
+
+ // Prevents running `init`.
+ initializing = 1;
+
+ var inst = new this();
+
+ // Allow running `init`.
+ initializing = 0;
+
+ return inst;
+ },
+ // Extends classes.
+
+ extend: function(fullName, klass, proto) {
+ // Figure out what was passed and normalize it.
+ if (typeof fullName != 'string') {
+ proto = klass;
+ klass = fullName;
+ fullName = null;
+ }
+
+ if (!proto) {
+ proto = klass;
+ klass = null;
+ }
+ proto = proto || {};
+
+ var _super_class = this,
+ _super = this.prototype,
+ name, shortName, namespace, prototype;
+
+ // Instantiate a base class (but only create the instance,
+ // don't run the init constructor).
+ prototype = this.instance();
+
+ // Copy the properties over onto the new prototype.
+ can.Construct._inherit(proto, _super, prototype);
+
+ // The dummy class constructor.
+
+ function Constructor() {
+ // All construction is actually done in the init method.
+ if (!initializing) {
+ return this.constructor !== Constructor && arguments.length ?
+ // We are being called without `new` or we are extending.
+ arguments.callee.extend.apply(arguments.callee, arguments) :
+ // We are being called with `new`.
+ this.constructor.newInstance.apply(this.constructor, arguments);
+ }
+ }
+
+ // Copy old stuff onto class (can probably be merged w/ inherit)
+ for (name in _super_class) {
+ if (_super_class.hasOwnProperty(name)) {
+ Constructor[name] = _super_class[name];
+ }
+ }
+
+ // Copy new static properties on class.
+ can.Construct._inherit(klass, _super_class, Constructor);
+
+ // Setup namespaces.
+ if (fullName) {
+
+ var parts = fullName.split('.'),
+ shortName = parts.pop(),
+ current = can.getObject(parts.join('.'), window, true),
+ namespace = current,
+ _fullName = can.underscore(fullName.replace(/\./g, "_")),
+ _shortName = can.underscore(shortName);
+
+
+
+ current[shortName] = Constructor;
+ }
+
+ // Set things that shouldn't be overwritten.
+ can.extend(Constructor, {
+ constructor: Constructor,
+ prototype: prototype,
+
+ namespace: namespace,
+
+ _shortName: _shortName,
+
+ fullName: fullName,
+ _fullName: _fullName
+ });
+
+ // Dojo and YUI extend undefined
+ if (shortName !== undefined) {
+ Constructor.shortName = shortName;
+ }
+
+ // Make sure our prototype looks nice.
+ Constructor.prototype.constructor = Constructor;
+
+
+ // Call the class `setup` and `init`
+ var t = [_super_class].concat(can.makeArray(arguments)),
+ args = Constructor.setup.apply(Constructor, t);
+
+ if (Constructor.init) {
+ Constructor.init.apply(Constructor, args || t);
+ }
+
+
+ return Constructor;
+
+ }
+
+ });
+ return can.Construct;
+ })(__m2);
+
+ // ## util/bind/bind.js
+ var __m8 = (function(can) {
+
+
+ // ## Bind helpers
+ can.bindAndSetup = function() {
+ // Add the event to this object
+ can.addEvent.apply(this, arguments);
+ // If not initializing, and the first binding
+ // call bindsetup if the function exists.
+ if (!this._init) {
+ if (!this._bindings) {
+ this._bindings = 1;
+ // setup live-binding
+ this._bindsetup && this._bindsetup();
+
+ } else {
+ this._bindings++;
+ }
+
+ }
+
+ return this;
+ };
+
+ can.unbindAndTeardown = function(ev, handler) {
+ // Remove the event handler
+ can.removeEvent.apply(this, arguments);
+
+ this._bindings--;
+ // If there are no longer any bindings and
+ // there is a bindteardown method, call it.
+ if (!this._bindings) {
+ this._bindteardown && this._bindteardown();
+ }
+ return this;
+ }
+
+ return can;
+
+ })(__m3);
+
+ // ## observe/observe.js
+ var __m7 = (function(can, bind) {
+ // ## observe.js
+ // `can.Observe`
+ // _Provides the observable pattern for JavaScript Objects._
+ // Returns `true` if something is an object with properties of its own.
+ var canMakeObserve = function(obj) {
+ return obj && !can.isDeferred(obj) && (can.isArray(obj) || can.isPlainObject(obj) || (obj instanceof can.Observe));
+ },
+
+ // Removes all listeners.
+ unhookup = function(items, namespace) {
+ return can.each(items, function(item) {
+ if (item && item.unbind) {
+ item.unbind("change" + namespace);
+ }
+ });
+ },
+ // Listens to changes on `child` and "bubbles" the event up.
+ // `child` - The object to listen for changes on.
+ // `prop` - The property name is at on.
+ // `parent` - The parent object of prop.
+ // `ob` - (optional) The Observe object constructor
+ // `list` - (optional) The observable list constructor
+ hookupBubble = function(child, prop, parent, Ob, List) {
+ Ob = Ob || Observe;
+ List = List || Observe.List;
+
+ // If it's an `array` make a list, otherwise a child.
+ if (child instanceof Observe) {
+ // We have an `observe` already...
+ // Make sure it is not listening to this already
+ // It's only listening if it has bindings already.
+ parent._bindings && unhookup([child], parent._cid);
+ } else if (can.isArray(child)) {
+ child = new List(child);
+ } else {
+ child = new Ob(child);
+ }
+ // only listen if something is listening to you
+ if (parent._bindings) {
+ // Listen to all changes and `batchTrigger` upwards.
+ bindToChildAndBubbleToParent(child, prop, parent)
+ }
+
+
+ return child;
+ },
+ bindToChildAndBubbleToParent = function(child, prop, parent) {
+ child.bind("change" + parent._cid, function() {
+ // `batchTrigger` the type on this...
+ var args = can.makeArray(arguments),
+ ev = args.shift();
+ args[0] = (prop === "*" ? [parent.indexOf(child), args[0]] : [prop, args[0]]).join(".");
+
+ // track objects dispatched on this observe
+ ev.triggeredNS = ev.triggeredNS || {};
+
+ // if it has already been dispatched exit
+ if (ev.triggeredNS[parent._cid]) {
+ return;
+ }
+
+ ev.triggeredNS[parent._cid] = true;
+ // send change event with modified attr to parent
+ can.trigger(parent, ev, args);
+ // send modified attr event to parent
+ //can.trigger(parent, args[0], args);
+ });
+ }
+ // An `id` to track events for a given observe.
+ observeId = 0,
+ // A helper used to serialize an `Observe` or `Observe.List`.
+ // `observe` - The observable.
+ // `how` - To serialize with `attr` or `serialize`.
+ // `where` - To put properties, in an `{}` or `[]`.
+ serialize = function(observe, how, where) {
+ // Go through each property.
+ observe.each(function(val, name) {
+ // If the value is an `object`, and has an `attrs` or `serialize` function.
+ where[name] = canMakeObserve(val) && can.isFunction(val[how]) ?
+ // Call `attrs` or `serialize` to get the original data back.
+ val[how]() :
+ // Otherwise return the value.
+ val;
+ });
+ return where;
+ },
+ attrParts = function(attr, keepKey) {
+ if (keepKey) {
+ return [attr];
+ }
+ return can.isArray(attr) ? attr : ("" + attr).split(".");
+ },
+ // Which batch of events this is for -- might not want to send multiple
+ // messages on the same batch. This is mostly for event delegation.
+ batchNum = 1,
+ // how many times has start been called without a stop
+ transactions = 0,
+ // an array of events within a transaction
+ batchEvents = [],
+ stopCallbacks = [],
+ makeBindSetup = function(wildcard) {
+ return function() {
+ var parent = this;
+ this._each(function(child, prop) {
+ if (child && child.bind) {
+ bindToChildAndBubbleToParent(child, wildcard || prop, parent)
+ }
+ })
+ };
+ };
+
+
+ var Observe = can.Map = can.Observe = can.Construct({
+
+ // keep so it can be overwritten
+ bind: can.bindAndSetup,
+ unbind: can.unbindAndTeardown,
+ id: "id",
+ canMakeObserve: canMakeObserve,
+ // starts collecting events
+ // takes a callback for after they are updated
+ // how could you hook into after ejs
+
+ startBatch: function(batchStopHandler) {
+ transactions++;
+ batchStopHandler && stopCallbacks.push(batchStopHandler);
+ },
+
+ stopBatch: function(force, callStart) {
+ if (force) {
+ transactions = 0;
+ } else {
+ transactions--;
+ }
+
+ if (transactions == 0) {
+ var items = batchEvents.slice(0),
+ callbacks = stopCallbacks.slice(0);
+ batchEvents = [];
+ stopCallbacks = [];
+ batchNum++;
+ callStart && this.startBatch();
+ can.each(items, function(args) {
+ can.trigger.apply(can, args);
+ });
+ can.each(callbacks, function(cb) {
+ cb();
+ });
+ }
+ },
+
+ triggerBatch: function(item, event, args) {
+ // Don't send events if initalizing.
+ if (!item._init) {
+ if (transactions == 0) {
+ return can.trigger(item, event, args);
+ } else {
+ event = typeof event === "string" ? {
+ type: event
+ } :
+ event;
+ event.batchNum = batchNum;
+ batchEvents.push([
+ item,
+ event,
+ args
+ ]);
+ }
+ }
+ },
+
+ keys: function(observe) {
+ var keys = [];
+ Observe.__reading && Observe.__reading(observe, '__keys');
+ for (var keyName in observe._data) {
+ keys.push(keyName);
+ }
+ return keys;
+ }
+ },
+
+ {
+ setup: function(obj) {
+ // `_data` is where we keep the properties.
+ this._data = {};
+
+ // The namespace this `object` uses to listen to events.
+ can.cid(this, ".observe");
+ // Sets all `attrs`.
+ this._init = 1;
+ this.attr(obj);
+ this.bind('change' + this._cid, can.proxy(this._changes, this));
+ delete this._init;
+ },
+ _bindsetup: makeBindSetup(),
+ _bindteardown: function() {
+ var cid = this._cid;
+ this._each(function(child) {
+ unhookup([child], cid)
+ })
+ },
+ _changes: function(ev, attr, how, newVal, oldVal) {
+ Observe.triggerBatch(this, {
+ type: attr,
+ batchNum: ev.batchNum
+ }, [newVal, oldVal]);
+ },
+ _triggerChange: function(attr, how, newVal, oldVal) {
+ Observe.triggerBatch(this, "change", can.makeArray(arguments))
+ },
+ // no live binding iterator
+ _each: function(callback) {
+ var data = this.__get();
+ for (var prop in data) {
+ if (data.hasOwnProperty(prop)) {
+ callback(data[prop], prop)
+ }
+ }
+ },
+
+ attr: function(attr, val) {
+ // This is super obfuscated for space -- basically, we're checking
+ // if the type of the attribute is not a `number` or a `string`.
+ var type = typeof attr;
+ if (type !== "string" && type !== "number") {
+ return this._attrs(attr, val)
+ } else if (val === undefined) { // If we are getting a value.
+ // Let people know we are reading.
+ Observe.__reading && Observe.__reading(this, attr)
+ return this._get(attr)
+ } else {
+ // Otherwise we are setting.
+ this._set(attr, val);
+ return this;
+ }
+ },
+
+ each: function() {
+ Observe.__reading && Observe.__reading(this, '__keys');
+ return can.each.apply(undefined, [this.__get()].concat(can.makeArray(arguments)))
+ },
+
+ removeAttr: function(attr) {
+ // Info if this is List or not
+ var isList = this instanceof can.Observe.List,
+ // Convert the `attr` into parts (if nested).
+ parts = attrParts(attr),
+ // The actual property to remove.
+ prop = parts.shift(),
+ // The current value.
+ current = isList ? this[prop] : this._data[prop];
+
+ // If we have more parts, call `removeAttr` on that part.
+ if (parts.length) {
+ return current.removeAttr(parts)
+ } else {
+ if (isList) {
+ this.splice(prop, 1)
+ } else if (prop in this._data) {
+ // Otherwise, `delete`.
+ delete this._data[prop];
+ // Create the event.
+ if (!(prop in this.constructor.prototype)) {
+ delete this[prop]
+ }
+ // Let others know the number of keys have changed
+ Observe.triggerBatch(this, "__keys");
+ this._triggerChange(prop, "remove", undefined, current);
+
+ }
+ return current;
+ }
+ },
+ // Reads a property from the `object`.
+ _get: function(attr) {
+ var value = typeof attr === 'string' && !! ~attr.indexOf('.') && this.__get(attr);
+ if (value) {
+ return value;
+ }
+
+ // break up the attr (`"foo.bar"`) into `["foo","bar"]`
+ var parts = attrParts(attr),
+ // get the value of the first attr name (`"foo"`)
+ current = this.__get(parts.shift());
+ // if there are other attributes to read
+ return parts.length ?
+ // and current has a value
+ current ?
+ // lookup the remaining attrs on current
+ current._get(parts) :
+ // or if there's no current, return undefined
+ undefined :
+ // if there are no more parts, return current
+ current;
+ },
+ // Reads a property directly if an `attr` is provided, otherwise
+ // returns the "real" data object itself.
+ __get: function(attr) {
+ return attr ? this._data[attr] : this._data;
+ },
+ // Sets `attr` prop as value on this object where.
+ // `attr` - Is a string of properties or an array of property values.
+ // `value` - The raw value to set.
+ _set: function(attr, value, keepKey) {
+ // Convert `attr` to attr parts (if it isn't already).
+ var parts = attrParts(attr, keepKey),
+ // The immediate prop we are setting.
+ prop = parts.shift(),
+ // The current value.
+ current = this.__get(prop);
+
+ // If we have an `object` and remaining parts.
+ if (canMakeObserve(current) && parts.length) {
+ // That `object` should set it (this might need to call attr).
+ current._set(parts, value)
+ } else if (!parts.length) {
+ // We're in "real" set territory.
+ if (this.__convert) {
+ value = this.__convert(prop, value)
+ }
+ this.__set(prop, value, current)
+ } else {
+ throw "can.Observe: Object does not exist"
+ }
+ },
+ __set: function(prop, value, current) {
+
+ // Otherwise, we are setting it on this `object`.
+ // TODO: Check if value is object and transform
+ // are we changing the value.
+ if (value !== current) {
+ // Check if we are adding this for the first time --
+ // if we are, we need to create an `add` event.
+ var changeType = this.__get().hasOwnProperty(prop) ? "set" : "add";
+
+ // Set the value on data.
+ this.___set(prop,
+
+ // If we are getting an object.
+ canMakeObserve(value) ?
+
+ // Hook it up to send event.
+ hookupBubble(value, prop, this) :
+ // Value is normal.
+ value);
+
+ if (changeType == "add") {
+ // If there is no current value, let others know that
+ // the the number of keys have changed
+
+ Observe.triggerBatch(this, "__keys", undefined);
+
+ }
+ // `batchTrigger` the change event.
+ this._triggerChange(prop, changeType, value, current);
+
+ //Observe.triggerBatch(this, prop, [value, current]);
+ // If we can stop listening to our old value, do it.
+ current && unhookup([current], this._cid);
+ }
+
+ },
+ // Directly sets a property on this `object`.
+ ___set: function(prop, val) {
+ this._data[prop] = val;
+ // Add property directly for easy writing.
+ // Check if its on the `prototype` so we don't overwrite methods like `attrs`.
+ if (!(prop in this.constructor.prototype)) {
+ this[prop] = val
+ }
+ },
+
+
+ bind: can.bindAndSetup,
+
+ unbind: can.unbindAndTeardown,
+
+ serialize: function() {
+ return serialize(this, 'serialize', {});
+ },
+
+ _attrs: function(props, remove) {
+
+ if (props === undefined) {
+ return serialize(this, 'attr', {})
+ }
+
+ props = can.extend({}, props);
+ var prop,
+ self = this,
+ newVal;
+ Observe.startBatch();
+ this.each(function(curVal, prop) {
+ newVal = props[prop];
+
+ // If we are merging...
+ if (newVal === undefined) {
+ remove && self.removeAttr(prop);
+ return;
+ }
+
+ if (self.__convert) {
+ newVal = self.__convert(prop, newVal)
+ }
+
+ // if we're dealing with models, want to call _set to let converter run
+ if (newVal instanceof can.Observe) {
+ self.__set(prop, newVal, curVal)
+ // if its an object, let attr merge
+ } else if (canMakeObserve(curVal) && canMakeObserve(newVal) && curVal.attr) {
+ curVal.attr(newVal, remove)
+ // otherwise just set
+ } else if (curVal != newVal) {
+ self.__set(prop, newVal, curVal)
+ }
+
+ delete props[prop];
+ })
+ // Add remaining props.
+ for (var prop in props) {
+ newVal = props[prop];
+ this._set(prop, newVal, true)
+ }
+ Observe.stopBatch()
+ return this;
+ },
+
+
+ compute: function(prop) {
+ return can.compute(this, prop);
+ }
+ });
+ // Helpers for `observable` lists.
+ var splice = [].splice,
+
+ list = Observe(
+
+ {
+ setup: function(instances, options) {
+ this.length = 0;
+ can.cid(this, ".observe")
+ this._init = 1;
+ if (can.isDeferred(instances)) {
+ this.replace(instances)
+ } else {
+ this.push.apply(this, can.makeArray(instances || []));
+ }
+ // this change needs to be ignored
+ this.bind('change' + this._cid, can.proxy(this._changes, this));
+ can.extend(this, options);
+ delete this._init;
+ },
+ _triggerChange: function(attr, how, newVal, oldVal) {
+
+ Observe.prototype._triggerChange.apply(this, arguments)
+ // `batchTrigger` direct add and remove events...
+ if (!~attr.indexOf('.')) {
+
+ if (how === 'add') {
+ Observe.triggerBatch(this, how, [newVal, +attr]);
+ Observe.triggerBatch(this, 'length', [this.length]);
+ } else if (how === 'remove') {
+ Observe.triggerBatch(this, how, [oldVal, +attr]);
+ Observe.triggerBatch(this, 'length', [this.length]);
+ } else {
+ Observe.triggerBatch(this, how, [newVal, +attr])
+ }
+
+ }
+
+ },
+ __get: function(attr) {
+ return attr ? this[attr] : this;
+ },
+ ___set: function(attr, val) {
+ this[attr] = val;
+ if (+attr >= this.length) {
+ this.length = (+attr + 1)
+ }
+ },
+ _each: function(callback) {
+ var data = this.__get();
+ for (var i = 0; i < data.length; i++) {
+ callback(data[i], i)
+ }
+ },
+ _bindsetup: makeBindSetup("*"),
+ // Returns the serialized form of this list.
+
+ serialize: function() {
+ return serialize(this, 'serialize', []);
+ },
+
+ splice: function(index, howMany) {
+ var args = can.makeArray(arguments),
+ i;
+
+ for (i = 2; i < args.length; i++) {
+ var val = args[i];
+ if (canMakeObserve(val)) {
+ args[i] = hookupBubble(val, "*", this, this.constructor.Observe, this.constructor)
+ }
+ }
+ if (howMany === undefined) {
+ howMany = args[1] = this.length - index;
+ }
+ var removed = splice.apply(this, args);
+ can.Observe.startBatch();
+ if (howMany > 0) {
+ this._triggerChange("" + index, "remove", undefined, removed);
+ unhookup(removed, this._cid);
+ }
+ if (args.length > 2) {
+ this._triggerChange("" + index, "add", args.slice(2), removed);
+ }
+ can.Observe.stopBatch();
+ return removed;
+ },
+
+ _attrs: function(items, remove) {
+ if (items === undefined) {
+ return serialize(this, 'attr', []);
+ }
+
+ // Create a copy.
+ items = can.makeArray(items);
+
+ Observe.startBatch();
+ this._updateAttrs(items, remove);
+ Observe.stopBatch()
+ },
+
+ _updateAttrs: function(items, remove) {
+ var len = Math.min(items.length, this.length);
+
+ for (var prop = 0; prop < len; prop++) {
+ var curVal = this[prop],
+ newVal = items[prop];
+
+ if (canMakeObserve(curVal) && canMakeObserve(newVal)) {
+ curVal.attr(newVal, remove)
+ } else if (curVal != newVal) {
+ this._set(prop, newVal)
+ } else {
+
+ }
+ }
+ if (items.length > this.length) {
+ // Add in the remaining props.
+ this.push.apply(this, items.slice(this.length));
+ } else if (items.length < this.length && remove) {
+ this.splice(items.length)
+ }
+ }
+ }),
+
+ // Converts to an `array` of arguments.
+ getArgs = function(args) {
+ return args[0] && can.isArray(args[0]) ?
+ args[0] :
+ can.makeArray(args);
+ };
+ // Create `push`, `pop`, `shift`, and `unshift`
+ can.each({
+
+ push: "length",
+
+ unshift: 0
+ },
+ // Adds a method
+ // `name` - The method name.
+ // `where` - Where items in the `array` should be added.
+
+ function(where, name) {
+ var orig = [][name]
+ list.prototype[name] = function() {
+ // Get the items being added.
+ var args = [],
+ // Where we are going to add items.
+ len = where ? this.length : 0,
+ i = arguments.length,
+ res,
+ val,
+ constructor = this.constructor;
+
+ // Go through and convert anything to an `observe` that needs to be converted.
+ while (i--) {
+ val = arguments[i];
+ args[i] = canMakeObserve(val) ?
+ hookupBubble(val, "*", this, this.constructor.Observe, this.constructor) :
+ val;
+ }
+
+ // Call the original method.
+ res = orig.apply(this, args);
+
+ if (!this.comparator || args.length) {
+
+ this._triggerChange("" + len, "add", args, undefined);
+ }
+
+ return res;
+ }
+ });
+
+ can.each({
+
+ pop: "length",
+
+ shift: 0
+ },
+ // Creates a `remove` type method
+
+ function(where, name) {
+ list.prototype[name] = function() {
+
+ var args = getArgs(arguments),
+ len = where && this.length ? this.length - 1 : 0;
+
+ var res = [][name].apply(this, args)
+
+ // Create a change where the args are
+ // `len` - Where these items were removed.
+ // `remove` - Items removed.
+ // `undefined` - The new values (there are none).
+ // `res` - The old, removed values (should these be unbound).
+ this._triggerChange("" + len, "remove", undefined, [res])
+
+ if (res && res.unbind) {
+ res.unbind("change" + this._cid)
+ }
+ return res;
+ }
+ });
+
+ can.extend(list.prototype, {
+
+ indexOf: function(item) {
+ this.attr('length')
+ return can.inArray(item, this)
+ },
+
+
+ join: [].join,
+
+
+ reverse: [].reverse,
+
+
+ slice: function() {
+ var temp = Array.prototype.slice.apply(this, arguments);
+ return new this.constructor(temp);
+ },
+
+
+ concat: function() {
+ var args = [];
+ can.each(can.makeArray(arguments), function(arg, i) {
+ args[i] = arg instanceof can.Observe.List ? arg.serialize() : arg;
+ });
+ return new this.constructor(Array.prototype.concat.apply(this.serialize(), args));
+ },
+
+
+ forEach: function(cb, thisarg) {
+ can.each(this, cb, thisarg || this);
+ },
+
+
+ replace: function(newList) {
+ if (can.isDeferred(newList)) {
+ newList.then(can.proxy(this.replace, this));
+ } else {
+ this.splice.apply(this, [0, this.length].concat(can.makeArray(newList || [])));
+ }
+
+ return this;
+ }
+ });
+
+ can.List = Observe.List = list;
+ Observe.setup = function() {
+ can.Construct.setup.apply(this, arguments);
+ // I would prefer not to do it this way. It should
+ // be using the attributes plugin to do this type of conversion.
+ this.List = Observe.List({
+ Observe: this
+ }, {});
+ }
+ return Observe;
+ })(__m3, __m8, __m1);
+
+ // ## observe/compute/compute.js
+ var __m9 = (function(can, bind) {
+
+ // returns the
+ // - observes and attr methods are called by func
+ // - the value returned by func
+ // ex: `{value: 100, observed: [{obs: o, attr: "completed"}]}`
+ var getValueAndObserved = function(func, self) {
+
+ var oldReading;
+ if (can.Observe) {
+ // Set a callback on can.Observe to know
+ // when an attr is read.
+ // Keep a reference to the old reader
+ // if there is one. This is used
+ // for nested live binding.
+ oldReading = can.Observe.__reading;
+ can.Observe.__reading = function(obj, attr) {
+ // Add the observe and attr that was read
+ // to `observed`
+ observed.push({
+ obj: obj,
+ attr: attr + ""
+ });
+ };
+ }
+
+ var observed = [],
+ // Call the "wrapping" function to get the value. `observed`
+ // will have the observe/attribute pairs that were read.
+ value = func.call(self);
+
+ // Set back so we are no longer reading.
+ if (can.Observe) {
+ can.Observe.__reading = oldReading;
+ }
+ return {
+ value: value,
+ observed: observed
+ };
+ },
+ // Calls `callback(newVal, oldVal)` everytime an observed property
+ // called within `getterSetter` is changed and creates a new result of `getterSetter`.
+ // Also returns an object that can teardown all event handlers.
+ computeBinder = function(getterSetter, context, callback, computeState) {
+ // track what we are observing
+ var observing = {},
+ // a flag indicating if this observe/attr pair is already bound
+ matched = true,
+ // the data to return
+ data = {
+ // we will maintain the value while live-binding is taking place
+ value: undefined,
+ // a teardown method that stops listening
+ teardown: function() {
+ for (var name in observing) {
+ var ob = observing[name];
+ ob.observe.obj.unbind(ob.observe.attr, onchanged);
+ delete observing[name];
+ }
+ }
+ },
+ batchNum;
+
+ // when a property value is changed
+ var onchanged = function(ev) {
+ // If the compute is no longer bound (because the same change event led to an unbind)
+ // then do not call getValueAndBind, or we will leak bindings.
+ if (computeState && !computeState.bound) {
+ return;
+ }
+ if (ev.batchNum === undefined || ev.batchNum !== batchNum) {
+ // store the old value
+ var oldValue = data.value,
+ // get the new value
+ newvalue = getValueAndBind();
+
+ // update the value reference (in case someone reads)
+ data.value = newvalue;
+ // if a change happened
+ if (newvalue !== oldValue) {
+ callback(newvalue, oldValue);
+ }
+ batchNum = batchNum = ev.batchNum;
+ }
+
+
+ };
+
+ // gets the value returned by `getterSetter` and also binds to any attributes
+ // read by the call
+ var getValueAndBind = function() {
+ var info = getValueAndObserved(getterSetter, context),
+ newObserveSet = info.observed;
+
+ var value = info.value;
+ matched = !matched;
+
+ // go through every attribute read by this observe
+ can.each(newObserveSet, function(ob) {
+ // if the observe/attribute pair is being observed
+ if (observing[ob.obj._cid + "|" + ob.attr]) {
+ // mark at as observed
+ observing[ob.obj._cid + "|" + ob.attr].matched = matched;
+ } else {
+ // otherwise, set the observe/attribute on oldObserved, marking it as being observed
+ observing[ob.obj._cid + "|" + ob.attr] = {
+ matched: matched,
+ observe: ob
+ };
+ ob.obj.bind(ob.attr, onchanged);
+ }
+ });
+
+ // Iterate through oldObserved, looking for observe/attributes
+ // that are no longer being bound and unbind them
+ for (var name in observing) {
+ var ob = observing[name];
+ if (ob.matched !== matched) {
+ ob.observe.obj.unbind(ob.observe.attr, onchanged);
+ delete observing[name];
+ }
+ }
+ return value;
+ };
+ // set the initial value
+ data.value = getValueAndBind();
+
+ data.isListening = !can.isEmptyObject(observing);
+ return data;
+ }
+
+ // if no one is listening ... we can not calculate every time
+
+ can.compute = function(getterSetter, context, eventName) {
+ if (getterSetter && getterSetter.isComputed) {
+ return getterSetter;
+ }
+ // stores the result of computeBinder
+ var computedData,
+ // how many listeners to this this compute
+ bindings = 0,
+ // the computed object
+ computed,
+ // an object that keeps track if the computed is bound
+ // onchanged needs to know this. It's possible a change happens and results in
+ // something that unbinds the compute, it needs to not to try to recalculate who it
+ // is listening to
+ computeState = {
+ bound: false,
+ // true if this compute is calculated from other computes and observes
+ hasDependencies: false
+ },
+ // The following functions are overwritten depending on how compute() is called
+ // a method to setup listening
+ on = function() {},
+ // a method to teardown listening
+ off = function() {},
+ // the current cached value (only valid if bound = true)
+ value,
+ // how to read the value
+ get = function() {
+ return value
+ },
+ // sets the value
+ set = function(newVal) {
+ value = newVal;
+ },
+ // this compute can be a dependency of other computes
+ canReadForChangeEvent = true;
+
+ computed = function(newVal) {
+ // setting ...
+ if (arguments.length) {
+ // save a reference to the old value
+ var old = value;
+
+ // setter may return a value if
+ // setter is for a value maintained exclusively by this compute
+ var setVal = set.call(context, newVal, old);
+
+ // if this has dependencies return the current value
+ if (computed.hasDependencies) {
+ return get.call(context);
+ }
+
+ if (setVal === undefined) {
+ // it's possible, like with the DOM, setting does not
+ // fire a change event, so we must read
+ value = get.call(context);
+ } else {
+ value = setVal;
+ }
+ // fire the change
+ if (old !== value) {
+ can.Observe.triggerBatch(computed, "change", [value, old]);
+ }
+ return value;
+ } else {
+ // Let others know to listen to changes in this compute
+ if (can.Observe.__reading && canReadForChangeEvent) {
+ can.Observe.__reading(computed, 'change');
+ }
+ // if we are bound, use the cached value
+ if (computeState.bound) {
+ return value;
+ } else {
+ return get.call(context);
+ }
+ }
+ }
+ if (typeof getterSetter === "function") {
+ set = getterSetter;
+ get = getterSetter;
+ canReadForChangeEvent = eventName === false ? false : true;
+ computed.hasDependencies = false;
+ on = function(update) {
+ computedData = computeBinder(getterSetter, context || this, update, computeState);
+ computed.hasDependencies = computedData.isListening
+ value = computedData.value;
+ }
+ off = function() {
+ computedData.teardown();
+ }
+ } else if (context) {
+
+ if (typeof context == "string") {
+ // `can.compute(obj, "propertyName", [eventName])`
+
+ var propertyName = context,
+ isObserve = getterSetter instanceof can.Observe;
+ if (isObserve) {
+ computed.hasDependencies = true;
+ }
+ get = function() {
+ if (isObserve) {
+ return getterSetter.attr(propertyName);
+ } else {
+ return getterSetter[propertyName];
+ }
+ }
+ set = function(newValue) {
+ if (isObserve) {
+ getterSetter.attr(propertyName, newValue)
+ } else {
+ getterSetter[propertyName] = newValue;
+ }
+ }
+ var handler;
+ on = function(update) {
+ handler = function() {
+ update(get(), value)
+ };
+ can.bind.call(getterSetter, eventName || propertyName, handler)
+
+ // use getValueAndObserved because
+ // we should not be indicating that some parent
+ // reads this property if it happens to be binding on it
+ value = getValueAndObserved(get).value
+ }
+ off = function() {
+ can.unbind.call(getterSetter, eventName || propertyName, handler)
+ }
+
+ } else {
+ // `can.compute(initialValue, setter)`
+ if (typeof context === "function") {
+ value = getterSetter;
+ set = context;
+ } else {
+ // `can.compute(initialValue,{get:, set:, on:, off:})`
+ value = getterSetter;
+ var options = context;
+ get = options.get || get;
+ set = options.set || set;
+ on = options.on || on;
+ off = options.off || off;
+ }
+
+ }
+
+
+
+ } else {
+ // `can.compute(5)`
+ value = getterSetter;
+ }
+
+ computed.isComputed = true;
+
+ can.cid(computed, "compute")
+
+ var updater = function(newValue, oldValue) {
+ value = newValue;
+ // might need a way to look up new and oldVal
+ can.Observe.triggerBatch(computed, "change", [newValue, oldValue])
+ }
+
+ return can.extend(computed, {
+ _bindsetup: function() {
+ computeState.bound = true;
+ // setup live-binding
+ on.call(this, updater)
+ },
+ _bindteardown: function() {
+ off.call(this, updater)
+ computeState.bound = false;
+ },
+
+ bind: can.bindAndSetup,
+
+ unbind: can.unbindAndTeardown
+ });
+ };
+ can.compute.binder = computeBinder;
+ return can.compute;
+ })(__m3, __m8);
+
+ // ## model/model.js
+ var __m10 = (function(can) {
+
+ // ## model.js
+ // `can.Model`
+ // _A `can.Observe` that connects to a RESTful interface._
+ // Generic deferred piping function
+
+ var pipe = function(def, model, func) {
+ var d = new can.Deferred();
+ def.then(function() {
+ var args = can.makeArray(arguments);
+ args[0] = model[func](args[0]);
+ d.resolveWith(d, args);
+ }, function() {
+ d.rejectWith(this, arguments);
+ });
+
+ if (typeof def.abort === 'function') {
+ d.abort = function() {
+ return def.abort();
+ }
+ }
+
+ return d;
+ },
+ modelNum = 0,
+ ignoreHookup = /change.observe\d+/,
+ getId = function(inst) {
+ // Instead of using attr, use __get for performance.
+ // Need to set reading
+ can.Observe.__reading && can.Observe.__reading(inst, inst.constructor.id)
+ return inst.__get(inst.constructor.id);
+ },
+ // Ajax `options` generator function
+ ajax = function(ajaxOb, data, type, dataType, success, error) {
+
+ var params = {};
+
+ // If we get a string, handle it.
+ if (typeof ajaxOb == "string") {
+ // If there's a space, it's probably the type.
+ var parts = ajaxOb.split(/\s+/);
+ params.url = parts.pop();
+ if (parts.length) {
+ params.type = parts.pop();
+ }
+ } else {
+ can.extend(params, ajaxOb);
+ }
+
+ // If we are a non-array object, copy to a new attrs.
+ params.data = typeof data == "object" && !can.isArray(data) ?
+ can.extend(params.data || {}, data) : data;
+
+ // Get the url with any templated values filled out.
+ params.url = can.sub(params.url, params.data, true);
+
+ return can.ajax(can.extend({
+ type: type || "post",
+ dataType: dataType || "json",
+ success: success,
+ error: error
+ }, params));
+ },
+ makeRequest = function(self, type, success, error, method) {
+ var args;
+ // if we pass an array as `self` it it means we are coming from
+ // the queued request, and we're passing already serialized data
+ // self's signature will be: [self, serializedData]
+ if (can.isArray(self)) {
+ args = self[1];
+ self = self[0];
+ } else {
+ args = self.serialize();
+ }
+ args = [args];
+ var deferred,
+ // The model.
+ model = self.constructor,
+ jqXHR;
+
+ // `destroy` does not need data.
+ if (type == 'destroy') {
+ args.shift();
+ }
+ // `update` and `destroy` need the `id`.
+ if (type !== 'create') {
+ args.unshift(getId(self));
+ }
+
+
+ jqXHR = model[type].apply(model, args);
+
+ deferred = jqXHR.pipe(function(data) {
+ self[method || type + "d"](data, jqXHR);
+ return self;
+ });
+
+ // Hook up `abort`
+ if (jqXHR.abort) {
+ deferred.abort = function() {
+ jqXHR.abort();
+ };
+ }
+
+ deferred.then(success, error);
+ return deferred;
+ },
+
+ // This object describes how to make an ajax request for each ajax method.
+ // The available properties are:
+ // `url` - The default url to use as indicated as a property on the model.
+ // `type` - The default http request type
+ // `data` - A method that takes the `arguments` and returns `data` used for ajax.
+
+ ajaxMethods = {
+
+ create: {
+ url: "_shortName",
+ type: "post"
+ },
+
+ update: {
+ data: function(id, attrs) {
+ attrs = attrs || {};
+ var identity = this.id;
+ if (attrs[identity] && attrs[identity] !== id) {
+ attrs["new" + can.capitalize(id)] = attrs[identity];
+ delete attrs[identity];
+ }
+ attrs[identity] = id;
+ return attrs;
+ },
+ type: "put"
+ },
+
+ destroy: {
+ type: "delete",
+ data: function(id) {
+ var args = {};
+ args.id = args[this.id] = id;
+ return args;
+ }
+ },
+
+ findAll: {
+ url: "_shortName"
+ },
+
+ findOne: {}
+ },
+ // Makes an ajax request `function` from a string.
+ // `ajaxMethod` - The `ajaxMethod` object defined above.
+ // `str` - The string the user provided. Ex: `findAll: "/recipes.json"`.
+ ajaxMaker = function(ajaxMethod, str) {
+ // Return a `function` that serves as the ajax method.
+ return function(data) {
+ // If the ajax method has it's own way of getting `data`, use that.
+ data = ajaxMethod.data ?
+ ajaxMethod.data.apply(this, arguments) :
+ // Otherwise use the data passed in.
+ data;
+ // Return the ajax method with `data` and the `type` provided.
+ return ajax(str || this[ajaxMethod.url || "_url"], data, ajaxMethod.type || "get")
+ }
+ }
+
+
+
+ can.Model = can.Observe({
+ fullName: "can.Model",
+ _reqs: 0,
+ setup: function(base) {
+ // create store here if someone wants to use model without inheriting from it
+ this.store = {};
+ can.Observe.setup.apply(this, arguments);
+ // Set default list as model list
+ if (!can.Model) {
+ return;
+ }
+ this.List = ML({
+ Observe: this
+ }, {});
+ var self = this,
+ clean = can.proxy(this._clean, self);
+
+
+ // go through ajax methods and set them up
+ can.each(ajaxMethods, function(method, name) {
+ // if an ajax method is not a function, it's either
+ // a string url like findAll: "/recipes" or an
+ // ajax options object like {url: "/recipes"}
+ if (!can.isFunction(self[name])) {
+ // use ajaxMaker to convert that into a function
+ // that returns a deferred with the data
+ self[name] = ajaxMaker(method, self[name]);
+ }
+ // check if there's a make function like makeFindAll
+ // these take deferred function and can do special
+ // behavior with it (like look up data in a store)
+ if (self["make" + can.capitalize(name)]) {
+ // pass the deferred method to the make method to get back
+ // the "findAll" method.
+ var newMethod = self["make" + can.capitalize(name)](self[name]);
+ can.Construct._overwrite(self, base, name, function() {
+ // increment the numer of requests
+ can.Model._reqs++;
+ var def = newMethod.apply(this, arguments);
+ var then = def.then(clean, clean);
+ then.abort = def.abort;
+
+ // attach abort to our then and return it
+ return then;
+ })
+ }
+ });
+
+ if (self.fullName == "can.Model" || !self.fullName) {
+ self.fullName = "Model" + (++modelNum);
+ }
+ // Add ajax converters.
+ can.Model._reqs = 0;
+ this._url = this._shortName + "/{" + this.id + "}"
+ },
+ _ajax: ajaxMaker,
+ _makeRequest: makeRequest,
+ _clean: function() {
+ can.Model._reqs--;
+ if (!can.Model._reqs) {
+ for (var id in this.store) {
+ if (!this.store[id]._bindings) {
+ delete this.store[id];
+ }
+ }
+ }
+ return arguments[0];
+ },
+
+ models: function(instancesRawData, oldList) {
+ // until "end of turn", increment reqs counter so instances will be added to the store
+ can.Model._reqs++;
+ if (!instancesRawData) {
+ return;
+ }
+
+ if (instancesRawData instanceof this.List) {
+ return instancesRawData;
+ }
+
+ // Get the list type.
+ var self = this,
+ tmp = [],
+ res = oldList instanceof can.Observe.List ? oldList : new(self.List || ML),
+ // Did we get an `array`?
+ arr = can.isArray(instancesRawData),
+
+ // Did we get a model list?
+ ml = (instancesRawData instanceof ML),
+
+ // Get the raw `array` of objects.
+ raw = arr ?
+
+ // If an `array`, return the `array`.
+ instancesRawData :
+
+ // Otherwise if a model list.
+ (ml ?
+
+ // Get the raw objects from the list.
+ instancesRawData.serialize() :
+
+ // Get the object's data.
+ instancesRawData.data),
+ i = 0;
+
+
+
+ if (res.length) {
+ res.splice(0);
+ }
+
+ can.each(raw, function(rawPart) {
+ tmp.push(self.model(rawPart));
+ });
+
+ // We only want one change event so push everything at once
+ res.push.apply(res, tmp);
+
+ if (!arr) { // Push other stuff onto `array`.
+ can.each(instancesRawData, function(val, prop) {
+ if (prop !== 'data') {
+ res.attr(prop, val);
+ }
+ })
+ }
+ // at "end of turn", clean up the store
+ setTimeout(can.proxy(this._clean, this), 1);
+ return res;
+ },
+
+ model: function(attributes) {
+ if (!attributes) {
+ return;
+ }
+ if (attributes instanceof this) {
+ attributes = attributes.serialize();
+ }
+ var id = attributes[this.id],
+ model = (id || id === 0) && this.store[id] ?
+ this.store[id].attr(attributes, this.removeAttr || false) : new this(attributes);
+ if (can.Model._reqs) {
+ this.store[attributes[this.id]] = model;
+ }
+ return model;
+ }
+ },
+
+
+ {
+
+ isNew: function() {
+ var id = getId(this);
+ return !(id || id === 0); // If `null` or `undefined`
+ },
+
+ save: function(success, error) {
+ return makeRequest(this, this.isNew() ? 'create' : 'update', success, error);
+ },
+
+ destroy: function(success, error) {
+ if (this.isNew()) {
+ var self = this;
+ var def = can.Deferred();
+ def.then(success, error);
+ return def.done(function(data) {
+ self.destroyed(data)
+ }).resolve(self);
+ }
+ return makeRequest(this, 'destroy', success, error, 'destroyed');
+ },
+
+ _bindsetup: function() {
+ this.constructor.store[this.__get(this.constructor.id)] = this;
+ return can.Observe.prototype._bindsetup.apply(this, arguments);
+ },
+
+ _bindteardown: function() {
+ delete this.constructor.store[getId(this)];
+ return can.Observe.prototype._bindteardown.apply(this, arguments)
+ },
+ // Change `id`.
+ ___set: function(prop, val) {
+ can.Observe.prototype.___set.call(this, prop, val)
+ // If we add an `id`, move it to the store.
+ if (prop === this.constructor.id && this._bindings) {
+ this.constructor.store[getId(this)] = this;
+ }
+ }
+ });
+
+ can.each({
+ makeFindAll: "models",
+ makeFindOne: "model",
+ makeCreate: "model",
+ makeUpdate: "model"
+ }, function(method, name) {
+ can.Model[name] = function(oldMethod) {
+ return function() {
+ var args = can.makeArray(arguments),
+ oldArgs = can.isFunction(args[1]) ? args.splice(0, 1) : args.splice(0, 2),
+ def = pipe(oldMethod.apply(this, oldArgs), this, method);
+ def.then(args[0], args[1]);
+ // return the original promise
+ return def;
+ };
+ };
+ });
+
+ can.each([
+
+ "created",
+
+ "updated",
+
+ "destroyed"
+ ], function(funcName) {
+ can.Model.prototype[funcName] = function(attrs) {
+ var stub,
+ constructor = this.constructor;
+
+ // Update attributes if attributes have been passed
+ stub = attrs && typeof attrs == 'object' && this.attr(attrs.attr ? attrs.attr() : attrs);
+
+ // triggers change event that bubble's like
+ // handler( 'change','1.destroyed' ). This is used
+ // to remove items on destroyed from Model Lists.
+ // but there should be a better way.
+ can.trigger(this, "change", funcName)
+
+
+ // Call event on the instance's Class
+ can.trigger(constructor, funcName, this);
+ };
+ });
+
+ // Model lists are just like `Observe.List` except that when their items are
+ // destroyed, it automatically gets removed from the list.
+
+ var ML = can.Model.List = can.Observe.List({
+ setup: function(params) {
+ if (can.isPlainObject(params) && !can.isArray(params)) {
+ can.Observe.List.prototype.setup.apply(this);
+ this.replace(this.constructor.Observe.findAll(params))
+ } else {
+ can.Observe.List.prototype.setup.apply(this, arguments);
+ }
+ },
+ _changes: function(ev, attr) {
+ can.Observe.List.prototype._changes.apply(this, arguments);
+ if (/\w+\.destroyed/.test(attr)) {
+ var index = this.indexOf(ev.target);
+ if (index != -1) {
+ this.splice(index, 1);
+ }
+ }
+ }
+ })
+
+ return can.Model;
+ })(__m3, __m7);
+
+ // ## view/view.js
+ var __m11 = (function(can) {
+ // ## view.js
+ // `can.view`
+ // _Templating abstraction._
+
+ var isFunction = can.isFunction,
+ makeArray = can.makeArray,
+ // Used for hookup `id`s.
+ hookupId = 1,
+
+ $view = can.view = can.template = function(view, data, helpers, callback) {
+ // If helpers is a `function`, it is actually a callback.
+ if (isFunction(helpers)) {
+ callback = helpers;
+ helpers = undefined;
+ }
+
+ var pipe = function(result) {
+ return $view.frag(result);
+ },
+ // In case we got a callback, we need to convert the can.view.render
+ // result to a document fragment
+ wrapCallback = isFunction(callback) ? function(frag) {
+ callback(pipe(frag));
+ } : null,
+ // Get the result.
+ result = $view.render(view, data, helpers, wrapCallback),
+ deferred = can.Deferred();
+
+ if (isFunction(result)) {
+ return result;
+ }
+
+ if (can.isDeferred(result)) {
+ result.then(function(result, data) {
+ deferred.resolve.call(deferred, pipe(result), data);
+ }, function() {
+ deferred.fail.apply(deferred, arguments);
+ });
+ return deferred;
+ }
+
+ // Convert it into a dom frag.
+ return pipe(result);
+ };
+
+ can.extend($view, {
+ // creates a frag and hooks it up all at once
+ frag: function(result, parentNode) {
+ return $view.hookup($view.fragment(result), parentNode);
+ },
+
+ // simply creates a frag
+ // this is used internally to create a frag
+ // insert it
+ // then hook it up
+ fragment: function(result) {
+ var frag = can.buildFragment(result, document.body);
+ // If we have an empty frag...
+ if (!frag.childNodes.length) {
+ frag.appendChild(document.createTextNode(''));
+ }
+ return frag;
+ },
+
+ // Convert a path like string into something that's ok for an `element` ID.
+ toId: function(src) {
+ return can.map(src.toString().split(/\/|\./g), function(part) {
+ // Dont include empty strings in toId functions
+ if (part) {
+ return part;
+ }
+ }).join("_");
+ },
+
+ hookup: function(fragment, parentNode) {
+ var hookupEls = [],
+ id,
+ func;
+
+ // Get all `childNodes`.
+ can.each(fragment.childNodes ? can.makeArray(fragment.childNodes) : fragment, function(node) {
+ if (node.nodeType === 1) {
+ hookupEls.push(node);
+ hookupEls.push.apply(hookupEls, can.makeArray(node.getElementsByTagName('*')));
+ }
+ });
+
+ // Filter by `data-view-id` attribute.
+ can.each(hookupEls, function(el) {
+ if (el.getAttribute && (id = el.getAttribute('data-view-id')) && (func = $view.hookups[id])) {
+ func(el, parentNode, id);
+ delete $view.hookups[id];
+ el.removeAttribute('data-view-id');
+ }
+ });
+
+ return fragment;
+ },
+
+
+ hookups: {},
+
+
+ hook: function(cb) {
+ $view.hookups[++hookupId] = cb;
+ return " data-view-id='" + hookupId + "'";
+ },
+
+
+ cached: {},
+
+ cachedRenderers: {},
+
+
+ cache: true,
+
+
+ register: function(info) {
+ this.types["." + info.suffix] = info;
+ },
+
+ types: {},
+
+
+ ext: ".ejs",
+
+
+ registerScript: function() {},
+
+
+ preload: function() {},
+
+
+ render: function(view, data, helpers, callback) {
+ // If helpers is a `function`, it is actually a callback.
+ if (isFunction(helpers)) {
+ callback = helpers;
+ helpers = undefined;
+ }
+
+ // See if we got passed any deferreds.
+ var deferreds = getDeferreds(data);
+
+ if (deferreds.length) { // Does data contain any deferreds?
+ // The deferred that resolves into the rendered content...
+ var deferred = new can.Deferred(),
+ dataCopy = can.extend({}, data);
+
+ // Add the view request to the list of deferreds.
+ deferreds.push(get(view, true))
+
+ // Wait for the view and all deferreds to finish...
+ can.when.apply(can, deferreds).then(function(resolved) {
+ // Get all the resolved deferreds.
+ var objs = makeArray(arguments),
+ // Renderer is the last index of the data.
+ renderer = objs.pop(),
+ // The result of the template rendering with data.
+ result;
+
+ // Make data look like the resolved deferreds.
+ if (can.isDeferred(data)) {
+ dataCopy = usefulPart(resolved);
+ } else {
+ // Go through each prop in data again and
+ // replace the defferreds with what they resolved to.
+ for (var prop in data) {
+ if (can.isDeferred(data[prop])) {
+ dataCopy[prop] = usefulPart(objs.shift());
+ }
+ }
+ }
+
+ // Get the rendered result.
+ result = renderer(dataCopy, helpers);
+
+ // Resolve with the rendered view.
+ deferred.resolve(result, dataCopy);
+
+ // If there's a `callback`, call it back with the result.
+ callback && callback(result, dataCopy);
+ }, function() {
+ deferred.reject.apply(deferred, arguments)
+ });
+ // Return the deferred...
+ return deferred;
+ } else {
+ // No deferreds! Render this bad boy.
+ var response,
+ // If there's a `callback` function
+ async = isFunction(callback),
+ // Get the `view` type
+ deferred = get(view, async);
+
+ // If we are `async`...
+ if (async) {
+ // Return the deferred
+ response = deferred;
+ // And fire callback with the rendered result.
+ deferred.then(function(renderer) {
+ callback(data ? renderer(data, helpers) : renderer);
+ })
+ } else {
+ // if the deferred is resolved, call the cached renderer instead
+ // this is because it's possible, with recursive deferreds to
+ // need to render a view while its deferred is _resolving_. A _resolving_ deferred
+ // is a deferred that was just resolved and is calling back it's success callbacks.
+ // If a new success handler is called while resoliving, it does not get fired by
+ // jQuery's deferred system. So instead of adding a new callback
+ // we use the cached renderer.
+ // We also add __view_id on the deferred so we can look up it's cached renderer.
+ // In the future, we might simply store either a deferred or the cached result.
+ if (deferred.state() === "resolved" && deferred.__view_id) {
+ var currentRenderer = $view.cachedRenderers[deferred.__view_id];
+ return data ? currentRenderer(data, helpers) : currentRenderer;
+ } else {
+ // Otherwise, the deferred is complete, so
+ // set response to the result of the rendering.
+ deferred.then(function(renderer) {
+ response = data ? renderer(data, helpers) : renderer;
+ });
+ }
+ }
+
+ return response;
+ }
+ },
+
+
+ registerView: function(id, text, type, def) {
+ // Get the renderer function.
+ var func = (type || $view.types[$view.ext]).renderer(id, text);
+ def = def || new can.Deferred();
+
+ // Cache if we are caching.
+ if ($view.cache) {
+ $view.cached[id] = def;
+ def.__view_id = id;
+ $view.cachedRenderers[id] = func;
+ }
+
+ // Return the objects for the response's `dataTypes`
+ // (in this case view).
+ return def.resolve(func);
+ }
+ });
+
+ // Makes sure there's a template, if not, have `steal` provide a warning.
+ var checkText = function(text, url) {
+ if (!text.length) {
+
+ throw "can.view: No template or empty template:" + url;
+ }
+ },
+ // `Returns a `view` renderer deferred.
+ // `url` - The url to the template.
+ // `async` - If the ajax request should be asynchronous.
+ // Returns a deferred.
+ get = function(url, async) {
+ var suffix = url.match(/\.[\w\d]+$/),
+ type,
+ // If we are reading a script element for the content of the template,
+ // `el` will be set to that script element.
+ el,
+ // A unique identifier for the view (used for caching).
+ // This is typically derived from the element id or
+ // the url for the template.
+ id,
+ // The ajax request used to retrieve the template content.
+ jqXHR;
+
+ //If the url has a #, we assume we want to use an inline template
+ //from a script element and not current page's HTML
+ if (url.match(/^#/)) {
+ url = url.substr(1);
+ }
+ // If we have an inline template, derive the suffix from the `text/???` part.
+ // This only supports `<script>` tags.
+ if (el = document.getElementById(url)) {
+ suffix = "." + el.type.match(/\/(x\-)?(.+)/)[2];
+ }
+
+ // If there is no suffix, add one.
+ if (!suffix && !$view.cached[url]) {
+ url += (suffix = $view.ext);
+ }
+
+ if (can.isArray(suffix)) {
+ suffix = suffix[0]
+ }
+
+ // Convert to a unique and valid id.
+ id = $view.toId(url);
+
+ // If an absolute path, use `steal` to get it.
+ // You should only be using `//` if you are using `steal`.
+ if (url.match(/^\/\//)) {
+ var sub = url.substr(2);
+ url = !window.steal ?
+ sub :
+ steal.config().root.mapJoin("" + steal.id(sub));
+ }
+
+ // Set the template engine type.
+ type = $view.types[suffix];
+
+ // If it is cached,
+ if ($view.cached[id]) {
+ // Return the cached deferred renderer.
+ return $view.cached[id];
+
+ // Otherwise if we are getting this from a `<script>` element.
+ } else if (el) {
+ // Resolve immediately with the element's `innerHTML`.
+ return $view.registerView(id, el.innerHTML, type);
+ } else {
+ // Make an ajax request for text.
+ var d = new can.Deferred();
+ can.ajax({
+ async: async,
+ url: url,
+ dataType: "text",
+ error: function(jqXHR) {
+ checkText("", url);
+ d.reject(jqXHR);
+ },
+ success: function(text) {
+ // Make sure we got some text back.
+ checkText(text, url);
+ $view.registerView(id, text, type, d)
+ }
+ });
+ return d;
+ }
+ },
+ // Gets an `array` of deferreds from an `object`.
+ // This only goes one level deep.
+ getDeferreds = function(data) {
+ var deferreds = [];
+
+ // pull out deferreds
+ if (can.isDeferred(data)) {
+ return [data]
+ } else {
+ for (var prop in data) {
+ if (can.isDeferred(data[prop])) {
+ deferreds.push(data[prop]);
+ }
+ }
+ }
+ return deferreds;
+ },
+ // Gets the useful part of a resolved deferred.
+ // This is for `model`s and `can.ajax` that resolve to an `array`.
+ usefulPart = function(resolved) {
+ return can.isArray(resolved) && resolved[1] === 'success' ? resolved[0] : resolved
+ };
+
+ //!steal-pluginify-remove-start
+ if (window.steal) {
+ steal.type("view js", function(options, success, error) {
+ var type = $view.types["." + options.type],
+ id = $view.toId(options.id);
+
+ options.text = "steal('" + (type.plugin || "can/view/" + options.type) + "',function(can){return " + "can.view.preload('" + id + "'," + options.text + ");\n})";
+ success();
+ })
+ }
+ //!steal-pluginify-remove-end
+
+ can.extend($view, {
+ register: function(info) {
+ this.types["." + info.suffix] = info;
+
+ //!steal-pluginify-remove-start
+ if (window.steal) {
+ steal.type(info.suffix + " view js", function(options, success, error) {
+ var type = $view.types["." + options.type],
+ id = $view.toId(options.id + '');
+
+ options.text = type.script(id, options.text)
+ success();
+ })
+ };
+ //!steal-pluginify-remove-end
+
+ $view[info.suffix] = function(id, text) {
+ if (!text) {
+ // Return a nameless renderer
+ var renderer = function() {
+ return $view.frag(renderer.render.apply(this, arguments));
+ }
+ renderer.render = function() {
+ var renderer = info.renderer(null, id);
+ return renderer.apply(renderer, arguments);
+ }
+ return renderer;
+ }
+
+ $view.preload(id, info.renderer(id, text));
+ return can.view(id);
+ }
+ },
+ registerScript: function(type, id, src) {
+ return "can.view.preload('" + id + "'," + $view.types["." + type].script(id, src) + ");";
+ },
+ preload: function(id, renderer) {
+ $view.cached[id] = new can.Deferred().resolve(function(data, helpers) {
+ return renderer.call(data, data, helpers);
+ });
+
+ function frag() {
+ return $view.frag(renderer.apply(this, arguments));
+ }
+ // expose the renderer for mustache
+ frag.render = renderer;
+ return frag;
+ }
+
+ });
+
+ return can;
+ })(__m3);
+
+ // ## view/elements.js
+ var __m14 = (function() {
+
+ var elements = {
+ tagToContentPropMap: {
+ option: "textContent" in document.createElement("option") ? "textContent" : "innerText",
+ textarea: "value"
+ },
+
+ attrMap: {
+ "class": "className",
+ "value": "value",
+ "innerText": "innerText",
+ "textContent": "textContent",
+ "checked": true,
+ "disabled": true,
+ "readonly": true,
+ "required": true
+ },
+ // elements whos default value we should set
+ defaultValue: ["input", "textarea"],
+ // a map of parent element to child elements
+ tagMap: {
+ "": "span",
+ table: "tbody",
+ tr: "td",
+ ol: "li",
+ ul: "li",
+ tbody: "tr",
+ thead: "tr",
+ tfoot: "tr",
+ select: "option",
+ optgroup: "option"
+ },
+ // a tag's parent element
+ reverseTagMap: {
+ tr: "tbody",
+ option: "select",
+ td: "tr",
+ th: "tr",
+ li: "ul"
+ },
+
+ getParentNode: function(el, defaultParentNode) {
+ return defaultParentNode && el.parentNode.nodeType === 11 ? defaultParentNode : el.parentNode;
+ },
+ // set an attribute on an element
+ setAttr: function(el, attrName, val) {
+ var tagName = el.nodeName.toString().toLowerCase(),
+ prop = elements.attrMap[attrName];
+ // if this is a special property
+ if (prop === true) {
+ el[attrName] = true;
+ } else if (prop) {
+ // set the value as true / false
+ el[prop] = val;
+ if (prop === "value" && can.inArray(tagName, elements.defaultValue) >= 0) {
+ el.defaultValue = val;
+ }
+ } else {
+ el.setAttribute(attrName, val);
+ }
+ },
+ // gets the value of an attribute
+ getAttr: function(el, attrName) {
+ // Default to a blank string for IE7/8
+ return (elements.attrMap[attrName] && el[elements.attrMap[attrName]] ?
+ el[elements.attrMap[attrName]] :
+ el.getAttribute(attrName)) || '';
+ },
+ // removes the attribute
+ removeAttr: function(el, attrName) {
+ if (elements.attrMap[attrName] === true) {
+ el[attrName] = false;
+ } else {
+ el.removeAttribute(attrName);
+ }
+ },
+ contentText: function(text) {
+ if (typeof text == 'string') {
+ return text;
+ }
+ // If has no value, return an empty string.
+ if (!text && text !== 0) {
+ return '';
+ }
+ return "" + text;
+ }
+ };
+
+ return elements;
+ })();
+
+ // ## view/scanner.js
+ var __m13 = (function(can, elements) {
+
+ var newLine = /(\r|\n)+/g,
+ // Escapes characters starting with `\`.
+ clean = function(content) {
+ return content
+ .split('\\').join("\\\\")
+ .split("\n").join("\\n")
+ .split('"').join('\\"')
+ .split("\t").join("\\t");
+ },
+ // Returns a tagName to use as a temporary placeholder for live content
+ // looks forward ... could be slow, but we only do it when necessary
+ getTag = function(tagName, tokens, i) {
+ // if a tagName is provided, use that
+ if (tagName) {
+ return tagName;
+ } else {
+ // otherwise go searching for the next two tokens like "<",TAG
+ while (i < tokens.length) {
+ if (tokens[i] == "<" && elements.reverseTagMap[tokens[i + 1]]) {
+ return elements.reverseTagMap[tokens[i + 1]];
+ }
+ i++;
+ }
+ }
+ return '';
+ },
+ bracketNum = function(content) {
+ return (--content.split("{").length) - (--content.split("}").length);
+ },
+ myEval = function(script) {
+ try {
+ eval(script);
+ } catch(e) {
+ console.log(script)
+ }
+ },
+ attrReg = /([^\s]+)[\s]*=[\s]*$/,
+ // Commands for caching.
+ startTxt = 'var ___v1ew = [];',
+ finishTxt = "return ___v1ew.join('')",
+ put_cmd = "___v1ew.push(",
+ insert_cmd = put_cmd,
+ // Global controls (used by other functions to know where we are).
+ // Are we inside a tag?
+ htmlTag = null,
+ // Are we within a quote within a tag?
+ quote = null,
+ // What was the text before the current quote? (used to get the `attr` name)
+ beforeQuote = null,
+ // Whether a rescan is in progress
+ rescan = null,
+ // Used to mark where the element is.
+ status = function() {
+ // `t` - `1`.
+ // `h` - `0`.
+ // `q` - String `beforeQuote`.
+ return quote ? "'" + beforeQuote.match(attrReg)[1] + "'" : (htmlTag ? 1 : 0);
+ };
+
+ can.view.Scanner = Scanner = function(options) {
+ // Set options on self
+ can.extend(this, {
+ text: {},
+ tokens: []
+ }, options);
+
+ // Cache a token lookup
+ this.tokenReg = [];
+ this.tokenSimple = {
+ "<": "<",
+ ">": ">",
+ '"': '"',
+ "'": "'"
+ };
+ this.tokenComplex = [];
+ this.tokenMap = {};
+ for (var i = 0, token; token = this.tokens[i]; i++) {
+
+
+ // Save complex mappings (custom regexp)
+ if (token[2]) {
+ this.tokenReg.push(token[2]);
+ this.tokenComplex.push({
+ abbr: token[1],
+ re: new RegExp(token[2]),
+ rescan: token[3]
+ });
+ }
+ // Save simple mappings (string only, no regexp)
+ else {
+ this.tokenReg.push(token[1]);
+ this.tokenSimple[token[1]] = token[0];
+ }
+ this.tokenMap[token[0]] = token[1];
+ }
+
+ // Cache the token registry.
+ this.tokenReg = new RegExp("(" + this.tokenReg.slice(0).concat(["<", ">", '"', "'"]).join("|") + ")", "g");
+ };
+
+ Scanner.prototype = {
+
+ helpers: [
+
+ {
+ name: /\s*\(([\$\w]+)\)\s*->([^\n]*)/,
+ fn: function(content) {
+ var quickFunc = /\s*\(([\$\w]+)\)\s*->([^\n]*)/,
+ parts = content.match(quickFunc);
+
+ return "can.proxy(function(__){var " + parts[1] + "=can.$(__);" + parts[2] + "}, this);";
+ }
+ }
+ ],
+
+ scan: function(source, name) {
+ var tokens = [],
+ last = 0,
+ simple = this.tokenSimple,
+ complex = this.tokenComplex;
+
+ source = source.replace(newLine, "\n");
+ if (this.transform) {
+ source = this.transform(source);
+ }
+ source.replace(this.tokenReg, function(whole, part) {
+ // offset is the second to last argument
+ var offset = arguments[arguments.length - 2];
+
+ // if the next token starts after the last token ends
+ // push what's in between
+ if (offset > last) {
+ tokens.push(source.substring(last, offset));
+ }
+
+ // push the simple token (if there is one)
+ if (simple[whole]) {
+ tokens.push(whole);
+ }
+ // otherwise lookup complex tokens
+ else {
+ for (var i = 0, token; token = complex[i]; i++) {
+ if (token.re.test(whole)) {
+ tokens.push(token.abbr);
+ // Push a rescan function if one exists
+ if (token.rescan) {
+ tokens.push(token.rescan(part));
+ }
+ break;
+ }
+ }
+ }
+
+ // update the position of the last part of the last token
+ last = offset + part.length;
+ });
+
+ // if there's something at the end, add it
+ if (last < source.length) {
+ tokens.push(source.substr(last));
+ }
+
+ var content = '',
+ buff = [startTxt + (this.text.start || '')],
+ // Helper `function` for putting stuff in the view concat.
+ put = function(content, bonus) {
+ buff.push(put_cmd, '"', clean(content), '"' + (bonus || '') + ');');
+ },
+ // A stack used to keep track of how we should end a bracket
+ // `}`.
+ // Once we have a `<%= %>` with a `leftBracket`,
+ // we store how the file should end here (either `))` or `;`).
+ endStack = [],
+ // The last token, used to remember which tag we are in.
+ lastToken,
+ // The corresponding magic tag.
+ startTag = null,
+ // Was there a magic tag inside an html tag?
+ magicInTag = false,
+ // The current tag name.
+ tagName = '',
+ // stack of tagNames
+ tagNames = [],
+ // Pop from tagNames?
+ popTagName = false,
+ // Declared here.
+ bracketCount,
+ i = 0,
+ token,
+ tmap = this.tokenMap;
+
+ // Reinitialize the tag state goodness.
+ htmlTag = quote = beforeQuote = null;
+
+ for (;
+ (token = tokens[i++]) !== undefined;) {
+ if (startTag === null) {
+ switch (token) {
+ case tmap.left:
+ case tmap.escapeLeft:
+ case tmap.returnLeft:
+ magicInTag = htmlTag && 1;
+ case tmap.commentLeft:
+ // A new line -- just add whatever content within a clean.
+ // Reset everything.
+ startTag = token;
+ if (content.length) {
+ put(content);
+ }
+ content = '';
+ break;
+ case tmap.escapeFull:
+ // This is a full line escape (a line that contains only whitespace and escaped logic)
+ // Break it up into escape left and right
+ magicInTag = htmlTag && 1;
+ rescan = 1;
+ startTag = tmap.escapeLeft;
+ if (content.length) {
+ put(content);
+ }
+ rescan = tokens[i++];
+ content = rescan.content || rescan;
+ if (rescan.before) {
+ put(rescan.before);
+ }
+ tokens.splice(i, 0, tmap.right);
+ break;
+ case tmap.commentFull:
+ // Ignore full line comments.
+ break;
+ case tmap.templateLeft:
+ content += tmap.left;
+ break;
+ case '<':
+ // Make sure we are not in a comment.
+ if (tokens[i].indexOf("!--") !== 0) {
+ htmlTag = 1;
+ magicInTag = 0;
+ }
+ content += token;
+ break;
+ case '>':
+ htmlTag = 0;
+ // content.substr(-1) doesn't work in IE7/8
+ var emptyElement = content.substr(content.length - 1) == "/" || content.substr(content.length - 2) == "--";
+ // if there was a magic tag
+ // or it's an element that has text content between its tags,
+ // but content is not other tags add a hookup
+ // TODO: we should only add `can.EJS.pending()` if there's a magic tag
+ // within the html tags.
+ if (magicInTag || !popTagName && elements.tagToContentPropMap[tagNames[tagNames.length - 1]]) {
+ // make sure / of /> is on the left of pending
+ if (emptyElement) {
+ put(content.substr(0, content.length - 1), ",can.view.pending(),\"/>\"");
+ } else {
+ put(content, ",can.view.pending(),\">\"");
+ }
+ content = '';
+ magicInTag = 0;
+ } else {
+ content += token;
+ }
+ // if it's a tag like <input/>
+ if (emptyElement || popTagName) {
+ // remove the current tag in the stack
+ tagNames.pop();
+ // set the current tag to the previous parent
+ tagName = tagNames[tagNames.length - 1];
+ // Don't pop next time
+ popTagName = false;
+ }
+ break;
+ case "'":
+ case '"':
+ // If we are in an html tag, finding matching quotes.
+ if (htmlTag) {
+ // We have a quote and it matches.
+ if (quote && quote === token) {
+ // We are exiting the quote.
+ quote = null;
+ // Otherwise we are creating a quote.
+ // TODO: does this handle `\`?
+ } else if (quote === null) {
+ quote = token;
+ beforeQuote = lastToken;
+ }
+ }
+ default:
+ // Track the current tag
+ if (lastToken === '<') {
+ tagName = token.split(/\s/)[0];
+ if (tagName.indexOf("/") === 0 && tagNames[tagNames.length - 1] === tagName.substr(1)) {
+ // set tagName to the last tagName
+ // if there are no more tagNames, we'll rely on getTag.
+ tagName = tagNames[tagNames.length - 1];
+ popTagName = true;
+ } else {
+ tagNames.push(tagName);
+ }
+ }
+ content += token;
+ break;
+ }
+ } else {
+ // We have a start tag.
+ switch (token) {
+ case tmap.right:
+ case tmap.returnRight:
+ switch (startTag) {
+ case tmap.left:
+ // Get the number of `{ minus }`
+ bracketCount = bracketNum(content);
+
+ // We are ending a block.
+ if (bracketCount == 1) {
+
+ // We are starting on.
+ buff.push(insert_cmd, "can.view.txt(0,'" + getTag(tagName, tokens, i) + "'," + status() + ",this,function(){", startTxt, content);
+
+ endStack.push({
+ before: "",
+ after: finishTxt + "}));\n"
+ });
+ } else {
+
+ // How are we ending this statement?
+ last = // If the stack has value and we are ending a block...
+ endStack.length && bracketCount == -1 ? // Use the last item in the block stack.
+ endStack.pop() : // Or use the default ending.
+ {
+ after: ";"
+ };
+
+ // If we are ending a returning block,
+ // add the finish text which returns the result of the
+ // block.
+ if (last.before) {
+ buff.push(last.before);
+ }
+ // Add the remaining content.
+ buff.push(content, ";", last.after);
+ }
+ break;
+ case tmap.escapeLeft:
+ case tmap.returnLeft:
+ // We have an extra `{` -> `block`.
+ // Get the number of `{ minus }`.
+ bracketCount = bracketNum(content);
+ // If we have more `{`, it means there is a block.
+ if (bracketCount) {
+ // When we return to the same # of `{` vs `}` end with a `doubleParent`.
+ endStack.push({
+ before: finishTxt,
+ after: "}));"
+ });
+ }
+
+ var escaped = startTag === tmap.escapeLeft ? 1 : 0,
+ commands = {
+ insert: insert_cmd,
+ tagName: getTag(tagName, tokens, i),
+ status: status()
+ };
+
+ for (var ii = 0; ii < this.helpers.length; ii++) {
+ // Match the helper based on helper
+ // regex name value
+ var helper = this.helpers[ii];
+ if (helper.name.test(content)) {
+ content = helper.fn(content, commands);
+
+ // dont escape partials
+ if (helper.name.source == /^>[\s]*\w*/.source) {
+ escaped = 0;
+ }
+ break;
+ }
+ }
+
+ // Handle special cases
+ if (typeof content == 'object') {
+ if (content.raw) {
+ buff.push(content.raw);
+ }
+ } else {
+ // If we have `<%== a(function(){ %>` then we want
+ // `can.EJS.text(0,this, function(){ return a(function(){ var _v1ew = [];`.
+ buff.push(insert_cmd, "can.view.txt(" + escaped + ",'" + tagName + "'," + status() + ",this,function(){ " + (this.text.escape || '') + "return ", content,
+ // If we have a block.
+ bracketCount ?
+ // Start with startTxt `"var _v1ew = [];"`.
+ startTxt :
+ // If not, add `doubleParent` to close push and text.
+ "}));");
+ }
+
+ if (rescan && rescan.after && rescan.after.length) {
+ put(rescan.after.length);
+ rescan = null;
+ }
+ break;
+ }
+ startTag = null;
+ content = '';
+ break;
+ case tmap.templateLeft:
+ content += tmap.left;
+ break;
+ default:
+ content += token;
+ break;
+ }
+ }
+ lastToken = token;
+ }
+
+ // Put it together...
+ if (content.length) {
+ // Should be `content.dump` in Ruby.
+ put(content);
+ }
+ buff.push(";");
+
+ var template = buff.join(''),
+ out = {
+ out: 'with(_VIEW) { with (_CONTEXT) {' + template + " " + finishTxt + "}}"
+ };
+ // Use `eval` instead of creating a function, because it is easier to debug.
+ myEval.call(out, 'this.fn = (function(_CONTEXT,_VIEW){' + out.out + '});\r\n//@ sourceURL=' + name + ".js");
+
+ return out;
+ }
+ };
+
+ return Scanner;
+ })(__m11, __m14);
+
+ // ## view/node_lists.js
+ var __m17 = (function(can) {
+
+ // text node expando test
+ var canExpando = true;
+ try {
+ document.createTextNode('')._ = 0;
+ } catch (ex) {
+ canExpando = false;
+ }
+
+ // a mapping of element ids to nodeList ids
+ var nodeMap = {},
+ // a mapping of ids to text nodes
+ textNodeMap = {},
+ // a mapping of nodeList ids to nodeList
+ nodeListMap = {},
+ expando = "ejs_" + Math.random(),
+ _id = 0,
+ id = function(node) {
+ if (canExpando || node.nodeType !== 3) {
+ if (node[expando]) {
+ return node[expando];
+ } else {
+ return node[expando] = (node.nodeName ? "element_" : "obj_") + (++_id);
+ }
+ } else {
+ for (var textNodeID in textNodeMap) {
+ if (textNodeMap[textNodeID] === node) {
+ return textNodeID;
+ }
+ }
+
+ textNodeMap["text_" + (++_id)] = node;
+ return "text_" + _id;
+ }
+ },
+ // removes a nodeListId from a node's nodeListIds
+ removeNodeListId = function(node, nodeListId) {
+ var nodeListIds = nodeMap[id(node)];
+ if (nodeListIds) {
+ var index = can.inArray(nodeListId, nodeListIds);
+
+ if (index >= 0) {
+ nodeListIds.splice(index, 1);
+ }
+ if (!nodeListIds.length) {
+ delete nodeMap[id(node)];
+ }
+ }
+ },
+ addNodeListId = function(node, nodeListId) {
+ var nodeListIds = nodeMap[id(node)];
+ if (!nodeListIds) {
+ nodeListIds = nodeMap[id(node)] = [];
+ }
+ nodeListIds.push(nodeListId);
+ };
+
+ var nodeLists = {
+ id: id,
+ // replaces the contents of one node list with the nodes in another list
+ replace: function(oldNodeList, newNodes) {
+ // for each node in the node list
+ oldNodeList = can.makeArray(oldNodeList);
+
+ // try every set
+ //can.each( oldNodeList, function(node){
+ var node = oldNodeList[0]
+ // for each nodeList the node is in
+ can.each(can.makeArray(nodeMap[id(node)]), function(nodeListId) {
+
+ // if startNode to endNode is
+ // within list, replace that list
+ // I think the problem is not the WHOLE part is being
+ // matched
+ var nodeList = nodeListMap[nodeListId],
+ startIndex = can.inArray(node, nodeList),
+ endIndex = can.inArray(oldNodeList[oldNodeList.length - 1], nodeList);
+
+
+ // remove this nodeListId from each node
+ if (startIndex >= 0 && endIndex >= 0) {
+ for (var i = startIndex; i <= endIndex; i++) {
+ var n = nodeList[i];
+ removeNodeListId(n, nodeListId);
+ }
+ // swap in new nodes into the nodeLIst
+ nodeList.splice.apply(nodeList, [startIndex, endIndex - startIndex + 1].concat(newNodes));
+
+ // tell these new nodes they belong to the nodeList
+ can.each(newNodes, function(node) {
+ addNodeListId(node, nodeListId);
+ });
+ } else {
+ nodeLists.unregister(nodeList);
+ }
+ });
+ //});
+ },
+ // registers a list of nodes
+ register: function(nodeList) {
+ var nLId = id(nodeList);
+ nodeListMap[nLId] = nodeList;
+
+ can.each(nodeList, function(node) {
+ addNodeListId(node, nLId);
+ });
+
+ },
+ // removes mappings
+ unregister: function(nodeList) {
+ var nLId = id(nodeList);
+ can.each(nodeList, function(node) {
+ removeNodeListId(node, nLId);
+ });
+ delete nodeListMap[nLId];
+ },
+ nodeMap: nodeMap,
+ nodeListMap: nodeListMap
+ }
+ var ids = function(nodeList) {
+ return nodeList.map(function(n) {
+ return id(n) + ":" + (n.innerHTML || n.nodeValue)
+ })
+ }
+ return nodeLists;
+
+ })(__m3);
+
+ // ## view/live.js
+ var __m16 = (function(can, elements, view, nodeLists) {
+ // ## live.js
+ // The live module provides live binding for computes
+ // and can.Observe.List.
+ // Currently, it's API is designed for `can/view/render`, but
+ // it could easily be used for other purposes.
+
+ // ### Helper methods
+ // #### setup
+ // `setup(HTMLElement, bind(data), unbind(data)) -> data`
+ // Calls bind right away, but will call unbind
+ // if the element is "destroyed" (removed from the DOM).
+ var setup = function(el, bind, unbind) {
+ var teardown = function() {
+ unbind(data)
+ can.unbind.call(el, 'destroyed', teardown);
+ },
+ data = {
+ teardownCheck: function(parent) {
+ if (!parent) {
+ teardown();
+ }
+ }
+ }
+
+ can.bind.call(el, 'destroyed', teardown);
+ bind(data)
+ return data;
+ },
+ // #### listen
+ // Calls setup, but presets bind and unbind to
+ // operate on a compute
+ listen = function(el, compute, change) {
+ return setup(el, function() {
+ compute.bind("change", change);
+ }, function(data) {
+ compute.unbind("change", change);
+ if (data.nodeList) {
+ nodeLists.unregister(data.nodeList);
+ }
+ });
+ },
+ // #### getAttributeParts
+ // Breaks up a string like foo='bar' into ["foo","'bar'""]
+ getAttributeParts = function(newVal) {
+ return (newVal || "").replace(/['"]/g, '').split('=')
+ }
+ // #### insertElementsAfter
+ // Appends elements after the last item in oldElements.
+ insertElementsAfter = function(oldElements, newFrag) {
+ var last = oldElements[oldElements.length - 1];
+
+ // Insert it in the `document` or `documentFragment`
+ if (last.nextSibling) {
+ last.parentNode.insertBefore(newFrag, last.nextSibling);
+ } else {
+ last.parentNode.appendChild(newFrag);
+ }
+ };
+
+ var live = {
+ nodeLists: nodeLists,
+ list: function(el, list, func, context, parentNode) {
+ // A mapping of the index to an array
+ // of elements that represent the item.
+ // Each array is registered so child or parent
+ // live structures can update the elements
+ var nodesMap = [],
+
+ add = function(ev, items, index) {
+
+ // Collect new html and mappings
+ var frag = document.createDocumentFragment(),
+ newMappings = [];
+ can.each(items, function(item) {
+ var itemHTML = func.call(context, item),
+ itemFrag = can.view.frag(itemHTML, parentNode);
+
+ newMappings.push(can.makeArray(itemFrag.childNodes));
+ frag.appendChild(itemFrag);
+ })
+
+ // Inserting at the end of the list
+ if (!nodesMap[index]) {
+ insertElementsAfter(
+ index == 0 ? [text] :
+ nodesMap[index - 1], frag)
+ } else {
+ var el = nodesMap[index][0];
+ el.parentNode.insertBefore(frag, el)
+ }
+ // register each item
+ can.each(newMappings, function(nodeList) {
+ nodeLists.register(nodeList)
+ });
+ [].splice.apply(nodesMap, [index, 0].concat(newMappings));
+ },
+ remove = function(ev, items, index) {
+ var removedMappings = nodesMap.splice(index, items.length),
+ itemsToRemove = [];
+
+ can.each(removedMappings, function(nodeList) {
+ // add items that we will remove all at once
+ [].push.apply(itemsToRemove, nodeList)
+ // Update any parent lists to remove these items
+ nodeLists.replace(nodeList, []);
+ // unregister the list
+ nodeLists.unregister(nodeList);
+
+ });
+ can.remove(can.$(itemsToRemove));
+ },
+ parentNode = elements.getParentNode(el, parentNode),
+ text = document.createTextNode("");
+
+ // Setup binding and teardown to add and remove events
+ setup(parentNode, function() {
+ list.bind("add", add).bind("remove", remove)
+ }, function() {
+ list.unbind("add", add).unbind("remove", remove);
+ can.each(nodesMap, function(nodeList) {
+ nodeLists.unregister(nodeList);
+ })
+ })
+
+ insertElementsAfter([el], text);
+ can.remove(can.$(el));
+ add({}, list, 0);
+
+ },
+ html: function(el, compute, parentNode) {
+ var parentNode = elements.getParentNode(el, parentNode),
+
+ data = listen(parentNode, compute, function(ev, newVal, oldVal) {
+ var attached = nodes[0].parentNode;
+ // update the nodes in the DOM with the new rendered value
+ if (attached) {
+ makeAndPut(newVal);
+ }
+ data.teardownCheck(nodes[0].parentNode);
+ });
+
+ var nodes,
+ makeAndPut = function(val) {
+ // create the fragment, but don't hook it up
+ // we need to insert it into the document first
+ var frag = can.view.frag(val, parentNode),
+ // keep a reference to each node
+ newNodes = can.makeArray(frag.childNodes);
+ // Insert it in the `document` or `documentFragment`
+ insertElementsAfter(nodes || [el], frag)
+ // nodes hasn't been set yet
+ if (!nodes) {
+ can.remove(can.$(el));
+ nodes = newNodes;
+ // set the teardown nodeList
+ data.nodeList = nodes;
+ nodeLists.register(nodes);
+ } else {
+ // Update node Array's to point to new nodes
+ // and then remove the old nodes.
+ // It has to be in this order for Mootools
+ // and IE because somehow, after an element
+ // is removed from the DOM, it loses its
+ // expando values.
+ var nodesToRemove = can.makeArray(nodes);
+ nodeLists.replace(nodes, newNodes);
+ can.remove(can.$(nodesToRemove));
+ }
+ };
+ makeAndPut(compute(), [el]);
+
+ },
+ text: function(el, compute, parentNode) {
+ var parent = elements.getParentNode(el, parentNode);
+
+ // setup listening right away so we don't have to re-calculate value
+ var data = listen(el.parentNode !== parent ? el.parentNode : parent, compute, function(ev, newVal, oldVal) {
+ // Sometimes this is 'unknown' in IE and will throw an exception if it is
+ if (typeof node.nodeValue != 'unknown') {
+ node.nodeValue = "" + newVal;
+ }
+ data.teardownCheck(node.parentNode);
+ });
+
+ var node = document.createTextNode(compute());
+
+ if (el.parentNode !== parent) {
+ parent = el.parentNode;
+ parent.insertBefore(node, el);
+ parent.removeChild(el);
+ } else {
+ parent.insertBefore(node, el);
+ parent.removeChild(el);
+ }
+ },
+ attributes: function(el, compute, currentValue) {
+ var setAttrs = function(newVal) {
+ var parts = getAttributeParts(newVal),
+ newAttrName = parts.shift();
+
+ // Remove if we have a change and used to have an `attrName`.
+ if ((newAttrName != attrName) && attrName) {
+ elements.removeAttr(el, attrName);
+ }
+ // Set if we have a new `attrName`.
+ if (newAttrName) {
+ elements.setAttr(el, newAttrName, parts.join('='));
+ attrName = newAttrName;
+ }
+ }
+
+ listen(el, compute, function(ev, newVal) {
+ setAttrs(newVal)
+ })
+ // current value has been set
+ if (arguments.length >= 3) {
+ var attrName = getAttributeParts(currentValue)[0]
+ } else {
+ setAttrs(compute())
+ }
+ },
+ attributePlaceholder: '__!!__',
+ attributeReplace: /__!!__/g,
+ attribute: function(el, attributeName, compute) {
+ listen(el, compute, function(ev, newVal) {
+ elements.setAttr(el, attributeName, hook.render());
+ })
+
+ var wrapped = can.$(el),
+ hooks;
+
+ // Get the list of hookups or create one for this element.
+ // Hooks is a map of attribute names to hookup `data`s.
+ // Each hookup data has:
+ // `render` - A `function` to render the value of the attribute.
+ // `funcs` - A list of hookup `function`s on that attribute.
+ // `batchNum` - The last event `batchNum`, used for performance.
+ hooks = can.data(wrapped, 'hooks');
+ if (!hooks) {
+ can.data(wrapped, 'hooks', hooks = {});
+ }
+
+ // Get the attribute value.
+ var attr = elements.getAttr(el, attributeName),
+ // Split the attribute value by the template.
+ // Only split out the first __!!__ so if we have multiple hookups in the same attribute,
+ // they will be put in the right spot on first render
+ parts = attr.split(live.attributePlaceholder),
+ goodParts = [],
+ hook;
+ goodParts.push(parts.shift(),
+ parts.join(live.attributePlaceholder));
+
+ // If we already had a hookup for this attribute...
+ if (hooks[attributeName]) {
+ // Just add to that attribute's list of `function`s.
+ hooks[attributeName].computes.push(compute);
+ } else {
+ // Create the hookup data.
+ hooks[attributeName] = {
+ render: function() {
+ var i = 0,
+ // attr doesn't have a value in IE
+ newAttr = attr ? attr.replace(live.attributeReplace, function() {
+ return elements.contentText(hook.computes[i++]());
+ }) : elements.contentText(hook.computes[i++]());
+ return newAttr;
+ },
+ computes: [compute],
+ batchNum: undefined
+ };
+ }
+
+ // Save the hook for slightly faster performance.
+ hook = hooks[attributeName];
+
+ // Insert the value in parts.
+ goodParts.splice(1, 0, compute());
+
+ // Set the attribute.
+ elements.setAttr(el, attributeName, goodParts.join(""));
+
+ }
+ }
+ return live;
+
+ })(__m3, __m14, __m11, __m17);
+
+ // ## view/render.js
+ var __m15 = (function(can, elements, live) {
+
+ var pendingHookups = [],
+ tagChildren = function(tagName) {
+ var newTag = elements.tagMap[tagName] || "span";
+ if (newTag === "span") {
+ //innerHTML in IE doesn't honor leading whitespace after empty elements
+ return "@@!!@@";
+ }
+ return "<" + newTag + ">" + tagChildren(newTag) + "</" + newTag + ">";
+ },
+ contentText = function(input, tag) {
+
+ // If it's a string, return.
+ if (typeof input == 'string') {
+ return input;
+ }
+ // If has no value, return an empty string.
+ if (!input && input !== 0) {
+ return '';
+ }
+
+ // If it's an object, and it has a hookup method.
+ var hook = (input.hookup &&
+
+ // Make a function call the hookup method.
+
+ function(el, id) {
+ input.hookup.call(input, el, id);
+ }) ||
+
+ // Or if it's a `function`, just use the input.
+ (typeof input == 'function' && input);
+
+ // Finally, if there is a `function` to hookup on some dom,
+ // add it to pending hookups.
+ if (hook) {
+ if (tag) {
+ return "<" + tag + " " + can.view.hook(hook) + "></" + tag + ">"
+ } else {
+ pendingHookups.push(hook);
+ }
+
+ return '';
+ }
+
+ // Finally, if all else is `false`, `toString()` it.
+ return "" + input;
+ },
+ // Returns escaped/sanatized content for anything other than a live-binding
+ contentEscape = function(txt) {
+ return (typeof txt == 'string' || typeof txt == 'number') ?
+ can.esc(txt) :
+ contentText(txt);
+ };
+
+ var current;
+
+ can.extend(can.view, {
+ live: live,
+ setupLists: function() {
+
+ var old = can.view.lists,
+ data;
+
+ can.view.lists = function(list, renderer) {
+ data = {
+ list: list,
+ renderer: renderer
+ }
+ }
+ return function() {
+ can.view.lists = old;
+ return data;
+ }
+ },
+ pending: function() {
+ // TODO, make this only run for the right tagName
+ var hooks = pendingHookups.slice(0);
+ lastHookups = hooks;
+ pendingHookups = [];
+ return can.view.hook(function(el) {
+ can.each(hooks, function(fn) {
+ fn(el);
+ });
+ });
+ },
+
+
+ txt: function(escape, tagName, status, self, func) {
+ var listTeardown = can.view.setupLists(),
+ emptyHandler = function() {},
+ unbind = function() {
+ compute.unbind("change", emptyHandler)
+ };
+
+ var compute = can.compute(func, self, false);
+ // bind to get and temporarily cache the value
+ compute.bind("change", emptyHandler);
+ // call the "wrapping" function and get the binding information
+ var tag = (elements.tagMap[tagName] || "span"),
+ listData = listTeardown(),
+ value = compute();
+
+
+ if (listData) {
+ return "<" + tag + can.view.hook(function(el, parentNode) {
+ live.list(el, listData.list, listData.renderer, self, parentNode);
+ }) + "></" + tag + ">";
+ }
+
+ // If we had no observes just return the value returned by func.
+ if (!compute.hasDependencies) {
+ unbind();
+ return (escape || status !== 0 ? contentEscape : contentText)(value, status === 0 && tag);
+ }
+
+ // the property (instead of innerHTML elements) to adjust. For
+ // example options should use textContent
+ var contentProp = elements.tagToContentPropMap[tagName];
+
+
+ // The magic tag is outside or between tags.
+ if (status === 0 && !contentProp) {
+ // Return an element tag with a hookup in place of the content
+ return "<" + tag + can.view.hook(
+ escape ?
+ // If we are escaping, replace the parentNode with
+ // a text node who's value is `func`'s return value.
+
+ function(el, parentNode) {
+ live.text(el, compute, parentNode);
+ unbind();
+ } :
+ // If we are not escaping, replace the parentNode with a
+ // documentFragment created as with `func`'s return value.
+
+ function(el, parentNode) {
+ live.html(el, compute, parentNode);
+ unbind();
+ //children have to be properly nested HTML for buildFragment to work properly
+ }) + ">" + tagChildren(tag) + "</" + tag + ">";
+ // In a tag, but not in an attribute
+ } else if (status === 1) {
+ // remember the old attr name
+ pendingHookups.push(function(el) {
+ live.attributes(el, compute, compute());
+ unbind();
+ });
+ return compute();
+ } else { // In an attribute...
+ var attributeName = status === 0 ? contentProp : status;
+ // if the magic tag is inside the element, like `<option><% TAG %></option>`,
+ // we add this hookup to the last element (ex: `option`'s) hookups.
+ // Otherwise, the magic tag is in an attribute, just add to the current element's
+ // hookups.
+ (status === 0 ? lastHookups : pendingHookups).push(function(el) {
+ live.attribute(el, attributeName, compute);
+ unbind();
+ });
+ return live.attributePlaceholder;
+ }
+ }
+ });
+
+ return can;
+ })(__m11, __m14, __m16, __m2);
+
+ // ## view/ejs/ejs.js
+ var __m12 = (function(can) {
+ // ## ejs.js
+ // `can.EJS`
+ // _Embedded JavaScript Templates._
+
+ // Helper methods.
+ var extend = can.extend,
+ EJS = function(options) {
+ // Supports calling EJS without the constructor
+ // This returns a function that renders the template.
+ if (this.constructor != EJS) {
+ var ejs = new EJS(options);
+ return function(data, helpers) {
+ return ejs.render(data, helpers);
+ };
+ }
+ // If we get a `function` directly, it probably is coming from
+ // a `steal`-packaged view.
+ if (typeof options == "function") {
+ this.template = {
+ fn: options
+ };
+ return;
+ }
+ // Set options on self.
+ extend(this, options);
+ this.template = this.scanner.scan(this.text, this.name);
+ };
+
+ can.EJS = EJS;
+
+
+ EJS.prototype.
+
+ render = function(object, extraHelpers) {
+ object = object || {};
+ return this.template.fn.call(object, object, new EJS.Helpers(object, extraHelpers || {}));
+ };
+
+ extend(EJS.prototype, {
+
+ scanner: new can.view.Scanner({
+
+ tokens: [
+ ["templateLeft", "<%%"], // Template
+ ["templateRight", "%>"], // Right Template
+ ["returnLeft", "<%=="], // Return Unescaped
+ ["escapeLeft", "<%="], // Return Escaped
+ ["commentLeft", "<%#"], // Comment
+ ["left", "<%"], // Run --- this is hack for now
+ ["right", "%>"], // Right -> All have same FOR Mustache ...
+ ["returnRight", "%>"]
+ ],
+
+
+ transform: function(source) {
+ return source.replace(/<%([\s\S]+?)%>/gm, function(whole, part) {
+ var brackets = [],
+ foundBracketPair,
+ i;
+
+ // Look for brackets (for removing self-contained blocks)
+ part.replace(/[{}]/gm, function(bracket, offset) {
+ brackets.push([bracket, offset]);
+ });
+
+ // Remove bracket pairs from the list of replacements
+ do {
+ foundBracketPair = false;
+ for (i = brackets.length - 2; i >= 0; i--) {
+ if (brackets[i][0] == '{' && brackets[i + 1][0] == '}') {
+ brackets.splice(i, 2);
+ foundBracketPair = true;
+ break;
+ }
+ }
+ } while (foundBracketPair);
+
+ // Unmatched brackets found, inject EJS tags
+ if (brackets.length >= 2) {
+ var result = ['<%'],
+ bracket,
+ last = 0;
+ for (i = 0; bracket = brackets[i]; i++) {
+ result.push(part.substring(last, last = bracket[1]));
+ if ((bracket[0] == '{' && i < brackets.length - 1) || (bracket[0] == '}' && i > 0)) {
+ result.push(bracket[0] == '{' ? '{ %><% ' : ' %><% }');
+ } else {
+ result.push(bracket[0]);
+ }
+ ++last;
+ }
+ result.push(part.substring(last), '%>');
+ return result.join('');
+ }
+ // Otherwise return the original
+ else {
+ return '<%' + part + '%>';
+ }
+ });
+ }
+ })
+ });
+
+ EJS.Helpers = function(data, extras) {
+ this._data = data;
+ this._extras = extras;
+ extend(this, extras);
+ };
+
+
+ EJS.Helpers.prototype = {
+ // TODO Deprecated!!
+ list: function(list, cb) {
+
+ can.each(list, function(item, i) {
+ cb(item, i, list)
+ })
+ },
+ each: function(list, cb) {
+ // Normal arrays don't get live updated
+ if (can.isArray(list)) {
+ this.list(list, cb);
+ } else {
+ can.view.lists(list, cb);
+ }
+ }
+ };
+
+ // Options for `steal`'s build.
+ can.view.register({
+ suffix: "ejs",
+ // returns a `function` that renders the view.
+ script: function(id, src) {
+ return "can.EJS(function(_CONTEXT,_VIEW) { " + new EJS({
+ text: src,
+ name: id
+ }).template.out + " })";
+ },
+ renderer: function(id, text) {
+ return EJS({
+ text: text,
+ name: id
+ });
+ }
+ });
+
+ return can;
+ })(__m3, __m11, __m2, __m9, __m13, __m15);
+
+ // ## control/control.js
+ var __m18 = (function(can) {
+ // ## control.js
+ // `can.Control`
+ // _Controller_
+
+ // Binds an element, returns a function that unbinds.
+ var bind = function(el, ev, callback) {
+
+ can.bind.call(el, ev, callback);
+
+ return function() {
+ can.unbind.call(el, ev, callback);
+ };
+ },
+ isFunction = can.isFunction,
+ extend = can.extend,
+ each = can.each,
+ slice = [].slice,
+ paramReplacer = /\{([^\}]+)\}/g,
+ special = can.getObject("$.event.special", [can]) || {},
+
+ // Binds an element, returns a function that unbinds.
+ delegate = function(el, selector, ev, callback) {
+ can.delegate.call(el, selector, ev, callback);
+ return function() {
+ can.undelegate.call(el, selector, ev, callback);
+ };
+ },
+
+ // Calls bind or unbind depending if there is a selector.
+ binder = function(el, ev, callback, selector) {
+ return selector ?
+ delegate(el, can.trim(selector), ev, callback) :
+ bind(el, ev, callback);
+ },
+
+ basicProcessor;
+
+ var Control = can.Control = can.Construct(
+
+ {
+ // Setup pre-processes which methods are event listeners.
+
+ setup: function() {
+
+ // Allow contollers to inherit "defaults" from super-classes as it
+ // done in `can.Construct`
+ can.Construct.setup.apply(this, arguments);
+
+ // If you didn't provide a name, or are `control`, don't do anything.
+ if (can.Control) {
+
+ // Cache the underscored names.
+ var control = this,
+ funcName;
+
+ // Calculate and cache actions.
+ control.actions = {};
+ for (funcName in control.prototype) {
+ if (control._isAction(funcName)) {
+ control.actions[funcName] = control._action(funcName);
+ }
+ }
+ }
+ },
+
+ // Moves `this` to the first argument, wraps it with `jQuery` if it's an element
+ _shifter: function(context, name) {
+
+ var method = typeof name == "string" ? context[name] : name;
+
+ if (!isFunction(method)) {
+ method = context[method];
+ }
+
+ return function() {
+ context.called = name;
+ return method.apply(context, [this.nodeName ? can.$(this) : this].concat(slice.call(arguments, 0)));
+ };
+ },
+
+ // Return `true` if is an action.
+
+ _isAction: function(methodName) {
+
+ var val = this.prototype[methodName],
+ type = typeof val;
+ // if not the constructor
+ return (methodName !== 'constructor') &&
+ // and is a function or links to a function
+ (type == "function" || (type == "string" && isFunction(this.prototype[val]))) &&
+ // and is in special, a processor, or has a funny character
+ !! (special[methodName] || processors[methodName] || /[^\w]/.test(methodName));
+ },
+ // Takes a method name and the options passed to a control
+ // and tries to return the data necessary to pass to a processor
+ // (something that binds things).
+
+ _action: function(methodName, options) {
+
+ // If we don't have options (a `control` instance), we'll run this
+ // later.
+ paramReplacer.lastIndex = 0;
+ if (options || !paramReplacer.test(methodName)) {
+ // If we have options, run sub to replace templates `{}` with a
+ // value from the options or the window
+ var convertedName = options ? can.sub(methodName, [options, window]) : methodName;
+ if (!convertedName) {
+ return null;
+ }
+ // If a `{}` template resolves to an object, `convertedName` will be
+ // an array
+ var arr = can.isArray(convertedName),
+
+ // Get the name
+ name = arr ? convertedName[1] : convertedName,
+
+ // Grab the event off the end
+ parts = name.split(/\s+/g),
+ event = parts.pop();
+
+ return {
+ processor: processors[event] || basicProcessor,
+ parts: [name, parts.join(" "), event],
+ delegate: arr ? convertedName[0] : undefined
+ };
+ }
+ },
+ // An object of `{eventName : function}` pairs that Control uses to
+ // hook up events auto-magically.
+
+ processors: {},
+ // A object of name-value pairs that act as default values for a
+ // control instance
+ defaults: {}
+
+ }, {
+
+ // Sets `this.element`, saves the control in `data, binds event
+ // handlers.
+
+ setup: function(element, options) {
+
+ var cls = this.constructor,
+ pluginname = cls.pluginName || cls._fullName,
+ arr;
+
+ // Want the raw element here.
+ this.element = can.$(element)
+
+ if (pluginname && pluginname !== 'can_control') {
+ // Set element and `className` on element.
+ this.element.addClass(pluginname);
+ }
+
+ (arr = can.data(this.element, "controls")) || can.data(this.element, "controls", arr = []);
+ arr.push(this);
+
+ // Option merging.
+
+ this.options = extend({}, cls.defaults, options);
+
+ // Bind all event handlers.
+ this.on();
+
+ // Gets passed into `init`.
+
+ return [this.element, this.options];
+ },
+
+ on: function(el, selector, eventName, func) {
+ if (!el) {
+
+ // Adds bindings.
+ this.off();
+
+ // Go through the cached list of actions and use the processor
+ // to bind
+ var cls = this.constructor,
+ bindings = this._bindings,
+ actions = cls.actions,
+ element = this.element,
+ destroyCB = can.Control._shifter(this, "destroy"),
+ funcName, ready;
+
+ for (funcName in actions) {
+ // Only push if we have the action and no option is `undefined`
+ if (actions.hasOwnProperty(funcName) &&
+ (ready = actions[funcName] || cls._action(funcName, this.options))) {
+ bindings.push(ready.processor(ready.delegate || element,
+ ready.parts[2], ready.parts[1], funcName, this));
+ }
+ }
+
+
+ // Setup to be destroyed...
+ // don't bind because we don't want to remove it.
+ can.bind.call(element, "destroyed", destroyCB);
+ bindings.push(function(el) {
+ can.unbind.call(el, "destroyed", destroyCB);
+ });
+ return bindings.length;
+ }
+
+ if (typeof el == 'string') {
+ func = eventName;
+ eventName = selector;
+ selector = el;
+ el = this.element;
+ }
+
+ if (func === undefined) {
+ func = eventName;
+ eventName = selector;
+ selector = null;
+ }
+
+ if (typeof func == 'string') {
+ func = can.Control._shifter(this, func);
+ }
+
+ this._bindings.push(binder(el, eventName, func, selector));
+
+ return this._bindings.length;
+ },
+ // Unbinds all event handlers on the controller.
+
+ off: function() {
+ var el = this.element[0]
+ each(this._bindings || [], function(value) {
+ value(el);
+ });
+ // Adds bindings.
+ this._bindings = [];
+ },
+ // Prepares a `control` for garbage collection
+
+ destroy: function() {
+ //Control already destroyed
+ if (this.element === null) {
+
+ return;
+ }
+ var Class = this.constructor,
+ pluginName = Class.pluginName || Class._fullName,
+ controls;
+
+ // Unbind bindings.
+ this.off();
+
+ if (pluginName && pluginName !== 'can_control') {
+ // Remove the `className`.
+ this.element.removeClass(pluginName);
+ }
+
+ // Remove from `data`.
+ controls = can.data(this.element, "controls");
+ controls.splice(can.inArray(this, controls), 1);
+
+ can.trigger(this, "destroyed"); // In case we want to know if the `control` is removed.
+
+ this.element = null;
+ }
+ });
+
+ var processors = can.Control.processors,
+ // Processors do the binding.
+ // They return a function that unbinds when called.
+ // The basic processor that binds events.
+ basicProcessor = function(el, event, selector, methodName, control) {
+ return binder(el, event, can.Control._shifter(control, methodName), selector);
+ };
+
+ // Set common events to be processed as a `basicProcessor`
+ each(["change", "click", "contextmenu", "dblclick", "keydown", "keyup",
+ "keypress", "mousedown", "mousemove", "mouseout", "mouseover",
+ "mouseup", "reset", "resize", "scroll", "select", "submit", "focusin",
+ "focusout", "mouseenter", "mouseleave",
+ // #104 - Add touch events as default processors
+ // TOOD feature detect?
+ "touchstart", "touchmove", "touchcancel", "touchend", "touchleave"
+ ], function(v) {
+ processors[v] = basicProcessor;
+ });
+
+ return Control;
+ })(__m3, __m1);
+
+ // ## util/string/deparam/deparam.js
+ var __m20 = (function(can) {
+
+ // ## deparam.js
+ // `can.deparam`
+ // _Takes a string of name value pairs and returns a Object literal that represents those params._
+ var digitTest = /^\d+$/,
+ keyBreaker = /([^\[\]]+)|(\[\])/g,
+ paramTest = /([^?#]*)(#.*)?$/,
+ prep = function(str) {
+ return decodeURIComponent(str.replace(/\+/g, " "));
+ };
+
+
+ can.extend(can, {
+
+ deparam: function(params) {
+
+ var data = {},
+ pairs, lastPart;
+
+ if (params && paramTest.test(params)) {
+
+ pairs = params.split('&'),
+
+ can.each(pairs, function(pair) {
+
+ var parts = pair.split('='),
+ key = prep(parts.shift()),
+ value = prep(parts.join("=")),
+ current = data;
+
+ if (key) {
+ parts = key.match(keyBreaker);
+
+ for (var j = 0, l = parts.length - 1; j < l; j++) {
+ if (!current[parts[j]]) {
+ // If what we are pointing to looks like an `array`
+ current[parts[j]] = digitTest.test(parts[j + 1]) || parts[j + 1] == "[]" ? [] : {};
+ }
+ current = current[parts[j]];
+ }
+ lastPart = parts.pop();
+ if (lastPart == "[]") {
+ current.push(value);
+ } else {
+ current[lastPart] = value;
+ }
+ }
+ });
+ }
+ return data;
+ }
+ });
+ return can;
+ })(__m3, __m2);
+
+ // ## route/route.js
+ var __m19 = (function(can) {
+
+ // ## route.js
+ // `can.route`
+ // _Helps manage browser history (and client state) by synchronizing the
+ // `window.location.hash` with a `can.Observe`._
+ // Helper methods used for matching routes.
+ var
+ // `RegExp` used to match route variables of the type ':name'.
+ // Any word character or a period is matched.
+ matcher = /\:([\w\.]+)/g,
+ // Regular expression for identifying &key=value lists.
+ paramsMatcher = /^(?:&[^=]+=[^&]*)+/,
+ // Converts a JS Object into a list of parameters that can be
+ // inserted into an html element tag.
+ makeProps = function(props) {
+ var tags = [];
+ can.each(props, function(val, name) {
+ tags.push((name === 'className' ? 'class' : name) + '="' +
+ (name === "href" ? val : can.esc(val)) + '"');
+ });
+ return tags.join(" ");
+ },
+ // Checks if a route matches the data provided. If any route variable
+ // is not present in the data, the route does not match. If all route
+ // variables are present in the data, the number of matches is returned
+ // to allow discerning between general and more specific routes.
+ matchesData = function(route, data) {
+ var count = 0,
+ i = 0,
+ defaults = {};
+ // look at default values, if they match ...
+ for (var name in route.defaults) {
+ if (route.defaults[name] === data[name]) {
+ // mark as matched
+ defaults[name] = 1;
+ count++;
+ }
+ }
+ for (; i < route.names.length; i++) {
+ if (!data.hasOwnProperty(route.names[i])) {
+ return -1;
+ }
+ if (!defaults[route.names[i]]) {
+ count++;
+ }
+
+ }
+
+ return count;
+ },
+ onready = !0,
+ location = window.location,
+ wrapQuote = function(str) {
+ return (str + '').replace(/([.?*+\^$\[\]\\(){}|\-])/g, "\\$1");
+ },
+ each = can.each,
+ extend = can.extend;
+
+ can.route = function(url, defaults) {
+ defaults = defaults || {};
+ // Extract the variable names and replace with `RegExp` that will match
+ // an atual URL with values.
+ var names = [],
+ test = url.replace(matcher, function(whole, name, i) {
+ names.push(name);
+ var next = "\\" + (url.substr(i + whole.length, 1) || can.route._querySeparator);
+ // a name without a default value HAS to have a value
+ // a name that has a default value can be empty
+ // The `\\` is for string-escaping giving single `\` for `RegExp` escaping.
+ return "([^" + next + "]" + (defaults[name] ? "*" : "+") + ")";
+ });
+
+ // Add route in a form that can be easily figured out.
+ can.route.routes[url] = {
+ // A regular expression that will match the route when variable values
+ // are present; i.e. for `:page/:type` the `RegExp` is `/([\w\.]*)/([\w\.]*)/` which
+ // will match for any value of `:page` and `:type` (word chars or period).
+ test: new RegExp("^" + test + "($|" + wrapQuote(can.route._querySeparator) + ")"),
+ // The original URL, same as the index for this entry in routes.
+ route: url,
+ // An `array` of all the variable names in this route.
+ names: names,
+ // Default values provided for the variables.
+ defaults: defaults,
+ // The number of parts in the URL separated by `/`.
+ length: url.split('/').length
+ };
+ return can.route;
+ };
+
+
+ extend(can.route, {
+
+ _querySeparator: '&',
+ _paramsMatcher: paramsMatcher,
+
+
+ param: function(data, _setRoute) {
+ // Check if the provided data keys match the names in any routes;
+ // Get the one with the most matches.
+ var route,
+ // Need to have at least 1 match.
+ matches = 0,
+ matchCount,
+ routeName = data.route,
+ propCount = 0;
+
+ delete data.route;
+
+ each(data, function() {
+ propCount++;
+ });
+ // Otherwise find route.
+ each(can.route.routes, function(temp, name) {
+ // best route is the first with all defaults matching
+
+
+ matchCount = matchesData(temp, data);
+ if (matchCount > matches) {
+ route = temp;
+ matches = matchCount;
+ }
+ if (matchCount >= propCount) {
+ return false;
+ }
+ });
+ // If we have a route name in our `can.route` data, and it's
+ // just as good as what currently matches, use that
+ if (can.route.routes[routeName] && matchesData(can.route.routes[routeName], data) === matches) {
+ route = can.route.routes[routeName];
+ }
+ // If this is match...
+ if (route) {
+ var cpy = extend({}, data),
+ // Create the url by replacing the var names with the provided data.
+ // If the default value is found an empty string is inserted.
+ res = route.route.replace(matcher, function(whole, name) {
+ delete cpy[name];
+ return data[name] === route.defaults[name] ? "" : encodeURIComponent(data[name]);
+ }),
+ after;
+ // Remove matching default values
+ each(route.defaults, function(val, name) {
+ if (cpy[name] === val) {
+ delete cpy[name];
+ }
+ });
+
+ // The remaining elements of data are added as
+ // `&` separated parameters to the url.
+ after = can.param(cpy);
+ // if we are paraming for setting the hash
+ // we also want to make sure the route value is updated
+ if (_setRoute) {
+ can.route.attr('route', route.route);
+ }
+ return res + (after ? can.route._querySeparator + after : "");
+ }
+ // If no route was found, there is no hash URL, only paramters.
+ return can.isEmptyObject(data) ? "" : can.route._querySeparator + can.param(data);
+ },
+
+ deparam: function(url) {
+ // See if the url matches any routes by testing it against the `route.test` `RegExp`.
+ // By comparing the URL length the most specialized route that matches is used.
+ var route = {
+ length: -1
+ };
+ each(can.route.routes, function(temp, name) {
+ if (temp.test.test(url) && temp.length > route.length) {
+ route = temp;
+ }
+ });
+ // If a route was matched.
+ if (route.length > -1) {
+
+ var // Since `RegExp` backreferences are used in `route.test` (parens)
+ // the parts will contain the full matched string and each variable (back-referenced) value.
+ parts = url.match(route.test),
+ // Start will contain the full matched string; parts contain the variable values.
+ start = parts.shift(),
+ // The remainder will be the `&key=value` list at the end of the URL.
+ remainder = url.substr(start.length - (parts[parts.length - 1] === can.route._querySeparator ? 1 : 0)),
+ // If there is a remainder and it contains a `&key=value` list deparam it.
+ obj = (remainder && can.route._paramsMatcher.test(remainder)) ? can.deparam(remainder.slice(1)) : {};
+
+ // Add the default values for this route.
+ obj = extend(true, {}, route.defaults, obj);
+ // Overwrite each of the default values in `obj` with those in
+ // parts if that part is not empty.
+ each(parts, function(part, i) {
+ if (part && part !== can.route._querySeparator) {
+ obj[route.names[i]] = decodeURIComponent(part);
+ }
+ });
+ obj.route = route.route;
+ return obj;
+ }
+ // If no route was matched, it is parsed as a `&key=value` list.
+ if (url.charAt(0) !== can.route._querySeparator) {
+ url = can.route._querySeparator + url;
+ }
+ return can.route._paramsMatcher.test(url) ? can.deparam(url.slice(1)) : {};
+ },
+
+ data: new can.Observe({}),
+
+ routes: {},
+
+ ready: function(val) {
+ if (val === false) {
+ onready = val;
+ }
+ if (val === true || onready === true) {
+ can.route._setup();
+ setState();
+ }
+ return can.route;
+ },
+
+ url: function(options, merge) {
+ if (merge) {
+ options = extend({}, curParams, options)
+ }
+ return "#!" + can.route.param(options);
+ },
+
+ link: function(name, options, props, merge) {
+ return "<a " + makeProps(
+ extend({
+ href: can.route.url(options, merge)
+ }, props)) + ">" + name + "</a>";
+ },
+
+ current: function(options) {
+ return location.hash == "#!" + can.route.param(options)
+ },
+ _setup: function() {
+ // If the hash changes, update the `can.route.data`.
+ can.bind.call(window, 'hashchange', setState);
+ },
+ _getHash: function() {
+ return location.href.split(/#!?/)[1] || "";
+ },
+ _setHash: function(serialized) {
+ var path = (can.route.param(serialized, true));
+ location.hash = "#!" + path;
+ return path;
+ }
+ });
+
+
+ // The functions in the following list applied to `can.route` (e.g. `can.route.attr('...')`) will
+ // instead act on the `can.route.data` observe.
+ each(['bind', 'unbind', 'delegate', 'undelegate', 'attr', 'removeAttr'], function(name) {
+ can.route[name] = function() {
+ // `delegate` and `undelegate` require
+ // the `can/observe/delegate` plugin
+ if (!can.route.data[name]) {
+ return;
+ }
+
+ return can.route.data[name].apply(can.route.data, arguments);
+ }
+ })
+
+ var // A ~~throttled~~ debounced function called multiple times will only fire once the
+ // timer runs down. Each call resets the timer.
+ timer,
+ // Intermediate storage for `can.route.data`.
+ curParams,
+ // Deparameterizes the portion of the hash of interest and assign the
+ // values to the `can.route.data` removing existing values no longer in the hash.
+ // setState is called typically by hashchange which fires asynchronously
+ // So it's possible that someone started changing the data before the
+ // hashchange event fired. For this reason, it will not set the route data
+ // if the data is changing or the hash already matches the hash that was set.
+ setState = can.route.setState = function() {
+ var hash = can.route._getHash();
+ curParams = can.route.deparam(hash);
+
+ // if the hash data is currently changing, or
+ // the hash is what we set it to anyway, do NOT change the hash
+ if (!changingData || hash !== lastHash) {
+ can.route.attr(curParams, true);
+ }
+ },
+ // The last hash caused by a data change
+ lastHash,
+ // Are data changes pending that haven't yet updated the hash
+ changingData;
+
+ // If the `can.route.data` changes, update the hash.
+ // Using `.serialize()` retrieves the raw data contained in the `observable`.
+ // This function is ~~throttled~~ debounced so it only updates once even if multiple values changed.
+ // This might be able to use batchNum and avoid this.
+ can.route.bind("change", function(ev, attr) {
+ // indicate that data is changing
+ changingData = 1;
+ clearTimeout(timer);
+ timer = setTimeout(function() {
+ // indicate that the hash is set to look like the data
+ changingData = 0;
+ var serialized = can.route.data.serialize();
+
+ lastHash = can.route._setHash(serialized);
+ }, 1);
+ });
+ // `onready` event...
+ can.bind.call(document, "ready", can.route.ready);
+
+ // Libraries other than jQuery don't execute the document `ready` listener
+ // if we are already DOM ready
+ if ((document.readyState === 'complete' || document.readyState === "interactive") && onready) {
+ can.route.ready();
+ }
+
+ // extend route to have a similar property
+ // that is often checked in mustache to determine
+ // an object's observability
+ can.route.constructor.canMakeObserve = can.Observe.canMakeObserve;
+
+ return can.route;
+ })(__m3, __m7, __m20);
+
+ // ## control/route/route.js
+ var __m21 = (function(can) {
+
+ // ## control/route.js
+ // _Controller route integration._
+
+ can.Control.processors.route = function(el, event, selector, funcName, controller) {
+ selector = selector || "";
+ can.route(selector);
+ var batchNum,
+ check = function(ev, attr, how) {
+ if (can.route.attr('route') === (selector) &&
+ (ev.batchNum === undefined || ev.batchNum !== batchNum)) {
+
+ batchNum = ev.batchNum;
+
+ var d = can.route.attr();
+ delete d.route;
+ if (can.isFunction(controller[funcName])) {
+ controller[funcName](d);
+ } else {
+ controller[controller[funcName]](d);
+ }
+
+ }
+ };
+ can.route.bind('change', check);
+ return function() {
+ can.route.unbind('change', check);
+ };
+ };
+
+ return can;
+ })(__m3, __m19, __m18);
+
+ window['can'] = __m5;
+ })();
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.min.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.min.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.jquery.min.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,11 @@
+/*!
+ * CanJS - 1.1.6
+ * http://canjs.us/
+ * Copyright (c) 2013 Bitovi
+ * Wed, 29 May 2013 18:59:22 GMT
+ * Licensed MIT
+ * Includes: CanJS default build
+ * Download from: http://canjs.us/
+ */
+!function(undefined){var __m5=function(){var a=window.can||{};("undefined"==typeof GLOBALCAN||GLOBALCAN!==!1)&&(window.can=a),a.isDeferred=function(a){var b=this.isFunction;return a&&b(a.then)&&b(a.pipe)};var b=0;return a.cid=function(a,c){return a._cid?a._cid:a._cid=(c||"")+ ++b},a.VERSION="@EDGE",a}(),__m6=function(a){return a.each=function(a,b,c){var d,e=0;if(a)if("number"==typeof a.length&&a.pop)for(a.attr&&a.attr("length"),d=a.length;d>e&&b.call(c||a[e],a[e],e,a)!==!1;e++);else if(a.hasOwnProperty)for(d in a)if(a.hasOwnProperty(d)&&b.call(c||a[d],a[d],d,a)===!1)break;return a},a}(__m5),__m3=function(a,b){a.extend(b,a,{trigger:function(b,c,d){b.trigger?b.trigger(c,d):a.event.trigger(c,d,b,!0)},addEvent:function(b,c){return a([this]).bind(b,c),this},removeEvent:function(b,c){return a([this]).unbind(b,c),this},buildFragment:function(b,c){var d,e=a.buildFragment;return b=[b],c=c||document,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,d=e.call(jQuery,b,c),d.cacheable?a.clone(d.fragment):d.fragment||d},$:a,each:b.each}),a.each(["bind","unbind","undelegate","delegate"],function(c,d){b[d]=function(){var b=this[d]?this:a([this]);return b[d].apply(b,arguments),this}}),a.each(["append","filter","addClass","remove","data","get"],function(a,c){b[c]=function(a){return a[c].apply(a,b.makeArray(arguments).slice(1))}});var c=a.cleanData;return a.cleanData=function(d){a.each(d,function(a,c){c&&b.trigger(c,"destroyed",[],!1)}),c(d)},b}(jQuery,__m5,__m6),__m2=function(a){var b=/_|-/,c=/\=\=/,d=/([A-Z]+)([A-Z][a-z])/g,e=/([a-z\d])([A-Z])/g,f=/([a-z\d])([A-Z])/g,g=/\{([^\}]+)\}/g,h=/"/g,i=/'/g,j=function(a,b,c){var d=a[b];return d===undefined&&c===!0&&(d=a[b]={}),d},k=function(a){return/^f|^o/.test(typeof a)};return a.extend(a,{esc:function(a){var b=null===a||a===undefined||isNaN(a)&&"NaN"==""+a;return(""+(b?"":a)).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(h,""").replace(i,"'")},getObject:function(b,c,d){var e,f,g,h,i=b?b.split("."):[],l=i.length,m=0;if(c=a.isArray(c)?c:[c||window],h=c.length,!l)return c[0];for(m;h>m;m++){for(e=c[m],g=undefined,f=0;l>f&&k(e);f++)g=e,e=j(g,i[f]);if(g!==undefined&&e!==undefined)break}if(d===!1&&e!==undefined&&delete g[i[f-1]],d===!0&&e===undefined)for(e=c[0],f=0;l>f&&k(e);f++)e=j(e,i[f],!0);return e},capitalize:function(a){return a.charAt(0).toUpperCase()+a.slice(1)},underscore:function(a){return a.replace(c,"/").replace(d,"$1_$2").replace(e,"$1_$2").replace(f,"_").toLowerCase()},sub:function(b,c,d){var e=[];return b=b||"",e.push(b.replace(g,function(b,f){var g=a.getObject(f,c,d===!0?!1:undefined);return g===undefined?(e=null,""):k(g)&&e?(e.push(g),""):""+g})),null===e?e:e.length<=1?e[0]:e},replacer:g,undHash:b}),a}(__m3),__m1=function(a){var b=0;return a.Construct=function(){return arguments.length?a.Construct.extend.apply(a.Construct,arguments):void 0},a.extend(a.Construct,{newInstance:function(){var a,b=this.instance();return b.setup&&(a=b.setup.apply(b,arguments)),b.init&&b.init.apply(b,a||arguments),b},_inherit:function(b,c,d){a.extend(d||b,b||{})},_overwrite:function(a,b,c,d){a[c]=d},setup:function(b){this.defaults=a.extend(!0,{},b.defaults,this.defaults)},instance:function(){b=1;var a=new this;return b=0,a},extend:function(c,d,e){function f(){return b?void 0:this.constructor!==f&&arguments.length?arguments.callee.extend.apply(arguments.callee,arguments):this.constructor.newInstance.apply(this.constructor,arguments)}"string"!=typeof c&&(e=d,d=c,c=null),e||(e=d,d=null),e=e||{};var g,h,i,j,k=this,l=this.prototype;j=this.instance(),a.Construct._inherit(e,l,j);for(g in k)k.hasOwnProperty(g)&&(f[g]=k[g]);if(a.Construct._inherit(d,k,f),c){var m=c.split("."),h=m.pop(),n=a.getObject(m.join("."),window,!0),i=n,o=a.underscore(c.replace(/\./g,"_")),p=a.underscore(h);n[h]=f}a.extend(f,{constructor:f,prototype:j,namespace:i,_shortName:p,fullName:c,_fullName:o}),h!==undefined&&(f.shortName=h),f.prototype.constructor=f;var q=[k].concat(a.makeArray(arguments)),r=f.setup.apply(f,q);return f.init&&f.init.apply(f,r||q),f}}),a.Construct}(__m2),__m8=function(a){return a.bindAndSetup=function(){return a.addEvent.apply(this,arguments),this._init||(this._bindings?this._bindings++:(this._bindings=1,this._bindsetup&&this._bindsetup())),this},a.unbindAndTeardown=function(){return a.removeEvent.apply(this,arguments),this._bindings--,this._bindings||this._bindteardown&&this._bindteardown(),this},a}(__m3),__m7=function(a){var b=function(b){return b&&!a.isDeferred(b)&&(a.isArray(b)||a.isPlainObject(b)||b instanceof a.Observe)},c=function(b,c){return a.each(b,function(a){a&&a.unbind&&a.unbind("change"+c)})},d=function(b,d,g,h,i){return h=h||f,i=i||f.List,b instanceof f?g._bindings&&c([b],g._cid):b=a.isArray(b)?new i(b):new h(b),g._bindings&&e(b,d,g),b},e=function(b,c,d){b.bind("change"+d._cid,function(){var e=a.makeArray(arguments),f=e.shift();e[0]=("*"===c?[d.indexOf(b),e[0]]:[c,e[0]]).join("."),f.triggeredNS=f.triggeredNS||{},f.triggeredNS[d._cid]||(f.triggeredNS[d._cid]=!0,a.trigger(d,f,e))})};observeId=0,serialize=function(c,d,e){return c.each(function(c,f){e[f]=b(c)&&a.isFunction(c[d])?c[d]():c}),e},attrParts=function(b,c){return c?[b]:a.isArray(b)?b:(""+b).split(".")},batchNum=1,transactions=0,batchEvents=[],stopCallbacks=[],makeBindSetup=function(a){return function(){var b=this;this._each(function(c,d){c&&c.bind&&e(c,a||d,b)})}};var f=a.Map=a.Observe=a.Construct({bind:a.bindAndSetup,unbind:a.unbindAndTeardown,id:"id",canMakeObserve:b,startBatch:function(a){transactions++,a&&stopCallbacks.push(a)},stopBatch:function(b,c){if(b?transactions=0:transactions--,0==transactions){var d=batchEvents.slice(0),e=stopCallbacks.slice(0);batchEvents=[],stopCallbacks=[],batchNum++,c&&this.startBatch(),a.each(d,function(b){a.trigger.apply(a,b)}),a.each(e,function(a){a()})}},triggerBatch:function(b,c,d){if(!b._init){if(0==transactions)return a.trigger(b,c,d);c="string"==typeof c?{type:c}:c,c.batchNum=batchNum,batchEvents.push([b,c,d])}},keys:function(a){var b=[];f.__reading&&f.__reading(a,"__keys");for(var c in a._data)b.push(c);return b}},{setup:function(b){this._data={},a.cid(this,".observe"),this._init=1,this.attr(b),this.bind("change"+this._cid,a.proxy(this._changes,this)),delete this._init},_bindsetup:makeBindSetup(),_bindteardown:function(){var a=this._cid;this._each(function(b){c([b],a)})},_changes:function(a,b,c,d,e){f.triggerBatch(this,{type:b,batchNum:a.batchNum},[d,e])},_triggerChange:function(){f.triggerBatch(this,"change",a.makeArray(arguments))},_each:function(a){var b=this.__get();for(var c in b)b.hasOwnProperty(c)&&a(b[c],c)},attr:function(a,b){var c=typeof a;return"string"!==c&&"number"!==c?this._attrs(a,b):b===undefined?(f.__reading&&f.__reading(this,a),this._get(a)):(this._set(a,b),this)},each:function(){return f.__reading&&f.__reading(this,"__keys"),a.each.apply(undefined,[this.__get()].concat(a.makeArray(arguments)))},removeAttr:function(b){var c=this instanceof a.Observe.List,d=attrParts(b),e=d.shift(),g=c?this[e]:this._data[e];return d.length?g.removeAttr(d):(c?this.splice(e,1):e in this._data&&(delete this._data[e],e in this.constructor.prototype||delete this[e],f.triggerBatch(this,"__keys"),this._triggerChange(e,"remove",undefined,g)),g)},_get:function(a){var b="string"==typeof a&&!!~a.indexOf(".")&&this.__get(a);if(b)return b;var c=attrParts(a),d=this.__get(c.shift());return c.length?d?d._get(c):undefined:d},__get:function(a){return a?this._data[a]:this._data},_set:function(a,c,d){var e=attrParts(a,d),f=e.shift(),g=this.__get(f);if(b(g)&&e.length)g._set(e,c);else{if(e.length)throw"can.Observe: Object does not exist";this.__convert&&(c=this.__convert(f,c)),this.__set(f,c,g)}},__set:function(a,e,g){if(e!==g){var h=this.__get().hasOwnProperty(a)?"set":"add";this.___set(a,b(e)?d(e,a,this):e),"add"==h&&f.triggerBatch(this,"__keys",undefined),this._triggerChange(a,h,e,g),g&&c([g],this._cid)}},___set:function(a,b){this._data[a]=b,a in this.constructor.prototype||(this[a]=b)},bind:a.bindAndSetup,unbind:a.unbindAndTeardown,serialize:function(){return serialize(this,"serialize",{})},_attrs:function(c,d){if(c===undefined)return serialize(this,"attr",{});c=a.extend({},c);var e,g,h=this;f.startBatch(),this.each(function(e,f){return g=c[f],g===undefined?(d&&h.removeAttr(f),void 0):(h.__convert&&(g=h.__convert(f,g)),g instanceof a.Observe?h.__set(f,g,e):b(e)&&b(g)&&e.attr?e.attr(g,d):e!=g&&h.__set(f,g,e),delete c[f],void 0)});for(var e in c)g=c[e],this._set(e,g,!0);return f.stopBatch(),this},compute:function(b){return a.compute(this,b)}}),g=[].splice,h=f({setup:function(b,c){this.length=0,a.cid(this,".observe"),this._init=1,a.isDeferred(b)?this.replace(b):this.push.apply(this,a.makeArray(b||[])),this.bind("change"+this._cid,a.proxy(this._changes,this)),a.extend(this,c),delete this._init},_triggerChange:function(a,b,c,d){f.prototype._triggerChange.apply(this,arguments),~a.indexOf(".")||("add"===b?(f.triggerBatch(this,b,[c,+a]),f.triggerBatch(this,"length",[this.length])):"remove"===b?(f.triggerBatch(this,b,[d,+a]),f.triggerBatch(this,"length",[this.length])):f.triggerBatch(this,b,[c,+a]))},__get:function(a){return a?this[a]:this},___set:function(a,b){this[a]=b,+a>=this.length&&(this.length=+a+1)},_each:function(a){for(var b=this.__get(),c=0;c<b.length;c++)a(b[c],c)},_bindsetup:makeBindSetup("*"),serialize:function(){return serialize(this,"serialize",[])},splice:function(e,f){var h,i=a.makeArray(arguments);for(h=2;h<i.length;h++){var j=i[h];b(j)&&(i[h]=d(j,"*",this,this.constructor.Observe,this.constructor))}f===undefined&&(f=i[1]=this.length-e);var k=g.apply(this,i);return a.Observe.startBatch(),f>0&&(this._triggerChange(""+e,"remove",undefined,k),c(k,this._cid)),i.length>2&&this._triggerChange(""+e,"add",i.slice(2),k),a.Observe.stopBatch(),k},_attrs:function(b,c){return b===undefined?serialize(this,"attr",[]):(b=a.makeArray(b),f.startBatch(),this._updateAttrs(b,c),f.stopBatch(),void 0)},_updateAttrs:function(a,c){for(var d=Math.min(a.length,this.length),e=0;d>e;e++){var f=this[e],g=a[e];b(f)&&b(g)?f.attr(g,c):f!=g&&this._set(e,g)}a.length>this.length?this.push.apply(this,a.slice(this.length)):a.length<this.length&&c&&this.splice(a.length)}}),i=function(b){return b[0]&&a.isArray(b[0])?b[0]:a.makeArray(b)};return a.each({push:"length",unshift:0},function(a,c){var e=[][c];h.prototype[c]=function(){var c,f,g=[],h=a?this.length:0,i=arguments.length;for(this.constructor;i--;)f=arguments[i],g[i]=b(f)?d(f,"*",this,this.constructor.Observe,this.constructor):f;return c=e.apply(this,g),(!this.comparator||g.length)&&this._triggerChange(""+h,"add",g,undefined),c}}),a.each({pop:"length",shift:0},function(a,b){h.prototype[b]=function(){var c=i(arguments),d=a&&this.length?this.length-1:0,e=[][b].apply(this,c);return this._triggerChange(""+d,"remove",undefined,[e]),e&&e.unbind&&e.unbind("change"+this._cid),e}}),a.extend(h.prototype,{indexOf:function(b){return this.attr("length"),a.inArray(b,this)},join:[].join,reverse:[].reverse,slice:function(){var a=Array.prototype.slice.apply(this,arguments);return new this.constructor(a)},concat:function(){var b=[];return a.each(a.makeArray(arguments),function(c,d){b[d]=c instanceof a.Observe.List?c.serialize():c}),new this.constructor(Array.prototype.concat.apply(this.serialize(),b))},forEach:function(b,c){a.each(this,b,c||this)},replace:function(b){return a.isDeferred(b)?b.then(a.proxy(this.replace,this)):this.splice.apply(this,[0,this.length].concat(a.makeArray(b||[]))),this}}),a.List=f.List=h,f.setup=function(){a.Construct.setup.apply(this,arguments),this.List=f.List({Observe:this},{})},f}(__m3,__m8,__m1),__m9=function(a){var b=function(b,c){var d;a.Observe&&(d=a.Observe.__reading,a.Observe.__reading=function(a,b){e.push({obj:a,attr:b+""})});var e=[],f=b.call(c);return a.Observe&&(a.Observe.__reading=d),{value:f,observed:e}},c=function(c,d,e,f){var g,h={},i=!0,j={value:undefined,teardown:function(){for(var a in h){var b=h[a];b.observe.obj.unbind(b.observe.attr,k),delete h[a]}}},k=function(a){if(!(f&&!f.bound||a.batchNum!==undefined&&a.batchNum===g)){var b=j.value,c=l();j.value=c,c!==b&&e(c,b),g=g=a.batchNum}},l=function(){var e=b(c,d),f=e.observed,g=e.value;i=!i,a.each(f,function(a){h[a.obj._cid+"|"+a.attr]?h[a.obj._cid+"|"+a.attr].matched=i:(h[a.obj._cid+"|"+a.attr]={matched:i,observe:a},a.obj.bind(a.attr,k))});for(var j in h){var l=h[j];l.matched!==i&&(l.observe.obj.unbind(l.observe.attr,k),delete h[j])}return g};return j.value=l(),j.isListening=!a.isEmptyObject(h),j};return a.compute=function(d,e,f){if(d&&d.isComputed)return d;var g,h,i,j={bound:!1,hasDependencies:!1},k=function(){},l=function(){},m=function(){return i},n=function(a){i=a},o=!0;if(h=function(b){if(arguments.length){var c=i,d=n.call(e,b,c);return h.hasDependencies?m.call(e):(i=d===undefined?m.call(e):d,c!==i&&a.Observe.triggerBatch(h,"change",[i,c]),i)}return a.Observe.__reading&&o&&a.Observe.__reading(h,"change"),j.bound?i:m.call(e)},"function"==typeof d)n=d,m=d,o=f===!1?!1:!0,h.hasDependencies=!1,k=function(a){g=c(d,e||this,a,j),h.hasDependencies=g.isListening,i=g.value},l=function(){g.teardown()};else if(e)if("string"==typeof e){var p=e,q=d instanceof a.Observe;q&&(h.hasDependencies=!0),m=function(){return q?d.attr(p):d[p]},n=function(a){q?d.attr(p,a):d[p]=a};var r;k=function(c){r=function(){c(m(),i)},a.bind.call(d,f||p,r),i=b(m).value},l=function(){a.unbind.call(d,f||p,r)}}else if("function"==typeof e)i=d,n=e;else{i=d;var s=e;m=s.get||m,n=s.set||n,k=s.on||k,l=s.off||l}else i=d;h.isComputed=!0,a.cid(h,"compute");var t=function(b,c){i=b,a.Observe.triggerBatch(h,"change",[b,c])};return a.extend(h,{_bindsetup:function(){j.bound=!0,k.call(this,t)},_bindteardown:function(){l.call(this,t),j.bound=!1},bind:a.bindAndSetup,unbind:a.unbindAndTeardown})},a.compute.binder=c,a.compute}(__m3,__m8),__m10=function(a){var b=function(b,c,d){var e=new a.Deferred;return b.then(function(){var b=a.makeArray(arguments);b[0]=c[d](b[0]),e.resolveWith(e,b)},function(){e.rejectWith(this,arguments)}),"function"==typeof b.abort&&(e.abort=function(){return b.abort()}),e},c=0,d=function(b){return a.Observe.__reading&&a.Observe.__reading(b,b.constructor.id),b.__get(b.constructor.id)},e=function(b,c,d,e,f,g){var h={};if("string"==typeof b){var i=b.split(/\s+/);h.url=i.pop(),i.length&&(h.type=i.pop())}else a.extend(h,b);return h.data="object"!=typeof c||a.isArray(c)?c:a.extend(h.data||{},c),h.url=a.sub(h.url,h.data,!0),a.ajax(a.extend({type:d||"post",dataType:e||"json",success:f,error:g},h))},f=function(b,c,e,f,g){var h;a.isArray(b)?(h=b[1],b=b[0]):h=b.serialize(),h=[h];var i,j,k=b.constructor;return"destroy"==c&&h.shift(),"create"!==c&&h.unshift(d(b)),j=k[c].apply(k,h),i=j.pipe(function(a){return b[g||c+"d"](a,j),b}),j.abort&&(i.abort=function(){j.abort()}),i.then(e,f),i},g={create:{url:"_shortName",type:"post"},update:{data:function(b,c){c=c||{};var d=this.id;return c[d]&&c[d]!==b&&(c["new"+a.capitalize(b)]=c[d],delete c[d]),c[d]=b,c},type:"put"},destroy:{type:"delete",data:function(a){var b={};return b.id=b[this.id]=a,b}},findAll:{url:"_shortName"},findOne:{}},h=function(a,b){return function(c){return c=a.data?a.data.apply(this,arguments):c,e(b||this[a.url||"_url"],c,a.type||"get")}};a.Model=a.Observe({fullName:"can.Model",_reqs:0,setup:function(b){if(this.store={},a.Observe.setup.apply(this,arguments),a.Model){this.List=i({Observe:this},{});var d=this,e=a.proxy(this._clean,d);a.each(g,function(c,f){if(a.isFunction(d[f])||(d[f]=h(c,d[f])),d["make"+a.capitalize(f)]){var g=d["make"+a.capitalize(f)](d[f]);a.Construct._overwrite(d,b,f,function(){a.Model._reqs++;var b=g.apply(this,arguments),c=b.then(e,e);return c.abort=b.abort,c})}}),"can.Model"!=d.fullName&&d.fullName||(d.fullName="Model"+ ++c),a.Model._reqs=0,this._url=this._shortName+"/{"+this.id+"}"}},_ajax:h,_makeRequest:f,_clean:function(){if(a.Model._reqs--,!a.Model._reqs)for(var b in this.store)this.store[b]._bindings||delete this.store[b];return arguments[0]},models:function(b,c){if(a.Model._reqs++,b){if(b instanceof this.List)return b;var d=this,e=[],f=c instanceof a.Observe.List?c:new(d.List||i),g=a.isArray(b),h=b instanceof i,j=g?b:h?b.serialize():b.data;return f.length&&f.splice(0),a.each(j,function(a){e.push(d.model(a))}),f.push.apply(f,e),g||a.each(b,function(a,b){"data"!==b&&f.attr(b,a)}),setTimeout(a.proxy(this._clean,this),1),f}},model:function(b){if(b){b instanceof this&&(b=b.serialize());var c=b[this.id],d=(c||0===c)&&this.store[c]?this.store[c].attr(b,this.removeAttr||!1):new this(b);return a.Model._reqs&&(this.store[b[this.id]]=d),d}}},{isNew:function(){var a=d(this);return!(a||0===a)},save:function(a,b){return f(this,this.isNew()?"create":"update",a,b)},destroy:function(b,c){if(this.isNew()){var d=this,e=a.Deferred();return e.then(b,c),e.done(function(a){d.destroyed(a)}).resolve(d)}return f(this,"destroy",b,c,"destroyed")},_bindsetup:function(){return this.constructor.store[this.__get(this.constructor.id)]=this,a.Observe.prototype._bindsetup.apply(this,arguments)},_bindteardown:function(){return delete this.constructor.store[d(this)],a.Observe.prototype._bindteardown.apply(this,arguments)},___set:function(b,c){a.Observe.prototype.___set.call(this,b,c),b===this.constructor.id&&this._bindings&&(this.constructor.store[d(this)]=this)}}),a.each({makeFindAll:"models",makeFindOne:"model",makeCreate:"model",makeUpdate:"model"},function(c,d){a.Model[d]=function(d){return function(){var e=a.makeArray(arguments),f=a.isFunction(e[1])?e.splice(0,1):e.splice(0,2),g=b(d.apply(this,f),this,c);return g.then(e[0],e[1]),g}}}),a.each(["created","updated","destroyed"],function(b){a.Model.prototype[b]=function(c){var d,e=this.constructor;d=c&&"object"==typeof c&&this.attr(c.attr?c.attr():c),a.trigger(this,"change",b),a.trigger(e,b,this)}});var i=a.Model.List=a.Observe.List({setup:function(b){a.isPlainObject(b)&&!a.isArray(b)?(a.Observe.List.prototype.setup.apply(this),this.replace(this.constructor.Observe.findAll(b))):a.Observe.List.prototype.setup.apply(this,arguments)},_changes:function(b,c){if(a.Observe.List.prototype._changes.apply(this,arguments),/\w+\.destroyed/.test(c)){var d=this.indexOf(b.target);-1!=d&&this.splice(d,1)}}});return a.Model}(__m3,__m7),__m11=function(a){var b=a.isFunction,c=a.makeArray,d=1,e=a.view=a.template=function(c,d,f,g){b(f)&&(g=f,f=undefined);var h=function(a){return e.frag(a)},i=b(g)?function(a){g(h(a))}:null,j=e.render(c,d,f,i),k=a.Deferred();return b(j)?j:a.isDeferred(j)?(j.then(function(a,b){k.resolve.call(k,h(a),b)},function(){k.fail.apply(k,arguments)}),k):h(j)};a.extend(e,{frag:function(a,b){return e.hookup(e.fragment(a),b)},fragment:function(b){var c=a.buildFragment(b,document.body);return c.childNodes.length||c.appendChild(document.createTextNode("")),c},toId:function(b){return a.map(b.toString().split(/\/|\./g),function(a){return a?a:void 0}).join("_")},hookup:function(b,c){var d,f,g=[];return a.each(b.childNodes?a.makeArray(b.childNodes):b,function(b){1===b.nodeType&&(g.push(b),g.push.apply(g,a.makeArray(b.getElementsByTagName("*"))))}),a.each(g,function(a){a.getAttribute&&(d=a.getAttribute("data-view-id"))&&(f=e.hookups[d])&&(f(a,c,d),delete e.hookups[d],a.removeAttribute("data-view-id"))}),b},hookups:{},hook:function(a){return e.hookups[++d]=a," data-view-id='"+d+"'"},cached:{},cachedRenderers:{},cache:!0,register:function(a){this.types["."+a.suffix]=a},types:{},ext:".ejs",registerScript:function(){},preload:function(){},render:function(d,f,j,k){b(j)&&(k=j,j=undefined);var l=h(f);if(l.length){var m=new a.Deferred,n=a.extend({},f);return l.push(g(d,!0)),a.when.apply(a,l).then(function(b){var d,e=c(arguments),g=e.pop();if(a.isDeferred(f))n=i(b);else for(var h in f)a.isDeferred(f[h])&&(n[h]=i(e.shift()));d=g(n,j),m.resolve(d,n),k&&k(d,n)},function(){m.reject.apply(m,arguments)}),m}var o,p=b(k),m=g(d,p);if(p)o=m,m.then(function(a){k(f?a(f,j):a)});else{if("resolved"===m.state()&&m.__view_id){var q=e.cachedRenderers[m.__view_id];return f?q(f,j):q}m.then(function(a){o=f?a(f,j):a})}return o},registerView:function(b,c,d,f){var g=(d||e.types[e.ext]).renderer(b,c);return f=f||new a.Deferred,e.cache&&(e.cached[b]=f,f.__view_id=b,e.cachedRenderers[b]=g),f.resolve(g)}});var f=function(a,b){if(!a.length)throw"can.view: No template or empty template:"+b},g=function(b,c){var d,g,h,i=b.match(/\.[\w\d]+$/);if(b.match(/^#/)&&(b=b.substr(1)),(g=document.getElementById(b))&&(i="."+g.type.match(/\/(x\-)?(.+)/)[2]),i||e.cached[b]||(b+=i=e.ext),a.isArray(i)&&(i=i[0]),h=e.toId(b),b.match(/^\/\//)){var j=b.substr(2);b=window.steal?steal.config().root.mapJoin(""+steal.id(j)):j}if(d=e.types[i],e.cached[h])return e.cached[h];if(g)return e.registerView(h,g.innerHTML,d);var k=new a.Deferred;return a.ajax({async:c,url:b,dataType:"text",error:function(a){f("",b),k.reject(a)},success:function(a){f(a,b),e.registerView(h,a,d,k)}}),k},h=function(b){var c=[];if(a.isDeferred(b))return[b];for(var d in b)a.isDeferred(b[d])&&c.push(b[d]);return c},i=function(b){return a.isArray(b)&&"success"===b[1]?b[0]:b};return window.steal&&steal.type("view js",function(a,b){var c=e.types["."+a.type],d=e.toId(a.id);a.text="steal('"+(c.plugin||"can/view/"+a.type)+"',function(can){return "+"can.view.preload('"+d+"',"+a.text+");\n})",b()}),a.extend(e,{register:function(b){this.types["."+b.suffix]=b,window.steal&&steal.type(b.suffix+" view js",function(a,b){var c=e.types["."+a.type],d=e.toId(a.id+"");a.text=c.script(d,a.text),b()}),e[b.suffix]=function(c,d){if(!d){var f=function(){return e.frag(f.render.apply(this,arguments))};return f.render=function(){var a=b.renderer(null,c);return a.apply(a,arguments)},f}return e.preload(c,b.renderer(c,d)),a.view(c)}},registerScript:function(a,b,c){return"can.view.preload('"+b+"',"+e.types["."+a].script(b,c)+");"},preload:function(b,c){function d(){return e.frag(c.apply(this,arguments))}return e.cached[b]=(new a.Deferred).resolve(function(a,b){return c.call(a,a,b)}),d.render=c,d}}),a}(__m3),__m14=function(){var a={tagToContentPropMap:{option:"textContent"in document.createElement("option")?"textContent":"innerText",textarea:"value"},attrMap:{"class":"className",value:"value",innerText:"innerText",textContent:"textContent",checked:!0,disabled:!0,readonly:!0,required:!0},defaultValue:["input","textarea"],tagMap:{"":"span",table:"tbody",tr:"td",ol:"li",ul:"li",tbody:"tr",thead:"tr",tfoot:"tr",select:"option",optgroup:"option"},reverseTagMap:{tr:"tbody",option:"select",td:"tr",th:"tr",li:"ul"},getParentNode:function(a,b){return b&&11===a.parentNode.nodeType?b:a.parentNode},setAttr:function(b,c,d){var e=b.nodeName.toString().toLowerCase(),f=a.attrMap[c];f===!0?b[c]=!0:f?(b[f]=d,"value"===f&&can.inArray(e,a.defaultValue)>=0&&(b.defaultValue=d)):b.setAttribute(c,d)},getAttr:function(b,c){return(a.attrMap[c]&&b[a.attrMap[c]]?b[a.attrMap[c]]:b.getAttribute(c))||""},removeAttr:function(b,c){a.attrMap[c]===!0?b[c]=!1:b.removeAttribute(c)},contentText:function(a){return"string"==typeof a?a:a||0===a?""+a:""}};return a}(),__m13=function(can,elements){var newLine=/(\r|\n)+/g,clean=function(a){return a.split("\\").join("\\\\").split("\n").join("\\n").split('"').join('\\"').split(" ").join("\\t")},getTag=function(a,b,c){if(a)return a;for(;c<b.length;){if("<"==b[c]&&elements.reverseTagMap[b[c+1]])return elements.reverseTagMap[b[c+1]];c++}return""},bracketNum=function(a){return--a.split("{").length- --a.split("}").length},myEval=function(script){eval(script)},attrReg=/([^\s]+)[\s]*=[\s]*$/,startTxt="var ___v1ew = [];",finishTxt="return ___v1ew.join('')",put_cmd="___v1ew.push(",insert_cmd=put_cmd,htmlTag=null,quote=null,beforeQuote=null,rescan=null,status=function(){return quote?"'"+beforeQuote.match(attrReg)[1]+"'":htmlTag?1:0};return can.view.Scanner=Scanner=function(a){can.extend(this,{text:{},tokens:[]},a),this.tokenReg=[],this.tokenSimple={"<":"<",">":">",'"':'"',"'":"'"},this.tokenComplex=[],this.tokenMap={};for(var b,c=0;b=this.tokens[c];c++)b[2]?(this.tokenReg.push(b[2]),this.tokenComplex.push({abbr:b[1],re:new RegExp(b[2]),rescan:b[3]})):(this.tokenReg.push(b[1]),this.tokenSimple[b[1]]=b[0]),this.tokenMap[b[0]]=b[1];this.tokenReg=new RegExp("("+this.tokenReg.slice(0).concat(["<",">",'"',"'"]).join("|")+")","g")},Scanner.prototype={helpers:[{name:/\s*\(([\$\w]+)\)\s*->([^\n]*)/,fn:function(a){var b=/\s*\(([\$\w]+)\)\s*->([^\n]*)/,c=a.match(b);return"can.proxy(function(__){var "+c[1]+"=can.$(__);"+c[2]+"}, this);"}}],scan:function(a,b){var c=[],d=0,e=this.tokenSimple,f=this.tokenComplex;a=a.replace(newLine,"\n"),this.transform&&(a=this.transform(a)),a.replace(this.tokenReg,function(b,g){var h=arguments[arguments.length-2];if(h>d&&c.push(a.substring(d,h)),e[b])c.push(b);else for(var i,j=0;i=f[j];j++)if(i.re.test(b)){c.push(i.abbr),i.rescan&&c.push(i.rescan(g));break}d=h+g.length}),d<a.length&&c.push(a.substr(d));var g,h,i,j="",k=[startTxt+(this.text.start||"")],l=function(a,b){k.push(put_cmd,'"',clean(a),'"'+(b||"")+");")},m=[],n=null,o=!1,p="",q=[],r=!1,s=0,t=this.tokenMap;for(htmlTag=quote=beforeQuote=null;(i=c[s++])!==undefined;){if(null===n)switch(i){case t.left:case t.escapeLeft:case t.returnLeft:o=htmlTag&&1;case t.commentLeft:n=i,j.length&&l(j),j="";break;case t.escapeFull:o=htmlTag&&1,rescan=1,n=t.escapeLeft,j.length&&l(j),rescan=c[s++],j=rescan.content||rescan,rescan.before&&l(rescan.before),c.splice(s,0,t.right);break;case t.commentFull:break;case t.templateLeft:j+=t.left;break;case"<":0!==c[s].indexOf("!--")&&(htmlTag=1,o=0),j+=i;break;case">":htmlTag=0;var u="/"==j.substr(j.length-1)||"--"==j.substr(j.length-2);o||!r&&elements.tagToContentPropMap[q[q.length-1]]?(u?l(j.substr(0,j.length-1),',can.view.pending(),"/>"'):l(j,',can.view.pending(),">"'),j="",o=0):j+=i,(u||r)&&(q.pop(),p=q[q.length-1],r=!1);break;case"'":case'"':htmlTag&&(quote&"e===i?quote=null:null===quote&&(quote=i,beforeQuote=g));default:"<"===g&&(p=i.split(/\s/)[0],0===p.indexOf("/")&&q[q.length-1]===p.substr(1)?(p=q[q.length-1],r=!0):q.push(p)),j+=i}else switch(i){case t.right:case t.returnRight:switch(n){case t.left:h=bracketNum(j),1==h?(k.push(insert_cmd,"can.view.txt(0,'"+getTag(p,c,s)+"',"+status()+",this,function(){",startTxt,j),m.push({before:"",after:finishTxt+"}));\n"})):(d=m.length&&-1==h?m.pop():{after:";"},d.before&&k.push(d.before),k.push(j,";",d.after));break;case t.escapeLeft:case t.returnLeft:h=bracketNum(j),h&&m.push({before:finishTxt,after:"}));"});for(var v=n===t.escapeLeft?1:0,w={insert:insert_cmd,tagName:getTag(p,c,s),status:status()},x=0;x<this.helpers.length;x++){var y=this.helpers[x];if(y.name.test(j)){j=y.fn(j,w),y.name.source==/^>[\s]*\w*/.source&&(v=0);break}}"object"==typeof j?j.raw&&k.push(j.raw):k.push(insert_cmd,"can.view.txt("+v+",'"+p+"',"+status()+",this,function(){ "+(this.text.escape||"")+"return ",j,h?startTxt:"}));"),rescan&&rescan.after&&rescan.after.length&&(l(rescan.after.length),rescan=null)}n=null,j="";break;case t.templateLeft:j+=t.left;break;default:j+=i}g=i}j.length&&l(j),k.push(";");var z=k.join(""),A={out:"with(_VIEW) { with (_CONTEXT) {"+z+" "+finishTxt+"}}"};return myEval.call(A,"this.fn = (function(_CONTEXT,_VIEW){"+A.out+"});\r\n//@ sourceURL="+b+".js"),A}},Scanner}(__m11,__m14),__m17=function(a){var b=!0;try{document.createTextNode("")._=0}catch(c){b=!1}var d={},e={},f={},g="ejs_"+Math.random(),h=0,i=function(a){if(b||3!==a.nodeType)return a[g]?a[g]:a[g]=(a.nodeName?"element_":"obj_")+ ++h;for(var c in e)if(e[c]===a)return c;return e["text_"+ ++h]=a,"text_"+h},j=function(b,c){var e=d[i(b)];if(e){var f=a.inArray(c,e);f>=0&&e.splice(f,1),e.length||delete d[i(b)]}},k=function(a,b){var c=d[i(a)];c||(c=d[i(a)]=[]),c.push(b)},l={id:i,replace:function(b,c){b=a.makeArray(b);var e=b[0];a.each(a.makeArray(d[i(e)]),function(d){var g=f[d],h=a.inArray(e,g),i=a.inArray(b[b.length-1],g);if(h>=0&&i>=0){for(var m=h;i>=m;m++){var n=g[m];j(n,d)}g.splice.apply(g,[h,i-h+1].concat(c)),a.each(c,function(a){k(a,d)})}else l.unregister(g)})},register:function(b){var c=i(b);f[c]=b,a.each(b,function(a){k(a,c)})},unregister:function(b){var c=i(b);a.each(b,function(a){j(a,c)}),delete f[c]},nodeMap:d,nodeListMap:f};return l}(__m3),__m16=function(a,b,c,d){var e=function(b,c,d){var e=function(){d(f),a.unbind.call(b,"destroyed",e)},f={teardownCheck:function(a){a||e()}};return a.bind.call(b,"destroyed",e),c(f),f},f=function(a,b,c){return e(a,function(){b.bind("change",c)},function(a){b.unbind("change",c),a.nodeList&&d.unregister(a.nodeList)})},g=function(a){return(a||"").replace(/['"]/g,"").split("=")};insertElementsAfter=function(a,b){var c=a[a.length-1];c.nextSibling?c.parentNode.insertBefore(b,c.nextSibling):c.parentNode.appendChild(b)};var h={nodeLists:d,list:function(c,f,g,h,i){var j=[],k=function(b,c,e){var f=document.createDocumentFragment(),k=[];if(a.each(c,function(b){var c=g.call(h,b),d=a.view.frag(c,i);k.push(a.makeArray(d.childNodes)),f.appendChild(d)}),j[e]){var l=j[e][0];l.parentNode.insertBefore(f,l)}else insertElementsAfter(0==e?[m]:j[e-1],f);a.each(k,function(a){d.register(a)}),[].splice.apply(j,[e,0].concat(k))},l=function(b,c,e){var f=j.splice(e,c.length),g=[];a.each(f,function(a){[].push.apply(g,a),d.replace(a,[]),d.unregister(a)}),a.remove(a.$(g))},i=b.getParentNode(c,i),m=document.createTextNode("");e(i,function(){f.bind("add",k).bind("remove",l)},function(){f.unbind("add",k).unbind("remove",l),a.each(j,function(a){d.unregister(a)})}),insertElementsAfter([c],m),a.remove(a.$(c)),k({},f,0)},html:function(c,e,g){var h,g=b.getParentNode(c,g),i=f(g,e,function(a,b){var c=h[0].parentNode;c&&j(b),i.teardownCheck(h[0].parentNode)}),j=function(b){var e=a.view.frag(b,g),f=a.makeArray(e.childNodes);if(insertElementsAfter(h||[c],e),h){var j=a.makeArray(h);d.replace(h,f),a.remove(a.$(j))}else a.remove(a.$(c)),h=f,i.nodeList=h,d.register(h)};j(e(),[c])},text:function(a,c,d){var e=b.getParentNode(a,d),g=f(a.parentNode!==e?a.parentNode:e,c,function(a,b){"unknown"!=typeof h.nodeValue&&(h.nodeValue=""+b),g.teardownCheck(h.parentNode)}),h=document.createTextNode(c());a.parentNode!==e?(e=a.parentNode,e.insertBefore(h,a),e.removeChild(a)):(e.insertBefore(h,a),e.removeChild(a))},attributes:function(a,c,d){var e=function(c){var d=g(c),e=d.shift();e!=h&&h&&b.removeAttr(a,h),e&&(b.setAttr(a,e,d.join("=")),h=e)};if(f(a,c,function(a,b){e(b)}),arguments.length>=3)var h=g(d)[0];else e(c())},attributePlaceholder:"__!!__",attributeReplace:/__!!__/g,attribute:function(c,d,e){f(c,e,function(){b.setAttr(c,d,j.render())});var g,i=a.$(c);g=a.data(i,"hooks"),g||a.data(i,"hooks",g={});var j,k=b.getAttr(c,d),l=k.split(h.attributePlaceholder),m=[];m.push(l.shift(),l.join(h.attributePlaceholder)),g[d]?g[d].computes.push(e):g[d]={render:function(){var a=0,c=k?k.replace(h.attributeReplace,function(){return b.contentText(j.computes[a++]())}):b.contentText(j.computes[a++]());return c},computes:[e],batchNum:undefined},j=g[d],m.splice(1,0,e()),b.setAttr(c,d,m.join(""))}};return h}(__m3,__m14,__m11,__m17),__m15=function(a,b,c){var d=[],e=function(a){var c=b.tagMap[a]||"span";return"span"===c?"@@!!@@":"<"+c+">"+e(c)+"</"+c+">"},f=function(b,c){if("string"==typeof b)return b;if(!b&&0!==b)return"";var e=b.hookup&&function(a,c){b.hookup.call(b,a,c)}||"function"==typeof b&&b;return e?c?"<"+c+" "+a.view.hook(e)+"></"+c+">":(d.push(e),""):""+b},g=function(b){return"string"==typeof b||"number"==typeof b?a.esc(b):f(b)};return a.extend(a.view,{live:c,setupLists:function(){var b,c=a.view.lists;return a.view.lists=function(a,c){b={list:a,renderer:c}},function(){return a.view.lists=c,b}},pending:function(){var b=d.slice(0);return lastHookups=b,d=[],a.view.hook(function(c){a.each(b,function(a){a(c)})})},txt:function(h,i,j,k,l){var m=a.view.setupLists(),n=function(){},o=function(){p.unbind("change",n)},p=a.compute(l,k,!1);p.bind("change",n);var q=b.tagMap[i]||"span",r=m(),s=p();if(r)return"<"+q+a.view.hook(function(a,b){c.list(a,r.list,r.renderer,k,b)})+"></"+q+">";if(!p.hasDependencies)return o(),(h||0!==j?g:f)(s,0===j&&q);var t=b.tagToContentPropMap[i];if(0!==j||t){if(1===j)return d.push(function(a){c.attributes(a,p,p()),o()}),p();var u=0===j?t:j;return(0===j?lastHookups:d).push(function(a){c.attribute(a,u,p),o()
+}),c.attributePlaceholder}return"<"+q+a.view.hook(h?function(a,b){c.text(a,p,b),o()}:function(a,b){c.html(a,p,b),o()})+">"+e(q)+"</"+q+">"}}),a}(__m11,__m14,__m16,__m2),__m12=function(a){var b=a.extend,c=function(a){if(this.constructor!=c){var d=new c(a);return function(a,b){return d.render(a,b)}}return"function"==typeof a?(this.template={fn:a},void 0):(b(this,a),this.template=this.scanner.scan(this.text,this.name),void 0)};return a.EJS=c,c.prototype.render=function(a,b){return a=a||{},this.template.fn.call(a,a,new c.Helpers(a,b||{}))},b(c.prototype,{scanner:new a.view.Scanner({tokens:[["templateLeft","<%%"],["templateRight","%>"],["returnLeft","<%=="],["escapeLeft","<%="],["commentLeft","<%#"],["left","<%"],["right","%>"],["returnRight","%>"]],transform:function(a){return a.replace(/<%([\s\S]+?)%>/gm,function(a,b){var c,d,e=[];b.replace(/[{}]/gm,function(a,b){e.push([a,b])});do for(c=!1,d=e.length-2;d>=0;d--)if("{"==e[d][0]&&"}"==e[d+1][0]){e.splice(d,2),c=!0;break}while(c);if(e.length>=2){var f,g=["<%"],h=0;for(d=0;f=e[d];d++)g.push(b.substring(h,h=f[1])),"{"==f[0]&&d<e.length-1||"}"==f[0]&&d>0?g.push("{"==f[0]?"{ %><% ":" %><% }"):g.push(f[0]),++h;return g.push(b.substring(h),"%>"),g.join("")}return"<%"+b+"%>"})}})}),c.Helpers=function(a,c){this._data=a,this._extras=c,b(this,c)},c.Helpers.prototype={list:function(b,c){a.each(b,function(a,d){c(a,d,b)})},each:function(b,c){a.isArray(b)?this.list(b,c):a.view.lists(b,c)}},a.view.register({suffix:"ejs",script:function(a,b){return"can.EJS(function(_CONTEXT,_VIEW) { "+new c({text:b,name:a}).template.out+" })"},renderer:function(a,b){return c({text:b,name:a})}}),a}(__m3,__m11,__m2,__m9,__m13,__m15),__m18=function(a){var b,c=function(b,c,d){return a.bind.call(b,c,d),function(){a.unbind.call(b,c,d)}},d=a.isFunction,e=a.extend,f=a.each,g=[].slice,h=/\{([^\}]+)\}/g,i=a.getObject("$.event.special",[a])||{},j=function(b,c,d,e){return a.delegate.call(b,c,d,e),function(){a.undelegate.call(b,c,d,e)}},k=function(b,d,e,f){return f?j(b,a.trim(f),d,e):c(b,d,e)},l=a.Control=a.Construct({setup:function(){if(a.Construct.setup.apply(this,arguments),a.Control){var b,c=this;c.actions={};for(b in c.prototype)c._isAction(b)&&(c.actions[b]=c._action(b))}},_shifter:function(b,c){var e="string"==typeof c?b[c]:c;return d(e)||(e=b[e]),function(){return b.called=c,e.apply(b,[this.nodeName?a.$(this):this].concat(g.call(arguments,0)))}},_isAction:function(a){var b=this.prototype[a],c=typeof b;return"constructor"!==a&&("function"==c||"string"==c&&d(this.prototype[b]))&&!!(i[a]||m[a]||/[^\w]/.test(a))},_action:function(c,d){if(h.lastIndex=0,d||!h.test(c)){var e=d?a.sub(c,[d,window]):c;if(!e)return null;var f=a.isArray(e),g=f?e[1]:e,i=g.split(/\s+/g),j=i.pop();return{processor:m[j]||b,parts:[g,i.join(" "),j],delegate:f?e[0]:undefined}}},processors:{},defaults:{}},{setup:function(b,c){var d,f=this.constructor,g=f.pluginName||f._fullName;return this.element=a.$(b),g&&"can_control"!==g&&this.element.addClass(g),(d=a.data(this.element,"controls"))||a.data(this.element,"controls",d=[]),d.push(this),this.options=e({},f.defaults,c),this.on(),[this.element,this.options]},on:function(b,c,d,e){if(!b){this.off();var f,g,h=this.constructor,i=this._bindings,j=h.actions,l=this.element,m=a.Control._shifter(this,"destroy");for(f in j)j.hasOwnProperty(f)&&(g=j[f]||h._action(f,this.options))&&i.push(g.processor(g.delegate||l,g.parts[2],g.parts[1],f,this));return a.bind.call(l,"destroyed",m),i.push(function(b){a.unbind.call(b,"destroyed",m)}),i.length}return"string"==typeof b&&(e=d,d=c,c=b,b=this.element),e===undefined&&(e=d,d=c,c=null),"string"==typeof e&&(e=a.Control._shifter(this,e)),this._bindings.push(k(b,d,e,c)),this._bindings.length},off:function(){var a=this.element[0];f(this._bindings||[],function(b){b(a)}),this._bindings=[]},destroy:function(){if(null!==this.element){var b,c=this.constructor,d=c.pluginName||c._fullName;this.off(),d&&"can_control"!==d&&this.element.removeClass(d),b=a.data(this.element,"controls"),b.splice(a.inArray(this,b),1),a.trigger(this,"destroyed"),this.element=null}}}),m=a.Control.processors,b=function(b,c,d,e,f){return k(b,c,a.Control._shifter(f,e),d)};return f(["change","click","contextmenu","dblclick","keydown","keyup","keypress","mousedown","mousemove","mouseout","mouseover","mouseup","reset","resize","scroll","select","submit","focusin","focusout","mouseenter","mouseleave","touchstart","touchmove","touchcancel","touchend","touchleave"],function(a){m[a]=b}),l}(__m3,__m1),__m20=function(a){var b=/^\d+$/,c=/([^\[\]]+)|(\[\])/g,d=/([^?#]*)(#.*)?$/,e=function(a){return decodeURIComponent(a.replace(/\+/g," "))};return a.extend(a,{deparam:function(f){var g,h,i={};return f&&d.test(f)&&(g=f.split("&"),a.each(g,function(a){var d=a.split("="),f=e(d.shift()),g=e(d.join("=")),j=i;if(f){d=f.match(c);for(var k=0,l=d.length-1;l>k;k++)j[d[k]]||(j[d[k]]=b.test(d[k+1])||"[]"==d[k+1]?[]:{}),j=j[d[k]];h=d.pop(),"[]"==h?j.push(g):j[h]=g}})),i}}),a}(__m3,__m2),__m19=function(a){var b=/\:([\w\.]+)/g,c=/^(?:&[^=]+=[^&]*)+/,d=function(b){var c=[];return a.each(b,function(b,d){c.push(("className"===d?"class":d)+'="'+("href"===d?b:a.esc(b))+'"')}),c.join(" ")},e=function(a,b){var c=0,d=0,e={};for(var f in a.defaults)a.defaults[f]===b[f]&&(e[f]=1,c++);for(;d<a.names.length;d++){if(!b.hasOwnProperty(a.names[d]))return-1;e[a.names[d]]||c++}return c},f=!0,g=window.location,h=function(a){return(a+"").replace(/([.?*+\^$\[\]\\(){}|\-])/g,"\\$1")},i=a.each,j=a.extend;a.route=function(c,d){d=d||{};var e=[],f=c.replace(b,function(b,f,g){e.push(f);var h="\\"+(c.substr(g+b.length,1)||a.route._querySeparator);return"([^"+h+"]"+(d[f]?"*":"+")+")"});return a.route.routes[c]={test:new RegExp("^"+f+"($|"+h(a.route._querySeparator)+")"),route:c,names:e,defaults:d,length:c.split("/").length},a.route},j(a.route,{_querySeparator:"&",_paramsMatcher:c,param:function(c,d){var f,g,h=0,k=c.route,l=0;if(delete c.route,i(c,function(){l++}),i(a.route.routes,function(a){return g=e(a,c),g>h&&(f=a,h=g),g>=l?!1:void 0}),a.route.routes[k]&&e(a.route.routes[k],c)===h&&(f=a.route.routes[k]),f){var m,n=j({},c),o=f.route.replace(b,function(a,b){return delete n[b],c[b]===f.defaults[b]?"":encodeURIComponent(c[b])});return i(f.defaults,function(a,b){n[b]===a&&delete n[b]}),m=a.param(n),d&&a.route.attr("route",f.route),o+(m?a.route._querySeparator+m:"")}return a.isEmptyObject(c)?"":a.route._querySeparator+a.param(c)},deparam:function(b){var c={length:-1};if(i(a.route.routes,function(a){a.test.test(b)&&a.length>c.length&&(c=a)}),c.length>-1){var d=b.match(c.test),e=d.shift(),f=b.substr(e.length-(d[d.length-1]===a.route._querySeparator?1:0)),g=f&&a.route._paramsMatcher.test(f)?a.deparam(f.slice(1)):{};return g=j(!0,{},c.defaults,g),i(d,function(b,d){b&&b!==a.route._querySeparator&&(g[c.names[d]]=decodeURIComponent(b))}),g.route=c.route,g}return b.charAt(0)!==a.route._querySeparator&&(b=a.route._querySeparator+b),a.route._paramsMatcher.test(b)?a.deparam(b.slice(1)):{}},data:new a.Observe({}),routes:{},ready:function(b){return b===!1&&(f=b),(b===!0||f===!0)&&(a.route._setup(),o()),a.route},url:function(b,c){return c&&(b=j({},l,b)),"#!"+a.route.param(b)},link:function(b,c,e,f){return"<a "+d(j({href:a.route.url(c,f)},e))+">"+b+"</a>"},current:function(b){return g.hash=="#!"+a.route.param(b)},_setup:function(){a.bind.call(window,"hashchange",o)},_getHash:function(){return g.href.split(/#!?/)[1]||""},_setHash:function(b){var c=a.route.param(b,!0);return g.hash="#!"+c,c}}),i(["bind","unbind","delegate","undelegate","attr","removeAttr"],function(b){a.route[b]=function(){return a.route.data[b]?a.route.data[b].apply(a.route.data,arguments):void 0}});var k,l,m,n,o=a.route.setState=function(){var b=a.route._getHash();l=a.route.deparam(b),n&&b===m||a.route.attr(l,!0)};return a.route.bind("change",function(){n=1,clearTimeout(k),k=setTimeout(function(){n=0;var b=a.route.data.serialize();m=a.route._setHash(b)},1)}),a.bind.call(document,"ready",a.route.ready),"complete"!==document.readyState&&"interactive"!==document.readyState||!f||a.route.ready(),a.route.constructor.canMakeObserve=a.Observe.canMakeObserve,a.route}(__m3,__m7,__m20),__m21=function(a){return a.Control.processors.route=function(b,c,d,e,f){d=d||"",a.route(d);var g,h=function(b){if(a.route.attr("route")===d&&(b.batchNum===undefined||b.batchNum!==g)){g=b.batchNum;var c=a.route.attr();delete c.route,a.isFunction(f[e])?f[e](c):f[f[e]](c)}};return a.route.bind("change",h),function(){a.route.unbind("change",h)}},a}(__m3,__m19,__m18);window.can=__m5}();
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.object.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.object.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.object.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,137 @@
+/*!
+ * CanJS - 1.1.6
+ * http://canjs.us/
+ * Copyright (c) 2013 Bitovi
+ * Wed, 29 May 2013 18:59:29 GMT
+ * Licensed MIT
+ * Includes: can/util/object
+ * Download from: http://canjs.com
+ */
+(function(can) {
+
+ var isArray = can.isArray,
+ // essentially returns an object that has all the must have comparisons ...
+ // must haves, do not return true when provided undefined
+ cleanSet = function(obj, compares) {
+ var copy = can.extend({}, obj);
+ for (var prop in copy) {
+ var compare = compares[prop] === undefined ? compares["*"] : compares[prop];
+ if (same(copy[prop], undefined, compare)) {
+ delete copy[prop]
+ }
+ }
+ return copy;
+ },
+ propCount = function(obj) {
+ var count = 0;
+ for (var prop in obj) count++;
+ return count;
+ };
+
+ can.Object = {};
+
+ var same = can.Object.same = function(a, b, compares, aParent, bParent, deep) {
+ var aType = typeof a,
+ aArray = isArray(a),
+ comparesType = typeof compares,
+ compare;
+
+ if (comparesType == 'string' || compares === null) {
+ compares = compareMethods[compares];
+ comparesType = 'function'
+ }
+ if (comparesType == 'function') {
+ return compares(a, b, aParent, bParent)
+ }
+ compares = compares || {};
+
+ if (a instanceof Date) {
+ return a === b;
+ }
+ if (deep === -1) {
+ return aType === 'object' || a === b;
+ }
+ if (aType !== typeof b || aArray !== isArray(b)) {
+ return false;
+ }
+ if (a === b) {
+ return true;
+ }
+ if (aArray) {
+ if (a.length !== b.length) {
+ return false;
+ }
+ for (var i = 0; i < a.length; i++) {
+ compare = compares[i] === undefined ? compares["*"] : compares[i]
+ if (!same(a[i], b[i], a, b, compare)) {
+ return false;
+ }
+ };
+ return true;
+ } else if (aType === "object" || aType === 'function') {
+ var bCopy = can.extend({}, b);
+ for (var prop in a) {
+ compare = compares[prop] === undefined ? compares["*"] : compares[prop];
+ if (!same(a[prop], b[prop], compare, a, b, deep === false ? -1 : undefined)) {
+ return false;
+ }
+ delete bCopy[prop];
+ }
+ // go through bCopy props ... if there is no compare .. return false
+ for (prop in bCopy) {
+ if (compares[prop] === undefined || !same(undefined, b[prop], compares[prop], a, b, deep === false ? -1 : undefined)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ };
+
+ can.Object.subsets = function(checkSet, sets, compares) {
+ var len = sets.length,
+ subsets = [],
+ checkPropCount = propCount(checkSet),
+ setLength;
+
+ for (var i = 0; i < len; i++) {
+ //check this subset
+ var set = sets[i];
+ if (can.Object.subset(checkSet, set, compares)) {
+ subsets.push(set)
+ }
+ }
+ return subsets;
+ };
+
+ can.Object.subset = function(subset, set, compares) {
+ // go through set {type: 'folder'} and make sure every property
+ // is in subset {type: 'folder', parentId :5}
+ // then make sure that set has fewer properties
+ // make sure we are only checking 'important' properties
+ // in subset (ones that have to have a value)
+
+ var setPropCount = 0,
+ compares = compares || {};
+
+ for (var prop in set) {
+
+ if (!same(subset[prop], set[prop], compares[prop], subset, set)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ var compareMethods = {
+ "null": function() {
+ return true;
+ },
+ i: function(a, b) {
+ return ("" + a).toLowerCase() == ("" + b).toLowerCase()
+ }
+ }
+
+ return can.Object;
+
+ })(can);
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.attributes.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.attributes.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.attributes.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,174 @@
+/*!
+ * CanJS - 1.1.6
+ * http://canjs.us/
+ * Copyright (c) 2013 Bitovi
+ * Wed, 29 May 2013 18:59:29 GMT
+ * Licensed MIT
+ * Includes: can/observe/attributes
+ * Download from: http://canjs.com
+ */
+(function(can, Observe) {
+
+ can.each([can.Observe, can.Model], function(clss) {
+ // in some cases model might not be defined quite yet.
+ if (clss === undefined) {
+ return;
+ }
+ var isObject = function(obj) {
+ return typeof obj === 'object' && obj !== null && obj;
+ };
+
+ can.extend(clss, {
+
+ attributes: {},
+
+
+ convert: {
+ "date": function(str) {
+ var type = typeof str;
+ if (type === "string") {
+ return isNaN(Date.parse(str)) ? null : Date.parse(str)
+ } else if (type === 'number') {
+ return new Date(str)
+ } else {
+ return str
+ }
+ },
+ "number": function(val) {
+ return parseFloat(val);
+ },
+ "boolean": function(val) {
+ if (val === 'false' || val === '0' || !val) {
+ return false;
+ }
+ return true;
+ },
+ "default": function(val, oldVal, error, type) {
+ var construct = can.getObject(type),
+ context = window,
+ realType;
+ // if type has a . we need to look it up
+ if (type.indexOf(".") >= 0) {
+ // get everything before the last .
+ realType = type.substring(0, type.lastIndexOf("."));
+ // get the object before the last .
+ context = can.getObject(realType);
+ }
+ return typeof construct == "function" ? construct.call(context, val, oldVal) : val;
+ }
+ },
+
+ serialize: {
+ "default": function(val, type) {
+ return isObject(val) && val.serialize ? val.serialize() : val;
+ },
+ "date": function(val) {
+ return val && val.getTime()
+ }
+ }
+ });
+
+ // overwrite setup to do this stuff
+ var oldSetup = clss.setup;
+
+
+ clss.setup = function(superClass, stat, proto) {
+ var self = this;
+ oldSetup.call(self, superClass, stat, proto);
+
+ can.each(["attributes"], function(name) {
+ if (!self[name] || superClass[name] === self[name]) {
+ self[name] = {};
+ }
+ });
+
+ can.each(["convert", "serialize"], function(name) {
+ if (superClass[name] != self[name]) {
+ self[name] = can.extend({}, superClass[name], self[name]);
+ }
+ });
+ };
+ });
+
+ var oldSetup = can.Observe.prototype.setup;
+
+ can.Observe.prototype.setup = function(obj) {
+
+ var diff = {};
+
+ oldSetup.call(this, obj);
+
+ can.each(this.constructor.defaults, function(value, key) {
+ if (!this.hasOwnProperty(key)) {
+ diff[key] = value;
+ }
+ }, this);
+
+ this._init = 1;
+ this.attr(diff);
+ delete this._init;
+ };
+
+ can.Observe.prototype.__convert = function(prop, value) {
+ // check if there is a
+
+ var Class = this.constructor,
+ oldVal = this.attr(prop),
+ type, converter;
+
+ if (Class.attributes) {
+ // the type of the attribute
+ type = Class.attributes[prop];
+ converter = Class.convert[type] || Class.convert['default'];
+ }
+
+ return value === null || !type ?
+ // just use the value
+ value :
+ // otherwise, pass to the converter
+ converter.call(Class, value, oldVal, function() {}, type);
+ };
+
+ can.Observe.prototype.serialize = function(attrName, stack) {
+ var where = {},
+ Class = this.constructor,
+ attrs = {};
+
+ stack = can.isArray(stack) ? stack : [];
+ stack.push(this._cid);
+
+ if (attrName !== undefined) {
+ attrs[attrName] = this[attrName];
+ } else {
+ attrs = this.__get();
+ }
+
+ can.each(attrs, function(val, name) {
+ var type, converter;
+
+ // If this is an observe, check that it wasn't serialized earlier in the stack.
+ if (val instanceof can.Observe && can.inArray(val._cid, stack) > -1) {
+ // Since this object has already been serialized once,
+ // just reference the id (or undefined if it doesn't exist).
+ where[name] = val.attr('id');
+ } else {
+ type = Class.attributes ? Class.attributes[name] : 0;
+ converter = Class.serialize ? Class.serialize[type] : 0;
+
+ // if the value is an object, and has a attrs or serialize function
+ where[name] = val && typeof val.serialize == 'function' ?
+ // call attrs or serialize to get the original data back
+ val.serialize(undefined, stack) :
+ // otherwise if we have a converter
+ converter ?
+ // use the converter
+ converter(val, type) :
+ // or return the val
+ val;
+ }
+ });
+
+ return attrName != undefined ? where[attrName] : where;
+ };
+ return can.Observe;
+ })(can);
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.delegate.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.delegate.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/libs/can.observe.delegate.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,215 @@
+/*!
+ * CanJS - 1.1.6
+ * http://canjs.us/
+ * Copyright (c) 2013 Bitovi
+ * Wed, 29 May 2013 18:59:29 GMT
+ * Licensed MIT
+ * Includes: can/observe/delegate
+ * Download from: http://canjs.com
+ */
+(function(can) {
+
+
+
+ // ** - 'this' will be the deepest item changed
+ // * - 'this' will be any changes within *, but * will be the
+ // this returned
+
+ // tells if the parts part of a delegate matches the broken up props of the event
+ // gives the prop to use as 'this'
+ // - parts - the attribute name of the delegate split in parts ['foo','*']
+ // - props - the split props of the event that happened ['foo','bar','0']
+ // - returns - the attribute to delegate too ('foo.bar'), or null if not a match
+ var delegateMatches = function(parts, props) {
+ //check props parts are the same or
+ var len = parts.length,
+ i = 0,
+ // keeps the matched props we will use
+ matchedProps = [],
+ prop;
+
+ // if the event matches
+ for (i; i < len; i++) {
+ prop = props[i]
+ // if no more props (but we should be matching them)
+ // return null
+ if (typeof prop !== 'string') {
+ return null;
+ } else
+ // if we have a "**", match everything
+ if (parts[i] == "**") {
+ return props.join(".");
+ } else
+ // a match, but we want to delegate to "*"
+ if (parts[i] == "*") {
+ // only do this if there is nothing after ...
+ matchedProps.push(prop);
+ } else if (prop === parts[i]) {
+ matchedProps.push(prop);
+ } else {
+ return null;
+ }
+ }
+ return matchedProps.join(".");
+ },
+ // gets a change event and tries to figure out which
+ // delegates to call
+ delegateHandler = function(event, prop, how, newVal, oldVal) {
+ // pre-split properties to save some regexp time
+ var props = prop.split("."),
+ delegates = (this._observe_delegates || []).slice(0),
+ delegate,
+ attr,
+ matchedAttr,
+ hasMatch,
+ valuesEqual;
+ event.attr = prop;
+ event.lastAttr = props[props.length - 1];
+
+ // for each delegate
+ for (var i = 0; delegate = delegates[i++];) {
+
+ // if there is a batchNum, this means that this
+ // event is part of a series of events caused by a single
+ // attrs call. We don't want to issue the same event
+ // multiple times
+ // setting the batchNum happens later
+ if ((event.batchNum && delegate.batchNum === event.batchNum) || delegate.undelegated) {
+ continue;
+ }
+
+ // reset match and values tests
+ hasMatch = undefined;
+ valuesEqual = true;
+
+ // yeah, all this under here has to be redone v
+
+ // for each attr in a delegate
+ for (var a = 0; a < delegate.attrs.length; a++) {
+
+ attr = delegate.attrs[a];
+
+ // check if it is a match
+ if (matchedAttr = delegateMatches(attr.parts, props)) {
+ hasMatch = matchedAttr;
+ }
+ // if it has a value, make sure it's the right value
+ // if it's set, we should probably check that it has a
+ // value no matter what
+ if (attr.value && valuesEqual) {
+ valuesEqual = attr.value === "" + this.attr(attr.attr)
+ } else if (valuesEqual && delegate.attrs.length > 1) {
+ // if there are multiple attributes, each has to at
+ // least have some value
+ valuesEqual = this.attr(attr.attr) !== undefined
+ }
+ }
+
+
+ // if there is a match and valuesEqual ... call back
+ if (hasMatch && valuesEqual) {
+ // how to get to the changed property from the delegate
+ var from = prop.replace(hasMatch + ".", "");
+
+ // if this event is part of a batch, set it on the delegate
+ // to only send one event
+ if (event.batchNum) {
+ delegate.batchNum = event.batchNum
+ }
+
+ // if we listen to change, fire those with the same attrs
+ // TODO: the attrs should probably be using from
+ if (delegate.event === 'change') {
+ arguments[1] = from;
+ event.curAttr = hasMatch;
+ delegate.callback.apply(this.attr(hasMatch), can.makeArray(arguments));
+ } else if (delegate.event === how) {
+
+ // if it's a match, callback with the location of the match
+ delegate.callback.apply(this.attr(hasMatch), [event, newVal, oldVal, from]);
+ } else if (delegate.event === 'set' &&
+ how == 'add') {
+ // if we are listening to set, we should also listen to add
+ delegate.callback.apply(this.attr(hasMatch), [event, newVal, oldVal, from]);
+ }
+ }
+
+ }
+ };
+
+ can.extend(can.Observe.prototype, {
+
+ delegate: function(selector, event, handler) {
+ selector = can.trim(selector);
+ var delegates = this._observe_delegates || (this._observe_delegates = []),
+ attrs = [],
+ selectorRegex = /([^\s=,]+)(?:=("[^",]*"|'[^',]*'|[^\s"',]*))?(,?)\s*/g,
+ matches;
+
+ // parse each property in the selector
+ while (matches = selectorRegex.exec(selector)) {
+ // we need to do a little doctoring to make up for the quotes.
+ if (matches[2] && can.inArray(matches[2].substr(0, 1), ['"', "'"]) >= 0) {
+ matches[2] = matches[2].substr(1, -1);
+ }
+
+ attrs.push({
+ // the attribute name
+ attr: matches[1],
+ // the attribute name, pre-split for speed
+ parts: matches[1].split('.'),
+ // the value associated with this property (if there was one given)
+ value: matches[2],
+ // whether this selector combines with the one after it with AND or OR
+ or: matches[3] === ','
+ });
+ }
+
+ // delegates has pre-processed info about the event
+ delegates.push({
+ // the attrs name for unbinding
+ selector: selector,
+ // an object of attribute names and values {type: 'recipe',id: undefined}
+ // undefined means a value was not defined
+ attrs: attrs,
+ callback: handler,
+ event: event
+ });
+ if (delegates.length === 1) {
+ this.bind("change", delegateHandler)
+ }
+ return this;
+ },
+
+ undelegate: function(selector, event, handler) {
+ selector = selector && can.trim(selector);
+
+ var i = 0,
+ delegates = this._observe_delegates || [],
+ delegateOb;
+ if (selector) {
+ while (i < delegates.length) {
+ delegateOb = delegates[i];
+ if (delegateOb.callback === handler ||
+ (!handler && delegateOb.selector === selector)) {
+ delegateOb.undelegated = true;
+ delegates.splice(i, 1)
+ } else {
+ i++;
+ }
+ }
+ } else {
+ // remove all delegates
+ delegates = [];
+ }
+ if (!delegates.length) {
+ //can.removeData(this, "_observe_delegates");
+ this.unbind("change", delegateHandler)
+ }
+ return this;
+ }
+ });
+ // add helpers for testing ..
+ can.Observe.prototype.delegate.matches = delegateMatches;
+ return can.Observe;
+ })(can);
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/comments.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,48 @@
+var Comment = can.Model({
+ findAll: 'GET /poll/{pollId}/comments',
+// findOne: 'GET /comments/{commentId}',
+ create : "POST /polls/{pollId}/comments",
+ update : "PUT /comments",
+ destroy : "DELETE /comments/{commentId}"
+},{});
+
+var COMMENTS = [
+ [{
+ text: "This is the end of the world",
+ author: "Maya",
+ postDate: "21/12/12"
+ },{
+ text: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.",
+ author: "Sacha",
+ postDate: "03/12/11"
+ }],
+ [{
+ text: "azztyuiopfghj",
+ author: "yyy",
+ postDate: ""
+ },{
+ text: "aqwxszedv",
+ author: "sdsqdqsdqsdqdqsd",
+ postDate: ""
+ }]
+];
+
+can.fixture('GET /poll/{pollId}/comments', function(orig) {
+ return COMMENTS[orig.data.pollId - 1];
+});
+
+var idToInc= 3;
+can.fixture("POST /polls/{pollId}/comments", function() {
+ console.log("create comment " + idToInc);
+ return {id: (idToInc++)}
+});
+
+can.fixture("PUT /comments", function(orig) {
+ console.log("update comment " + orig.data.id);
+ return {};
+});
+
+can.fixture("DELETE /comments/{commentId}", function(orig){
+ console.log("delete comment " + orig.data.commentId);
+ return {};
+});
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/polls.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,70 @@
+var Poll = can.Model({
+ findAll: 'GET /polls',
+ findOne: "GET /polls/{id}",
+ create : "POST /polls",
+ update : "PUT /polls/{id}",
+ destroy : "DELETE /polls/{id}"
+},{});
+
+var POLLS = [
+ {
+ id: 1,
+ title: 'Titre 1',
+ description: "Desc 1",
+ creatorName: "Kevin",
+ choices: [
+ {
+ id: 1,
+ name: "Choix 1",
+ description: "desc du choix 1"
+ },
+ {
+ id: 2,
+ name: "Choix 2",
+ description: "desc du choix 2"
+ }
+ ]
+ },
+ {
+ id: 2,
+ title: 'Lorem Ipsum',
+ description: "description très longue, mais vraiment très longue pour qu'elle passe en dessous. Enfin j'espère que ce sera assez long",
+ creatorName: "moi",
+ choices: [
+ {
+ id: 3,
+ name: "Choix 1",
+ description: "desc du choix 1"
+ },
+ {
+ id: 4,
+ name: "Choix 2",
+ description: "desc du choix 2"
+ }
+ ]
+ },
+];
+
+can.fixture('GET /polls', function(){
+ return POLLS;
+});
+
+can.fixture('GET /polls/{id}', function(orig) {
+ return POLLS[orig.data.id - 1];
+});
+
+var idToInc= 3;
+can.fixture("POST /polls", function() {
+ console.log("create poll " + idToInc);
+ return {id: (idToInc++)}
+});
+
+can.fixture("PUT /polls/{id}", function(orig) {
+ console.log("update poll " + orig.data.id);
+ return {};
+});
+
+can.fixture("DELETE /polls/{id}", function(orig){
+ console.log("delete poll " + orig.data.id);
+ return {};
+});
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/votes.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/votes.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/models/votes.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,138 @@
+var Vote = can.Model({
+ findAll: 'GET /poll/{pollId}/votes',
+// findOne: 'GET /comments/{commentId}',
+ create : "POST /poll/{pollId}/votes",
+ update : "PUT /votes",
+ destroy : "DELETE /votes/{voteId}"
+},{});
+
+var VOTES = [
+ [{
+ id: 1,
+ voterListMember: {
+ name: "Joe",
+ email: "joe(a)dalt.on"
+ },
+ voteToChoices: [{
+ voteValue: 0,
+ choice: 1
+ },{
+ voteValue: 0,
+ choice: 2
+ }]
+
+ }, {
+ id: 2,
+ voterListMember: {
+ name: "Jack",
+ email: "jack(a)dalt.on"
+ },
+ voteToChoices: [{
+ voteValue: 1,
+ choice: 1
+ },{
+ voteValue: 1,
+ choice: 2
+ }]
+ },{
+ id: 3,
+ voterListMember: {
+ name: "William",
+ email: "william(a)dalt.on"
+ },
+ voteToChoices: [{
+ voteValue: 1,
+ choice: 1
+ },{
+ voteValue: 0,
+ choice: 2
+ }]
+ }, {
+ id: 4,
+ voterListMember: {
+ name: "Avrel",
+ email: "avrel(a)dalt.on"
+ },
+ voteToChoices: [{
+ voteValue: 0,
+ choice: 1
+ },{
+ voteValue: 1,
+ choice: 2
+ }]
+ }],
+ [{
+ id: 5,
+ voterListMember: {
+ name: "Joe",
+ email: "joe(a)dalt.on"
+ },
+ voteToChoices: [{
+ voteValue: 0,
+ choice: 3
+ },{
+ voteValue: 0,
+ choice: 4
+ }]
+
+ }, {
+ id: 6,
+ voterListMember: {
+ name: "Jack",
+ email: "jack(a)dalt.on"
+ },
+ voteToChoices: [{
+ voteValue: 1,
+ choice: 3
+ },{
+ voteValue: 1,
+ choice: 4
+ }]
+ },{
+ id: 7,
+ voterListMember: {
+ name: "William",
+ email: "william(a)dalt.on"
+ },
+ voteToChoices: [{
+ voteValue: 1,
+ choice: 3
+ },{
+ voteValue: 0,
+ choice: 4
+ }]
+ }, {
+ id: 8,
+ voterListMember: {
+ name: "Avrel",
+ email: "avrel(a)dalt.on"
+ },
+ voteToChoices: [{
+ voteValue: 0,
+ choice: 3
+ },{
+ voteValue: 1,
+ choice: 4
+ }]
+ }]
+];
+
+can.fixture('GET /poll/{pollId}/votes', function(orig) {
+ return VOTES[orig.data.pollId - 1];
+});
+
+var idToInc= 3;
+can.fixture("POST /polls/{pollId}/votes", function() {
+ console.log("create vote " + idToInc);
+ return {id: (idToInc++)}
+});
+
+can.fixture("PUT /votes", function(orig) {
+ console.log("update vote " + orig.data.id);
+ return {};
+});
+
+can.fixture("DELETE /votes/{voteId}", function(orig){
+ console.log("delete vote " + orig.data.vote);
+ return {};
+});
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/route.js
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/route.js (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/js/route.js 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,14 @@
+var Routing = can.Control({
+ 'route': function() {
+ // Matches every routing change, but gets passed no data.
+ console.log("route")
+ },
+
+ ':type route': function(data) {
+ console.log(":type route " + data)
+ },
+
+ ':type/:id route': function(data) {
+ console.log(":type/:id route" + data)
+ }
+})
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/menu.ejs 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,4 @@
+<ul>
+ <li><%== can.route.link('Sondage', { type: 'poll', action: 'edit' }) %></li>
+ <li><%== can.route.link('Autre', { type: 'other', action: 'donothing' }) %></li>
+</ul>
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/poll_form.ejs
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/poll_form.ejs (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/poll_form.ejs 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,30 @@
+<h1>Création de sondage</h1>
+
+<form id='pollCreationForm' class="form-horizontal">
+
+ <div class="control-group">
+ <label class="control-label" for="pollCreationFormTitle">Title</label>
+ <div class="controls">
+ <input type='text' name='title' id='pollCreationFormTitle' placeholder='title'
+ <%= poll.attr("title") ? "value='" + poll.attr("title") + "'" : "class='empty'" %>/>
+ </div>
+ </div>
+
+ <div class="control-group">
+ <label class="control-label" for='pollCreationFormDescription'>Description</label>
+ <div class="controls">
+ <textarea id='pollCreationFormDescription' name='description'
+ <% if (!poll.attr("description")) {%>
+ class='empty'
+ <% } %>><%= poll.attr('description') %></textarea>
+ </div>
+ </div>
+
+ <div class="form-actions">
+ <a href="javascript://" class="btn btn-primary save">Save</a>
+ <a href="javascript://" class="btn btn-primary create">New poll</a>
+ <a href="javascript://" data-id="1" class="btn btn">Edit poll 1</a>
+ <a href="javascript://" data-id="2" class="btn btn">Edit poll 2</a>
+ </div>
+
+</form>
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/summary.ejs 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,35 @@
+<h1>Sondage <%= poll.title %></h1>
+
+<div class="control-group">
+ <label class="control-label" for='pollSummaryLink'>Lien pour participer</label>
+ <input type='url' id='pollSummaryLink' value="<%== window.location.href.split('#')[0] + can.route.url({ type: 'poll', action: 'vote', id: poll.id }) %>"/>
+</div>
+
+<div class='row-fluid'>
+ <div class='span4'>
+ <h2>Sondage</h2>
+ <ul class='noListStyle'>
+ <li><%== can.route.link('<i class="icon-ok"></i>Clore', {}) %></li>
+ <li><%== can.route.link('<i class="icon-pencil"></i>Modifer', {type: 'poll', action: 'edit', id: poll.id}) %></li>
+ <li><%== can.route.link('<i class="icon-envelope"></i>Notification', {}) %></li>
+ <li><%== can.route.link('<i class="icon-time"></i>Historique', {}) %></li>
+ <li><%== can.route.link('<i class="icon-clone"></i>Créer un duplicata', {}) %></li>
+ <li><%== can.route.link('<i class="icon-trash"></i>Effacer', {}) %></li>
+ </ul>
+ </div>
+
+ <div class='span4'>
+ <h2>Participants</h2>
+ <ul class='noListStyle'>
+ <li><%== can.route.link('<i class="icon-user"></i>Inviter des participants', {}) %></li>
+ <li><%== can.route.link('<i class="icon-envelope"></i>Contacter les invités', {}) %></li>
+ </ul>
+ </div>
+
+ <div class='span4'>
+ <h2>Export</h2>
+ <ul class='noListStyle'>
+ <li><i class="icon-upload"></i>clore</li>
+ </ul>
+ </div>
+</div>
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/views/vote.ejs 2013-06-08 12:12:35 UTC (rev 3819)
@@ -0,0 +1,53 @@
+<div class="page-header">
+ <h1><%= poll.title %></h1>
+ <p>Sondage lancé par <%= poll.creatorName %>
+ | <i class='icon-user'></i> 0
+ | <i class='icon-comment'></i> 0
+ | <i class='icon-time'></i> il y a 2 minutes</p>
+ <p><%= poll.description %></p>
+</div>
+
+<form>
+
+ <table class="table table-bordered table-striped">
+ <caption>Votes</caption>
+ <thead>
+ <tr>
+ <th>Votant</th>
+ <% poll.choices.each(function(choice) { %>
+ <th><%= choice.attr('name') %></th>
+ <% }); %>
+ </tr>
+ </thead>
+ <tbody>
+ <% votes.each(function(vote) { %>
+ <tr>
+ <td><%= vote.attr('voterListMember.name') %></td>
+ <% vote.voteToChoices.each(function(choice) { %>
+ <td><%= choice.attr('voteValue') %></td>
+ <% }); %>
+ </tr>
+ <% }); %>
+ <tr>
+ <td><input type='text'/></td>
+ <% poll.choices.each(function(choice) { %>
+ <td><input type='checkbox'/></td>
+ <% }); %>
+ </tr>
+ </tbody>
+ </table>
+
+ <div class="form-actions">
+ <button class="btn btn-primary">Voter</button>
+ </div>
+
+</form>
+
+<div>
+<h2>Commentaires</h2>
+<% comments.each(function(comment) { %>
+
+<p><strong><%= comment.attr('author') %></strong> : <%= comment.attr('text') %></p>
+
+<% }); %>
+</div>
\ No newline at end of file
1
0
r3818 - in branches/pollen-2.0: . pollen-ui-js pollen-ui-js/src pollen-ui-js/src/main pollen-ui-js/src/main/webapp pollen-ui-js/src/main/webapp/css pollen-ui-js/src/main/webapp/img
by kmorin@users.chorem.org 07 Jun '13
by kmorin@users.chorem.org 07 Jun '13
07 Jun '13
Author: kmorin
Date: 2013-06-07 18:16:07 +0200 (Fri, 07 Jun 2013)
New Revision: 3818
Url: http://chorem.org/projects/pollen/repository/revisions/3818
Log:
first shot of the pollen UI with canJS
Added:
branches/pollen-2.0/pollen-ui-js/
branches/pollen-2.0/pollen-ui-js/src/
branches/pollen-2.0/pollen-ui-js/src/main/
branches/pollen-2.0/pollen-ui-js/src/main/webapp/
branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/
branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css
branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css
branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/
branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings-white.png
branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings.png
branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/bootstrap.min.css 2013-06-07 16:16:07 UTC (rev 3818)
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap v2.3.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/css/style.css 2013-06-07 16:16:07 UTC (rev 3818)
@@ -0,0 +1,11 @@
+#content >div {
+ display: none;
+}
+
+.noListStyle {
+ list-style-type: none;
+}
+
+.noListStyle i {
+ margin-right: 5px;
+}
\ No newline at end of file
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings-white.png
===================================================================
(Binary files differ)
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings-white.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings.png
===================================================================
(Binary files differ)
Property changes on: branches/pollen-2.0/pollen-ui-js/src/main/webapp/img/glyphicons-halflings.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html
===================================================================
--- branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html (rev 0)
+++ branches/pollen-2.0/pollen-ui-js/src/main/webapp/index.html 2013-06-07 16:16:07 UTC (rev 3818)
@@ -0,0 +1,57 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Pollen</title>
+ <link rel="stylesheet" href="css/bootstrap.min.css">
+ <link rel="stylesheet" href="css/style.css">
+</head>
+
+<body>
+
+ <div class='container-fluid'>
+ <div class="row-fluid">
+ <div id="menu" class="span2"></div>
+
+ <div class="span10" id="content">
+ <!--Body content-->
+ <div id="pollForm"></div>
+ <div id="pollSummary"></div>
+ <div id="vote"></div>
+ </div>
+ </div>
+
+ </div>
+
+
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.js"></script>
+ <script src="js/libs/bootstrap.min.js"></script>
+ <script src="js/libs/can.jquery.js"></script>
+ <script src="js/libs/can.object.js"></script>
+ <script src="js/libs/can.fixture.js"></script>
+ <script src="js/libs/can.observe.attributes.js"></script>
+ <script src="js/libs/can.observe.delegate.js"></script>
+
+ <script src="js/models/polls.js"></script>
+ <script src="js/models/comments.js"></script>
+ <script src="js/models/votes.js"></script>
+
+ <script src="js/controls/menu.js"></script>
+ <script src="js/controls/poll_form.js"></script>
+ <script src="js/controls/poll_summary.js"></script>
+ <script src="js/controls/vote.js"></script>
+
+ <script type="text/javascript">
+
+ var menu = new Menu('#menu');
+
+ var pf = new PollForm('#pollForm');
+ var summary = new PollSummary('#pollSummary');
+ var vote = new PollVote('#vote');
+
+ can.route(':type/:action');
+ can.route(':type/:id/:action');
+
+ </script>
+
+</body>
+</html>
\ No newline at end of file
1
0
Author: tchemit
Date: 2013-06-06 18:43:31 +0200 (Thu, 06 Jun 2013)
New Revision: 3817
Url: http://chorem.org/projects/pollen/repository/revisions/3817
Log:
implements user + auth service + review rest api
Added:
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenJpaDao.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenApplicationContext.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/ErrorAction.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/EmailService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/EntityNotFoundException.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserEmailAlreadyUsedException.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidEmailActiviationTokenException.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidPasswordException.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserLoginAlreadyUsedException.java
Modified:
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaPollenPersistenceContext.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenPersistenceContext.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserDao.java
branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserJpaDao.java
branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.zargo
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenJpaTransactionFilter.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceContextFilter.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServices.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/AuthService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteCountingService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java
branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java
branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/CommentService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FavoriteListService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FixturesService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteCountingService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteService.java
branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoterListService.java
branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml
branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java
branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/FakePollenServiceContext.java
branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaPollenPersistenceContext.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaPollenPersistenceContext.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/JpaPollenPersistenceContext.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -23,6 +23,7 @@
* #L%
*/
+import org.nuiton.jpa.api.JpaEntity;
import org.nuiton.jpa.api.JpaEntityIdFactory;
import org.nuiton.jpa.api.hibernate.HibernateUtil;
@@ -46,6 +47,11 @@
}
@Override
+ public void detach(JpaEntity entity) {
+ entityManager.detach(entity);
+ }
+
+ @Override
public void clearDatabase() {
rollback();
HibernateUtil.cleanDatabase(entityManager);
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenPersistenceContext.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenPersistenceContext.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/PollenPersistenceContext.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -29,11 +29,13 @@
import org.chorem.pollen.persistence.dao.FavoriteListMemberJpaDao;
import org.chorem.pollen.persistence.dao.PollJpaDao;
import org.chorem.pollen.persistence.dao.PollenUserJpaDao;
+import org.chorem.pollen.persistence.dao.SessionTokenJpaDao;
import org.chorem.pollen.persistence.dao.VoteJpaDao;
import org.chorem.pollen.persistence.dao.VoteToChoiceJpaDao;
import org.chorem.pollen.persistence.dao.VoterJpaDao;
import org.chorem.pollen.persistence.dao.VoterListJpaDao;
import org.chorem.pollen.persistence.dao.VoterListMemberJpaDao;
+import org.nuiton.jpa.api.JpaEntity;
/**
* TODO
@@ -43,6 +45,8 @@
*/
public interface PollenPersistenceContext {
+ void detach(JpaEntity entity);
+
void commit();
void rollback();
@@ -61,6 +65,8 @@
PollenUserJpaDao getPollenUserDao();
+ SessionTokenJpaDao getSessionTokenDao();
+
VoteJpaDao getVoteDao();
VoteToChoiceJpaDao getVoteToChoiceDao();
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserDao.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserDao.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -34,4 +34,10 @@
public interface PollenUserDao {
PollenUser findByLogin(String login);
+
+ PollenUser findByEmail(String email);
+
+ boolean loginExists(String login);
+
+ boolean emailExists(String email);
}
Modified: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserJpaDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserJpaDao.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/PollenUserJpaDao.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -26,6 +26,7 @@
import org.chorem.pollen.persistence.entity.PollenUser;
import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
/**
* TODO
@@ -41,10 +42,30 @@
@Override
public PollenUser findByLogin(String login) {
- PollenUser result = createQuery(
- "from " + getEntityClass() + " where login = :login").
- setParameter("login", login).
- getSingleResult();
+ TypedQuery<PollenUser> query =
+ createQuery(PollenUser.PROPERTY_LOGIN, login);
+ PollenUser result = findUniqueOrNull(query);
+
return result;
}
+
+ @Override
+ public PollenUser findByEmail(String email) {
+ TypedQuery<PollenUser> query =
+ createQuery(PollenUser.PROPERTY_EMAIL, email);
+ PollenUser result = findUniqueOrNull(query);
+ return result;
+ }
+
+ @Override
+ public boolean loginExists(String login) {
+ PollenUser user = findByLogin(login);
+ return user != null;
+ }
+
+ @Override
+ public boolean emailExists(String email) {
+ PollenUser user = findByEmail(email);
+ return user != null;
+ }
} //PollenUserJpaDao
Added: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenDao.java (rev 0)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenDao.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,37 @@
+package org.chorem.pollen.persistence.dao;
+
+/*
+ * #%L
+ * Pollen :: Persistence
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.chorem.pollen.persistence.entity.SessionToken;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public interface SessionTokenDao {
+
+ SessionToken findByToken(String token);
+}
Property changes on: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenDao.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenJpaDao.java
===================================================================
--- branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenJpaDao.java (rev 0)
+++ branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenJpaDao.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,50 @@
+package org.chorem.pollen.persistence.dao;
+
+/*
+ * #%L
+ * Pollen :: Persistence
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.chorem.pollen.persistence.entity.SessionToken;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class SessionTokenJpaDao extends AbstractSessionTokenJpaDao {
+
+ public SessionTokenJpaDao(EntityManager entityManager) {
+ super(entityManager);
+ }
+
+ @Override
+ public SessionToken findByToken(String token) {
+ TypedQuery<SessionToken> query = createQuery(SessionToken.PROPERTY_TOKEN, token);
+ SessionToken result = findUniqueOrNull(query);
+ return result;
+ }
+
+} //SessionTokenJpaDao
Property changes on: branches/pollen-2.0/pollen-persistence/src/main/java/org/chorem/pollen/persistence/dao/SessionTokenJpaDao.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-persistence/src/main/xmi/pollen.zargo
===================================================================
(Binary files differ)
Added: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenApplicationContext.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenApplicationContext.java (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenApplicationContext.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,125 @@
+package org.chorem.pollen.rest;
+
+/*
+ * #%L
+ * Pollen :: Rest Api
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
+import org.chorem.pollen.service.DefaultPollenServiceContext;
+import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.config.PollenServiceConfig;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import javax.persistence.PersistenceException;
+import java.io.Closeable;
+import java.util.Map;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class PollenApplicationContext implements Closeable {
+
+ private static final Log log = LogFactory.getLog(PollenApplicationContext.class);
+
+ protected static final String APPLICATION_CONTEXT_PARAMETER = "pollen_PollenApplicationContext";
+
+ protected PollenServiceConfig applicationConfig;
+
+ protected EntityManagerFactory entityManagerFactory;
+
+ public PollenServiceConfig getPollenServiceConfig() {
+ if (applicationConfig == null) {
+ applicationConfig = new PollenServiceConfig();
+ }
+ return applicationConfig;
+ }
+
+ public EntityManager newEntityManager() {
+
+ if (entityManagerFactory == null) {
+
+ PollenServiceConfig applicationConfig = getPollenServiceConfig();
+
+ Map<String, String> jpaParameters = applicationConfig.getJpaParameters();
+
+ if (log.isInfoEnabled()) {
+ log.info("creating entity manager factory");
+ }
+
+ try {
+
+ entityManagerFactory = Persistence.createEntityManagerFactory("pollenPersistenceUnit", jpaParameters);
+
+ } catch (PersistenceException e) {
+
+ if (log.isErrorEnabled()) {
+ log.error("unable to create entity manager factory", e);
+ }
+
+ throw e;
+
+ }
+
+ }
+
+ EntityManager entityManager = entityManagerFactory.createEntityManager();
+
+ return entityManager;
+
+ }
+
+ public void close() {
+
+ if (entityManagerFactory != null && entityManagerFactory.isOpen()) {
+
+ if (log.isInfoEnabled()) {
+ log.info("stopping magalie, will close entity manager factory");
+ }
+
+ entityManagerFactory.close();
+
+ }
+
+ }
+
+ public PollenServiceContext newServiceContext(EntityManager entityManager) {
+
+ DefaultPollenServiceContext serviceContext = new DefaultPollenServiceContext();
+
+ JpaPollenPersistenceContext jpaMagaliePersistenceContext =
+ new JpaPollenPersistenceContext(entityManager);
+
+ serviceContext.setPersistenceContext(jpaMagaliePersistenceContext);
+
+ serviceContext.setPollenServiceConfig(applicationConfig);
+
+ return serviceContext;
+
+ }
+}
Property changes on: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenApplicationContext.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenJpaTransactionFilter.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenJpaTransactionFilter.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenJpaTransactionFilter.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -29,7 +29,6 @@
import org.nuiton.web.filter.JpaTransactionFilter;
import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
@@ -40,7 +39,7 @@
private static final Log log =
LogFactory.getLog(PollenJpaTransactionFilter.class);
- protected EntityManagerFactory entityManagerFactory;
+ protected PollenApplicationContext applicationContext;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
@@ -51,10 +50,10 @@
log.info("Init JPA Filter");
}
- entityManagerFactory = PollenServices.getEntityManagerFactory(
+ applicationContext = PollenServices.getApplicationContext(
filterConfig.getServletContext());
- Preconditions.checkNotNull(entityManagerFactory, "Could not find entit manager factory at ServletContext#pollen_EntityManagerFactory");
+ Preconditions.checkNotNull(applicationContext, "Could not find application context at ServletContext#pollen_PollenApplicationContext");
}
@Override
@@ -64,7 +63,7 @@
try {
- entityManager = entityManagerFactory.createEntityManager();
+ entityManager = applicationContext.newEntityManager();
} catch (PersistenceException e) {
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceContextFilter.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceContextFilter.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceContextFilter.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -23,8 +23,7 @@
* #L%
*/
-import org.chorem.pollen.service.DefaultPollenServiceContext;
-import org.chorem.pollen.service.config.PollenServiceConfig;
+import org.chorem.pollen.service.PollenServiceContext;
import org.debux.webmotion.server.WebMotionFilter;
import org.debux.webmotion.server.call.HttpContext;
@@ -40,17 +39,15 @@
public void inject(HttpContext context) {
- DefaultPollenServiceContext serviceContext =
- new DefaultPollenServiceContext();
+ PollenApplicationContext applicationContext =
+ PollenServices.getApplicationContext(context.getServletContext());
- PollenServiceConfig serviceConfig =
- PollenServices.getServiceConfig(context.getServletContext());
- serviceContext.setPollenServiceConfig(serviceConfig);
-
EntityManager entityManager =
PollenServices.getEntityManager(context.getRequest());
- serviceContext.setEntityManager(entityManager);
+ PollenServiceContext serviceContext =
+ applicationContext.newServiceContext(entityManager);
+
PollenServices.setServiceContext(context.getRequest(), serviceContext);
doProcess();
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServiceListener.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -26,7 +26,6 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.config.PollenServiceConfig;
import org.debux.webmotion.server.WebMotionServerListener;
import org.debux.webmotion.server.call.Call;
import org.debux.webmotion.server.call.HttpContext;
@@ -34,12 +33,8 @@
import org.debux.webmotion.server.handler.ExecutorParametersInjectorHandler;
import org.debux.webmotion.server.mapping.Mapping;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.Persistence;
-import javax.persistence.PersistenceException;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;
-import java.util.Map;
/**
* TODO
@@ -58,46 +53,26 @@
serverContext.addInjector(new PollenServiceContextInjector());
- // get configuration
- PollenServiceConfig config = new PollenServiceConfig();
+ // Create application context
+ PollenApplicationContext applicationContext =
+ new PollenApplicationContext();
- // push config in context
- PollenServices.setServiceConfig(serverContext.getServletContext(), config);
-
- // get persistence properties
- Map<String, String> jpaParameters = config.getJpaParameters();
-
- if (log.isInfoEnabled()) {
- log.info("creating entity manager factory");
- }
-
- // get entity manager factory
- try {
-
- EntityManagerFactory entityManagerFactory =
- Persistence.createEntityManagerFactory("pollenPersistenceUnit", jpaParameters);
-
- // store it in server context
- PollenServices.setEntityManagerFactory(serverContext.getServletContext(), entityManagerFactory);
-
- } catch (PersistenceException e) {
-
- if (log.isErrorEnabled()) {
- log.error("unable to create entity manager factory", e);
- }
-
- throw e;
- }
+ // push it in context
+ PollenServices.setApplicationContext(
+ serverContext.getServletContext(), applicationContext);
}
@Override
public void onStop(ServerContext serverContext) {
- EntityManagerFactory entityManagerFactory =
- PollenServices.getEntityManagerFactory(serverContext.getServletContext());
+ // Get application context
+ PollenApplicationContext applicationContext =
+ PollenServices.getApplicationContext(
+ serverContext.getServletContext());
- if (entityManagerFactory != null) {
- entityManagerFactory.close();
+ // close it (and all underlined resources)
+ if (applicationContext != null) {
+ applicationContext.close();
}
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServices.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServices.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/PollenServices.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -24,12 +24,10 @@
*/
import org.chorem.pollen.service.PollenServiceContext;
-import org.chorem.pollen.service.config.PollenServiceConfig;
+import org.nuiton.web.filter.JpaTransactionFilter;
import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
import javax.servlet.ServletContext;
-import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
@@ -40,38 +38,24 @@
*/
public class PollenServices {
- static final String APPLICATION_POLLEN_SERVICE_CONFIG = "pollen_PollenServiceConfig";
+ protected static final String APPLICATION_CONTEXT_PARAMETER = "pollen_PollenApplicationContext";
- static final String APPLICATION_ENTITY_MANAGER_FACTORY = "pollen_EntityManagerFactory";
+ protected static final String REQUEST_POLLEN_SERVICE_CONTEXT = "pollen_PollenServiceContext";
- static final String REQUEST_POLLEN_SERVICE_CONTEXT = "pollen_PollenServiceContext";
+ protected static final String REQUEST_ENTITY_MANAGER = JpaTransactionFilter.JPA_TRANSACTION_REQUEST_ATTRIBUTE;
- public static PollenServiceConfig getServiceConfig(ServletContext servletContext) {
- PollenServiceConfig result = (PollenServiceConfig)
- servletContext.getAttribute(APPLICATION_POLLEN_SERVICE_CONFIG);
+ public static PollenApplicationContext getApplicationContext(ServletContext servletContext) {
+ PollenApplicationContext result = (PollenApplicationContext)
+ servletContext.getAttribute(APPLICATION_CONTEXT_PARAMETER);
return result;
}
- public static void setServiceConfig(ServletContext servletContext,
- PollenServiceConfig serviceConfig) {
- servletContext.setAttribute(APPLICATION_POLLEN_SERVICE_CONFIG, serviceConfig);
+ public static void setApplicationContext(ServletContext servletContext,
+ PollenApplicationContext applicationContext) {
+ servletContext.setAttribute(APPLICATION_CONTEXT_PARAMETER, applicationContext);
}
- public static EntityManagerFactory getEntityManagerFactory(ServletContext servletContext) {
- EntityManagerFactory result = (EntityManagerFactory)
- servletContext.getAttribute(APPLICATION_ENTITY_MANAGER_FACTORY);
- return result;
- }
- public static void setEntityManagerFactory(ServletContext servletContext,
- EntityManagerFactory entityManagerFactory) {
- servletContext.setAttribute(APPLICATION_ENTITY_MANAGER_FACTORY, entityManagerFactory);
- }
-
- public static EntityManager getEntityManager(ServletRequest servletRequest) {
- return PollenJpaTransactionFilter.getTransaction(servletRequest);
- }
-
public static PollenServiceContext getServiceContext(HttpServletRequest request) {
PollenServiceContext result = (PollenServiceContext)
request.getAttribute(REQUEST_POLLEN_SERVICE_CONTEXT);
@@ -83,4 +67,9 @@
request.setAttribute(REQUEST_POLLEN_SERVICE_CONTEXT, serviceContext);
}
-}
+ public static EntityManager getEntityManager(HttpServletRequest request) {
+ EntityManager result = (EntityManager)
+ request.getAttribute(REQUEST_ENTITY_MANAGER);
+ return result;
+ }
+}
\ No newline at end of file
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/AuthService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/AuthService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/AuthService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -24,6 +24,8 @@
*/
import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.service.exception.UserInvalidPasswordException;
import org.debux.webmotion.server.WebMotionController;
/**
@@ -34,15 +36,15 @@
*/
public class AuthService extends WebMotionController {
- public String login(PollenServiceContext context, String login, String password) {
+ public String login(PollenServiceContext context, String login, String password) throws UserInvalidPasswordException, EntityNotFoundException {
return context.getAuthService().login(login, password);
}
- public void lostPassword(PollenServiceContext context, String token) {
- context.getAuthService().lostPassword(token);
+ public void lostPassword(PollenServiceContext context, String login) throws EntityNotFoundException {
+ context.getAuthService().lostPassword(login);
}
- public void logout(PollenServiceContext context, String login) {
- context.getAuthService().logout(login);
+ public void logout(PollenServiceContext context, String login, String token) throws EntityNotFoundException {
+ context.getAuthService().logout(login, token);
}
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/CommentService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -25,6 +25,7 @@
import org.chorem.pollen.persistence.entity.Comment;
import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
import java.util.List;
@@ -37,24 +38,24 @@
*/
public class CommentService extends WebMotionController {
- public Comment[] getComments(PollenServiceContext context, String pollId) {
+ public Comment[] getComments(PollenServiceContext context, String pollId) throws EntityNotFoundException {
List<Comment> comments = context.getCommentService().getComments(pollId);
return comments.toArray(new Comment[comments.size()]);
}
- public Comment getComment(PollenServiceContext context, String pollId, String commentId) {
- return context.getCommentService().getComment(pollId, commentId);
+ public Comment getComment(PollenServiceContext context, String commentId) throws EntityNotFoundException {
+ return context.getCommentService().getComment(commentId);
}
- public Comment addComment(PollenServiceContext context, String pollId, Comment comment) {
+ public Comment addComment(PollenServiceContext context, String pollId, Comment comment) throws EntityNotFoundException {
return context.getCommentService().addComment(pollId, comment);
}
- public Comment editComment(PollenServiceContext context, String pollId, Comment comment) {
- return context.getCommentService().editComment(pollId, comment);
+ public Comment editComment(PollenServiceContext context,Comment comment) throws EntityNotFoundException {
+ return context.getCommentService().editComment(comment);
}
- public void deleteComment(PollenServiceContext context, String pollId, String commentId) {
+ public void deleteComment(PollenServiceContext context, String pollId, String commentId) throws EntityNotFoundException {
context.getCommentService().deleteComment(pollId, commentId);
}
}
Added: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/ErrorAction.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/ErrorAction.java (rev 0)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/ErrorAction.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,44 @@
+package org.chorem.pollen.rest.api;
+
+/*
+ * #%L
+ * Pollen :: Rest Api
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.debux.webmotion.server.WebMotionController;
+import org.debux.webmotion.server.render.Render;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class ErrorAction extends WebMotionController {
+
+ public Render on404(Exception e) {
+ return renderError(404, e.getMessage());
+ }
+
+ public Render on500(Exception e) {
+ return renderError(500, e.getMessage());
+ }
+}
Property changes on: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/ErrorAction.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/FavoriteListService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -26,6 +26,7 @@
import org.chorem.pollen.persistence.entity.FavoriteList;
import org.chorem.pollen.persistence.entity.FavoriteListMember;
import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
import java.util.List;
@@ -38,45 +39,45 @@
*/
public class FavoriteListService extends WebMotionController {
- public FavoriteList[] getFavoriteLists(PollenServiceContext context, String userId) {
+ public FavoriteList[] getFavoriteLists(PollenServiceContext context, String userId) throws EntityNotFoundException {
List<FavoriteList> favoriteLists = context.getFavoriteListService().getFavoriteLists(userId);
return favoriteLists.toArray(new FavoriteList[favoriteLists.size()]);
}
- public FavoriteList getFavoriteList(PollenServiceContext context, String userId, String favoriteListId) {
- return context.getFavoriteListService().getFavoriteList(userId, favoriteListId);
+ public FavoriteList getFavoriteList(PollenServiceContext context, String favoriteListId) throws EntityNotFoundException {
+ return context.getFavoriteListService().getFavoriteList(favoriteListId);
}
- public FavoriteList createFavoriteList(PollenServiceContext context, String userId, FavoriteList favoriteList) {
+ public FavoriteList createFavoriteList(PollenServiceContext context, String userId, FavoriteList favoriteList) throws EntityNotFoundException {
return context.getFavoriteListService().createFavoriteList(userId, favoriteList);
}
- public FavoriteList editFavoriteList(PollenServiceContext context, String userId, FavoriteList favoriteList) {
- return context.getFavoriteListService().editFavoriteList(userId, favoriteList);
+ public FavoriteList editFavoriteList(PollenServiceContext context, FavoriteList favoriteList) throws EntityNotFoundException {
+ return context.getFavoriteListService().editFavoriteList(favoriteList);
}
- public void deleteFavoriteList(PollenServiceContext context, String userId, String favoriteListId) {
+ public void deleteFavoriteList(PollenServiceContext context, String userId, String favoriteListId) throws EntityNotFoundException {
context.getFavoriteListService().deleteFavoriteList(userId, favoriteListId);
}
- public FavoriteListMember[] getMembers(PollenServiceContext context, String userId, String favoriteListId) {
- List<FavoriteListMember> members = context.getFavoriteListService().getMembers(userId, favoriteListId);
- return members.toArray(new FavoriteListMember[members.size()]);
+ public List<FavoriteListMember> getMembers(PollenServiceContext context, String favoriteListId) throws EntityNotFoundException {
+ List<FavoriteListMember> members = context.getFavoriteListService().getFavoriteListMembers(favoriteListId);
+ return members;
}
- public FavoriteListMember getMember(PollenServiceContext context, String userId, String favoriteListId, String memberId) {
- return context.getFavoriteListService().getMember(userId, favoriteListId, memberId);
+ public FavoriteListMember getMember(PollenServiceContext context, String memberId) throws EntityNotFoundException {
+ return context.getFavoriteListService().getFavoriteListMember(memberId);
}
- public FavoriteListMember addMember(PollenServiceContext context, String userId, String favoriteListId, FavoriteListMember member) {
- return context.getFavoriteListService().addMember(userId, favoriteListId, member);
+ public FavoriteListMember addMember(PollenServiceContext context, String favoriteListId, FavoriteListMember member) throws EntityNotFoundException {
+ return context.getFavoriteListService().addFavoriteListMember(favoriteListId, member);
}
- public FavoriteListMember editMember(PollenServiceContext context, String userId, String favoriteListId, FavoriteListMember member) {
- return context.getFavoriteListService().editMember(userId, favoriteListId, member);
+ public FavoriteListMember editMember(PollenServiceContext context, FavoriteListMember member) throws EntityNotFoundException {
+ return context.getFavoriteListService().editFavoriteListMember(member);
}
- public void removeMember(PollenServiceContext context, String userId, String favoriteListId, String memberId) {
- context.getFavoriteListService().removeMember(userId, favoriteListId, memberId);
+ public void removeMember(PollenServiceContext context, String favoriteListId, String memberId) throws EntityNotFoundException {
+ context.getFavoriteListService().removeFavoriteListMember( favoriteListId, memberId);
}
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -26,6 +26,7 @@
import org.chorem.pollen.persistence.entity.Choice;
import org.chorem.pollen.persistence.entity.Poll;
import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
import java.io.File;
@@ -40,63 +41,63 @@
*/
public class PollService extends WebMotionController {
- public Poll[] getCreatedPolls(PollenServiceContext context, String userId) {
+ public Poll[] getCreatedPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
Set<Poll> polls = context.getPollService().getCreatedPolls(userId);
return polls.toArray(new Poll[polls.size()]);
}
- public Poll[] getInvitedPolls(PollenServiceContext context, String userId) {
+ public Poll[] getInvitedPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
Set<Poll> polls = context.getPollService().getInvitedPolls(userId);
return polls.toArray(new Poll[polls.size()]);
}
- public Poll[] getParticipatedPolls(PollenServiceContext context, String userId) {
+ public Poll[] getParticipatedPolls(PollenServiceContext context, String userId) throws EntityNotFoundException {
Set<Poll> polls = context.getPollService().getParticipatedPolls(userId);
return polls.toArray(new Poll[polls.size()]);
}
- public Poll createPoll(PollenServiceContext context, String userId, Poll poll) {
+ public Poll createPoll(PollenServiceContext context, String userId, Poll poll) throws EntityNotFoundException {
return context.getPollService().createPoll(userId, poll);
}
- public Poll editPoll(PollenServiceContext context, Poll poll) {
+ public Poll editPoll(PollenServiceContext context, Poll poll) throws EntityNotFoundException {
return context.getPollService().editPoll(poll);
}
- public void deletePoll(PollenServiceContext context, String pollId) {
+ public void deletePoll(PollenServiceContext context, String pollId) throws EntityNotFoundException {
context.getPollService().deletePoll(pollId);
}
- public Poll clonePoll(PollenServiceContext context, String pollId) {
+ public Poll clonePoll(PollenServiceContext context, String pollId) throws EntityNotFoundException {
return context.getPollService().clonePoll(pollId);
}
- public File closePoll(PollenServiceContext context, String pollId) {
+ public File closePoll(PollenServiceContext context, String pollId) throws EntityNotFoundException {
return context.getPollService().closePoll(pollId);
}
- public File exportPoll(PollenServiceContext context, String pollId) {
+ public File exportPoll(PollenServiceContext context, String pollId) throws EntityNotFoundException {
return context.getPollService().exportPoll(pollId);
}
- public Choice[] getChoices(PollenServiceContext context, String pollId) {
+ public List<Choice> getChoices(PollenServiceContext context, String pollId) throws EntityNotFoundException {
List<Choice> choices = context.getPollService().getChoices(pollId);
- return choices.toArray(new Choice[choices.size()]);
+ return choices;
}
- public Choice getChoice(PollenServiceContext context, String pollId, String choiceId) {
- return context.getPollService().getChoice(pollId, choiceId);
+ public Choice getChoice(PollenServiceContext context, String choiceId) throws EntityNotFoundException {
+ return context.getPollService().getChoice(choiceId);
}
- public Choice addChoice(PollenServiceContext context, String pollId, Choice choice) {
+ public Choice addChoice(PollenServiceContext context, String pollId, Choice choice) throws EntityNotFoundException {
return context.getPollService().addChoice(pollId, choice);
}
- public Choice editChoice(PollenServiceContext context, String pollId, Choice choice) {
- return context.getPollService().editChoice(pollId, choice);
+ public Choice editChoice(PollenServiceContext context, Choice choice) throws EntityNotFoundException {
+ return context.getPollService().editChoice(choice);
}
- public void deleteChoice(PollenServiceContext context, String pollId, String choiceId) {
+ public void deleteChoice(PollenServiceContext context, String pollId, String choiceId) throws EntityNotFoundException {
context.getPollService().deleteChoice(pollId, choiceId);
}
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/UserService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -25,6 +25,11 @@
import org.chorem.pollen.persistence.entity.PollenUser;
import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.service.exception.UserEmailAlreadyUsedException;
+import org.chorem.pollen.service.exception.UserInvalidEmailActiviationTokenException;
+import org.chorem.pollen.service.exception.UserInvalidPasswordException;
+import org.chorem.pollen.service.exception.UserLoginAlreadyUsedException;
import org.debux.webmotion.server.WebMotionController;
import java.util.List;
@@ -42,19 +47,33 @@
return users.toArray(new PollenUser[users.size()]);
}
- public PollenUser getUser(PollenServiceContext context, String userId) {
+ public PollenUser getUser(PollenServiceContext context,
+ String userId) throws EntityNotFoundException {
return context.getUserService().getUser(userId);
}
- public PollenUser createUser(PollenServiceContext context, PollenUser user) {
- return context.getUserService().createUser(user);
+ public PollenUser createUser(PollenServiceContext context,
+ PollenUser user,
+ boolean generatePassword) throws UserEmailAlreadyUsedException, UserLoginAlreadyUsedException {
+ return context.getUserService().createUser(user, generatePassword);
+
}
- public PollenUser editUser(PollenServiceContext context, PollenUser user) {
+ public PollenUser editUser(PollenServiceContext context,
+ PollenUser user) throws UserInvalidPasswordException, UserEmailAlreadyUsedException, EntityNotFoundException {
return context.getUserService().editUser(user);
}
- public void validateUserEmail(PollenServiceContext context, String userId, String token) {
+ public void validateUserEmail(PollenServiceContext context,
+ String userId,
+ String token) throws EntityNotFoundException, UserInvalidEmailActiviationTokenException {
context.getUserService().validateUserEmail(userId, token);
}
+
+ public void changePassword(PollenServiceContext context,
+ String userId,
+ String oldPassword,
+ String newPassword) throws UserInvalidPasswordException, EntityNotFoundException {
+ context.getUserService().changePassword(userId, oldPassword, newPassword);
+ }
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteCountingService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteCountingService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteCountingService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -25,6 +25,7 @@
import org.chorem.pollen.service.PollResult;
import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
/**
@@ -35,7 +36,7 @@
*/
public class VoteCountingService extends WebMotionController {
- public PollResult getResult(PollenServiceContext context, String pollId) {
+ public PollResult getResult(PollenServiceContext context, String pollId) throws EntityNotFoundException {
return context.getVoteCountingService().getResult(pollId);
}
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoteService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -25,6 +25,7 @@
import org.chorem.pollen.persistence.entity.Vote;
import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
import java.util.List;
@@ -37,24 +38,24 @@
*/
public class VoteService extends WebMotionController {
- public Vote[] getVotes(PollenServiceContext context, String pollId) {
+ public Vote[] getVotes(PollenServiceContext context, String pollId) throws EntityNotFoundException {
List<Vote> votes = context.getVoteService().getVotes(pollId);
return votes.toArray(new Vote[votes.size()]);
}
- public Vote getVote(PollenServiceContext context, String pollId, String voteId) {
- return context.getVoteService().getVote(pollId, voteId);
+ public Vote getVote(PollenServiceContext context, String voteId) throws EntityNotFoundException {
+ return context.getVoteService().getVote(voteId);
}
- public Vote addVote(PollenServiceContext context, String pollId, Vote vote) {
+ public Vote addVote(PollenServiceContext context, String pollId, Vote vote) throws EntityNotFoundException {
return context.getVoteService().addVote(pollId, vote);
}
- public Vote editVote(PollenServiceContext context, String pollId, Vote vote) {
- return context.getVoteService().editVote(pollId, vote);
+ public Vote editVote(PollenServiceContext context, Vote vote) throws EntityNotFoundException {
+ return context.getVoteService().editVote(vote);
}
- public void deleteVote(PollenServiceContext context, String pollId, String voteId) {
+ public void deleteVote(PollenServiceContext context, String pollId, String voteId) throws EntityNotFoundException {
context.getVoteService().deleteVote(pollId, voteId);
}
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/VoterListService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -26,6 +26,7 @@
import org.chorem.pollen.persistence.entity.VoterList;
import org.chorem.pollen.persistence.entity.VoterListMember;
import org.chorem.pollen.service.PollenServiceContext;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import org.debux.webmotion.server.WebMotionController;
import java.util.List;
@@ -39,49 +40,49 @@
*/
public class VoterListService extends WebMotionController {
- public VoterList importFavoriteList(PollenServiceContext context, String userId, String pollId, String favoriteListId) {
- return context.getVoterListService().importFavoriteList(userId, pollId, favoriteListId);
+ public VoterList importFavoriteList(PollenServiceContext context, String pollId, String favoriteListId) throws EntityNotFoundException {
+ return context.getVoterListService().importFavoriteList(pollId, favoriteListId);
}
- public VoterList[] getVoterLists(PollenServiceContext context, String pollId) {
+ public VoterList[] getVoterLists(PollenServiceContext context, String pollId) throws EntityNotFoundException {
List<VoterList> voterLists = context.getVoterListService().getVoterLists(pollId);
return voterLists.toArray(new VoterList[voterLists.size()]);
}
- public VoterList getVoterList(PollenServiceContext context, String pollId, String voterListId) {
- return context.getVoterListService().getVoterList(pollId, voterListId);
+ public VoterList getVoterList(PollenServiceContext context, String voterListId) throws EntityNotFoundException {
+ return context.getVoterListService().getVoterList(voterListId);
}
- public VoterList addVoterList(PollenServiceContext context, String pollId, VoterList voterList) {
+ public VoterList addVoterList(PollenServiceContext context, String pollId, VoterList voterList) throws EntityNotFoundException {
return context.getVoterListService().addVoterList(pollId, voterList);
}
- public VoterList editVoterList(PollenServiceContext context, String pollId, VoterList voterList) {
- return context.getVoterListService().editVoterList(pollId, voterList);
+ public VoterList editVoterList(PollenServiceContext context, VoterList voterList) throws EntityNotFoundException {
+ return context.getVoterListService().editVoterList(voterList);
}
- public void deleteVoterList(PollenServiceContext context, String pollId, String voterListId) {
+ public void deleteVoterList(PollenServiceContext context, String pollId, String voterListId) throws EntityNotFoundException {
context.getVoterListService().deleteVoterList(pollId, voterListId);
}
- public VoterListMember[] getMembers(PollenServiceContext context, String pollId, String voterListId) {
- Set<VoterListMember> members = context.getVoterListService().getMembers(pollId, voterListId);
- return members.toArray(new VoterListMember[members.size()]);
+ public Set<VoterListMember> getMembers(PollenServiceContext context, String voterListId) throws EntityNotFoundException {
+ Set<VoterListMember> members = context.getVoterListService().getMembers(voterListId);
+ return members;
}
- public VoterListMember getMember(PollenServiceContext context, String pollId, String voterListId, String memberId) {
- return context.getVoterListService().getMember(pollId, voterListId, memberId);
+ public VoterListMember getMember(PollenServiceContext context, String memberId) throws EntityNotFoundException {
+ return context.getVoterListService().getMember(memberId);
}
- public VoterListMember addMember(PollenServiceContext context, String pollId, String voterListId, VoterListMember member) {
- return context.getVoterListService().addMember(pollId, voterListId, member);
+ public VoterListMember addMember(PollenServiceContext context, String voterListId, VoterListMember member) throws EntityNotFoundException {
+ return context.getVoterListService().addMember(voterListId, member);
}
- public VoterListMember editMember(PollenServiceContext context, String pollId, String voterListId, VoterListMember member) {
- return context.getVoterListService().editMember(pollId, voterListId, member);
+ public VoterListMember editMember(PollenServiceContext context, VoterListMember member) throws EntityNotFoundException {
+ return context.getVoterListService().editMember(member);
}
- public void deleteMember(PollenServiceContext context, String pollId, String voterListId, String memberId) {
- context.getVoterListService().deleteMember(pollId, voterListId, memberId);
+ public void deleteMember(PollenServiceContext context, String voterListId, String memberId) throws EntityNotFoundException {
+ context.getVoterListService().deleteMember(voterListId, memberId);
}
}
Modified: branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping
===================================================================
--- branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-rest-api/src/main/resources/mapping 2013-06-06 16:43:31 UTC (rev 3817)
@@ -8,8 +8,16 @@
* /* PollenIdOrTokenInjector.inject
* /* PollenSecurityFilter.inject (prend le param auth pour retrouver le PollenUser)
-- une fois un object lié à PollenUser, c'est immuable.
+#- une fois un object lié à PollenUser, c'est immuable.
+[errors]
+
+org.chorem.pollen.service.exception.EntityNotFoundException action:ErrorAction.on402
+org.chorem.pollen.service.exception.UserEmailAlreadyUsedException action:ErrorAction.on500
+org.chorem.pollen.service.exception.UserLoginAlreadyUsedException action:ErrorAction.on500
+org.chorem.pollen.service.exception.UserInvalidPasswordException action:ErrorAction.on500
+org.chorem.pollen.service.exception.UserInvalidEmailActiviationTokenException action:ErrorAction.on500
+
[actions]
# AuthService
@@ -20,74 +28,74 @@
# CommentService
-GET /poll/{pollId}/comments action:CommentService.getComments
-POST /poll/{pollId}/comment action:CommentService.addComment
-GET /comment/{commentId} action:CommentService.getComment
-PUT /comment action:CommentService.editComment
-DELETE /comment/{commentId} action:CommentService.deleteComment
+GET /polls/{pollId}/comments action:CommentService.getComments
+POST /polls/{pollId}/comments action:CommentService.addComment
+GET /comments/{commentId} action:CommentService.getComment
+PUT /comments action:CommentService.editComment
+DELETE /polls/{pollId}/comments/{commentId} action:CommentService.deleteComment
# FavoriteListService
-GET /favoriteList action:FavoriteList.getFavoriteLists
-GET /favoriteList/{flId} action:FavoriteList.getFavoriteList
-POST /favoriteList action:FavoriteList.createFavoriteList
-PUT /favoriteList action:FavoriteList.editFavoriteList
-DELETE /favoriteList/{flId} action:FavoriteList.deleteFavoriteList
-GET /favoriteList/{flId}/members action:FavoriteList.getMembers
-GET /favoriteListMember/{mId} action:FavoriteList.getMember
-POST /favoriteList/{flId}/member action:FavoriteList.addMember
-PUT /favoriteListMember action:FavoriteList.editMember
-DELETE /favoriteListMember/{mId} action:FavoriteList.removeMember
+GET /favoriteLists action:FavoriteList.getFavoriteLists
+GET /favoriteLists/{flId} action:FavoriteList.getFavoriteList
+POST /favoriteLists action:FavoriteList.createFavoriteList
+PUT /favoriteLists action:FavoriteList.editFavoriteList
+DELETE /favoriteLists/{flId} action:FavoriteList.deleteFavoriteList
+GET /favoriteLists/{flId}/members action:FavoriteList.getMembers
+GET /favoriteListMembers/{mId} action:FavoriteList.getMember
+POST /favoriteLists/{flId}/members action:FavoriteList.addMember
+PUT /favoriteListMembers action:FavoriteList.editMember
+DELETE /favoriteLists/{flId}/members/{mId} action:FavoriteList.removeMember
# PollService
-GET /poll action:PollService.getPolls
-GET /poll/created action:PollService.getCreatedPolls
-GET /poll/invited action:PollService.getInvitedPolls
-GET /poll/participated action:PollService.getParticipatedPolls
-PUT /poll action:PollService.createPoll
-PUT /poll action:PollService.editPoll
-DELETE /poll/{pollOrTokenId} action:PollService.deletePoll
-POST /poll/{pollId} action:PollService.clonePoll
-GET /poll/{pollId}/export action:PollService.exportPoll
-PUT /poll/{pollId}/close action:PollService.closePoll
+GET /polls action:PollService.getPolls
+GET /polls/created action:PollService.getCreatedPolls
+GET /polls/invited action:PollService.getInvitedPolls
+GET /polls/participated action:PollService.getParticipatedPolls
+PUT /polls action:PollService.createPoll
+PUT /polls action:PollService.editPoll
+DELETE /polls/{pollOrTokenId} action:PollService.deletePoll
+POST /polls/{pollId} action:PollService.clonePoll
+GET /polls/{pollId}/export action:PollService.exportPoll
+PUT /polls/{pollId}/close action:PollService.closePoll
-GET /poll/{pollId}/choices action:PollService.getChoices
-POST /poll/{pollId}/choice action:PollService.addChoice
-GET /choice/{choiceId} action:PollService.getChoice
-PUT /choice action:PollService.editChoice
-DELETE /choice/{choiceId} action:PollService.deleteChoice
-
+GET /polls/{pollId}/choices action:PollService.getChoices
+POST /polls/{pollId}/choices action:PollService.addChoice
+GET /choices/{choiceId} action:PollService.getChoice
+PUT /choices action:PollService.editChoice
+DELETE /polls/{pollId}/choices/{choiceId} action:PollService.deleteChoice
+
# UserService
-GET /user action:UserService.getUsers
-GET /user/{userId} action:UserService.getUser
-POST /user action:UserService.createUser
-PUT /user action:UserService.editUser
+GET /users action:UserService.getUsers
+GET /users/{userId} action:UserService.getUser
+POST /users action:UserService.createUser
+PUT /users action:UserService.editUser
GET /validateemail/{token} action:UserService.validateUserEmail
# VoteCountingService
-GET /poll/{pollId}/results action:VoteCountingService.getResult
+GET /polls/{pollId}/results action:VoteCountingService.getResult
# VoterListService
-PUT /poll/{pollId}/favoriteLists/{flId} action:VoterListService.importFavoriteList
-GET /poll/{pollId}/voterLists action:VoterListService.getVoterLists
-GET /voterList/{vlId} action:VoterListService.getVoterList
-PUT /voterList/{vlId} action:VoterListService.editVoterList
-DELETE /voterList/{vlId} action:VoterListService.deleteVoterList
+PUT /polls/{pollId}/favoriteLists/{flId} action:VoterListService.importFavoriteList
+GET /polls/{pollId}/voterLists action:VoterListService.getVoterLists
+GET /voterLists/{vlId} action:VoterListService.getVoterList
+PUT /voterLists/{vlId} action:VoterListService.editVoterList
+DELETE /polls/{pollId}/voterLists/{vlId} action:VoterListService.deleteVoterList
-GET /voterList/{vlId}/members action:VoterListService.getMembers
-GET /voterListMember/{mId} action:VoterListService.getMember
-POST /voterList/{vlId}/member action:VoterListService.addMember
-PUT /voterListMember action:VoterListService.editMember
-DELETE /voterListMember/{mId} action:VoterListService.deleteMember
+GET /voterLists/{vlId}/members action:VoterListService.getMembers
+GET /voterListMembers/{mId} action:VoterListService.getMember
+POST /voterLists/{vlId}/members action:VoterListService.addMember
+PUT /voterListMembers action:VoterListService.editMember
+DELETE /voterLists/{vlId}/members/{mId} action:VoterListService.deleteMember
# VoteService
-GET /poll/{pollId}/votes action:VoteService.getVotes
-PUT /poll/{pollId}/vote action:VoteService.addVote
-GET /vote/{voteId} action:VoteService.getVote
-PUT /vote action:VoteService.editVote
-DELETE /vote/{voteId} action:VoteService.deleteVote
+GET /polls/{pollId}/votes action:VoteService.getVotes
+PUT /polls/{pollId}/votes action:VoteService.addVote
+GET /votes/{voteId} action:VoteService.getVote
+PUT /votes action:VoteService.editVote
+DELETE /polls/{pollId}/votes/{voteId} action:VoteService.deleteVote
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AbstractPollenService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -26,6 +26,7 @@
import com.google.common.base.Preconditions;
import org.chorem.pollen.persistence.PollenPersistenceContext;
import org.chorem.pollen.service.config.PollenServiceConfig;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import org.nuiton.jpa.api.JpaEntities;
import org.nuiton.jpa.api.JpaEntity;
@@ -101,4 +102,16 @@
protected VoteService getVoteService() {
return serviceContext.getVoteService();
}
+
+ protected EmailService getEmailService() {
+ return serviceContext.getEmailService();
+ }
+
+ protected <E extends JpaEntity> void checkEntityExists(Class<E> type,
+ E entity,
+ String entityId) throws EntityNotFoundException {
+ if (entity == null) {
+ throw new EntityNotFoundException(type, entityId);
+ }
+ }
}
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/AuthService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -24,6 +24,12 @@
*/
import com.google.common.base.Preconditions;
+import org.chorem.pollen.persistence.dao.PollenUserJpaDao;
+import org.chorem.pollen.persistence.dao.SessionTokenJpaDao;
+import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.persistence.entity.SessionToken;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.service.exception.UserInvalidPasswordException;
/**
* TODO
@@ -33,20 +39,78 @@
*/
public class AuthService extends AbstractPollenService {
- public String login(String login, String password) {
+ public String login(String login, String password) throws EntityNotFoundException, UserInvalidPasswordException {
Preconditions.checkNotNull(login);
Preconditions.checkNotNull(password);
- //TODO
- return null;
+
+ PollenUser user = getPersistenceContext().getPollenUserDao().findByLogin(login);
+ if (user == null) {
+ throw new EntityNotFoundException(PollenUser.class, login);
+ }
+
+ String encodedPassword = serviceContext.encodePassword(password);
+ if (!encodedPassword.equals(user.getPassword())) {
+ throw new UserInvalidPasswordException();
+ }
+
+ // Create a new session Token
+ SessionTokenJpaDao dao = getPersistenceContext().getSessionTokenDao();
+
+ SessionToken sessionToken = dao.newInstance();
+ String token = serviceContext.generateUUID();
+ String encodedToken = serviceContext.encodePassword(token);
+ sessionToken.setPollenUser(user);
+ sessionToken.setToken(encodedToken);
+ sessionToken.setCreationDate(serviceContext.getNow());
+
+ dao.persist(sessionToken);
+ getPersistenceContext().commit();
+
+ return token;
}
- public void lostPassword(String token) {
+ public void lostPassword(String login) throws EntityNotFoundException {
+ Preconditions.checkNotNull(login);
+
+ PollenUserJpaDao dao = getPersistenceContext().getPollenUserDao();
+
+ PollenUser user = dao.findByLogin(login);
+ if (user == null) {
+ throw new EntityNotFoundException(PollenUser.class, login);
+ }
+
+ // Generate a new password
+ String newPassword = serviceContext.generatePassword();
+ String encodedPassword = serviceContext.encodePassword(newPassword);
+ user.setPassword(encodedPassword);
+ dao.merge(user);
+ getPersistenceContext().commit();
+
+ notifyPasswordChanged(user, newPassword);
+ }
+
+ public void logout(String login, String token) throws EntityNotFoundException {
+ Preconditions.checkNotNull(login);
Preconditions.checkNotNull(token);
- //TODO
+ PollenUser user = getPersistenceContext().getPollenUserDao().findByLogin(login);
+ if (user == null) {
+ throw new EntityNotFoundException(PollenUser.class, login);
+ }
+
+ String encodedToken = serviceContext.encodePassword(token);
+
+ SessionTokenJpaDao dao = getPersistenceContext().getSessionTokenDao();
+
+ SessionToken sessionToken = dao.findByToken(encodedToken);
+ if (sessionToken == null) {
+ throw new EntityNotFoundException(SessionToken.class, token);
+ }
+
+ dao.remove(sessionToken);
+ getPersistenceContext().commit();
}
- public void logout(String login) {
- Preconditions.checkNotNull(login);
+ protected void notifyPasswordChanged(PollenUser user, String newPassword) {
//TODO
}
}
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/CommentService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/CommentService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/CommentService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -26,6 +26,7 @@
import com.google.common.base.Preconditions;
import org.chorem.pollen.persistence.entity.Comment;
import org.chorem.pollen.persistence.entity.Poll;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import java.util.List;
@@ -37,60 +38,50 @@
*/
public class CommentService extends AbstractPollenService {
- public List<Comment> getComments(String pollId) {
+ public List<Comment> getComments(String pollId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
-
return poll.getComment();
}
- public Comment getComment(String pollId, String commentId) {
- Preconditions.checkNotNull(pollId);
+ public Comment getComment(String commentId) throws EntityNotFoundException {
Preconditions.checkNotNull(commentId);
- Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
-
- Comment comment = poll.getCommentById(commentId);
- Preconditions.checkNotNull(comment);
-
- return comment;
+ Comment result = getPersistenceContext().getCommentDao().findById(commentId);
+ checkEntityExists(Comment.class, result, commentId);
+ return result;
}
- public Comment addComment(String pollId, Comment comment) {
+ public Comment addComment(String pollId, Comment comment) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
checkHasNoId(comment);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
poll.addComment(comment);
getPersistenceContext().getPollDao().merge(poll);
getPersistenceContext().commit();
- return null;
+
+ Comment result = getComment(comment.getId());
+ return result;
}
- public Comment editComment(String pollId, Comment comment) {
- Preconditions.checkNotNull(pollId);
- checkHasId(comment);
- Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
+ public Comment editComment(Comment comment) throws EntityNotFoundException {
- Comment persisted = poll.getCommentById(comment.getId());
- Preconditions.checkNotNull(persisted);
+ // check comment exists
+ getComment(comment.getId());
getPersistenceContext().getCommentDao().merge(comment);
-
getPersistenceContext().commit();
- return null;
+
+ Comment result = getComment(comment.getId());
+ return result;
}
- public void deleteComment(String pollId, String commentId) {
+ public void deleteComment(String pollId, String commentId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Preconditions.checkNotNull(commentId);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
- Comment comment = poll.getCommentById(commentId);
+ Comment comment = getComment(commentId);
Preconditions.checkNotNull(comment);
poll.removeComment(comment);
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/DefaultPollenServiceContext.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -23,11 +23,11 @@
* #L%
*/
-import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
+import org.apache.commons.lang3.RandomStringUtils;
import org.chorem.pollen.persistence.PollenPersistenceContext;
import org.chorem.pollen.service.config.PollenServiceConfig;
+import org.nuiton.util.StringUtil;
-import javax.persistence.EntityManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
@@ -35,20 +35,18 @@
public class DefaultPollenServiceContext implements PollenServiceContext {
- protected EntityManager entityManager;
-
protected PollenServiceConfig pollenServiceConfig;
protected PollenPersistenceContext persistenceContext;
- public void setEntityManager(EntityManager entityManager) {
- this.entityManager = entityManager;
- }
-
public void setPollenServiceConfig(PollenServiceConfig pollenServiceConfig) {
this.pollenServiceConfig = pollenServiceConfig;
}
+ public void setPersistenceContext(PollenPersistenceContext persistenceContext) {
+ this.persistenceContext = persistenceContext;
+ }
+
@Override
public PollenServiceConfig getPollenServiceConfig() {
return pollenServiceConfig;
@@ -65,11 +63,12 @@
return now;
}
+ public String generatePassword() {
+ return RandomStringUtils.randomAlphanumeric(8);
+ }
+
@Override
public PollenPersistenceContext getPersistenceContext() {
- if (persistenceContext == null) {
- persistenceContext = new JpaPollenPersistenceContext(entityManager);
- }
return persistenceContext;
}
@@ -113,6 +112,16 @@
return newService(VoteService.class);
}
+ @Override
+ public EmailService getEmailService() {
+ return newService(EmailService.class);
+ }
+
+ @Override
+ public String encodePassword(String password) {
+ return StringUtil.encodeMD5(password);
+ }
+
protected <E extends PollenServiceSupport> E newService(Class<E> serviceClass) {
E service;
Added: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/EmailService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/EmailService.java (rev 0)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/EmailService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,39 @@
+package org.chorem.pollen.service;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.chorem.pollen.persistence.entity.PollenUser;
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class EmailService extends AbstractPollenService {
+
+ public void onUserCreated(PollenUser user) {
+ //TODO
+ }
+}
Property changes on: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/EmailService.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FavoriteListService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FavoriteListService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FavoriteListService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -27,6 +27,7 @@
import org.chorem.pollen.persistence.entity.FavoriteList;
import org.chorem.pollen.persistence.entity.FavoriteListMember;
import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import java.util.List;
@@ -38,65 +39,57 @@
*/
public class FavoriteListService extends AbstractPollenService {
- public List<FavoriteList> getFavoriteLists(String userId) {
+ public List<FavoriteList> getFavoriteLists(String userId)throws EntityNotFoundException {
Preconditions.checkNotNull(userId);
PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
List<FavoriteList> result = user.getFavoriteList();
return result;
}
- public FavoriteList getFavoriteList(String userId, String favoriteListId) {
- Preconditions.checkNotNull(userId);
+ public FavoriteList getFavoriteList(String favoriteListId) throws EntityNotFoundException{
Preconditions.checkNotNull(favoriteListId);
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
- FavoriteList favoriteList = user.getFavoriteListById(favoriteListId);
- return favoriteList;
+ FavoriteList result = getPersistenceContext().getFavoriteListDao().findById(favoriteListId);
+ checkEntityExists(FavoriteList.class, result, favoriteListId);
+ return result;
}
- public FavoriteList createFavoriteList(String userId, FavoriteList favoriteList) {
+ public FavoriteList createFavoriteList(String userId,
+ FavoriteList favoriteList) throws EntityNotFoundException{
Preconditions.checkNotNull(userId);
Preconditions.checkNotNull(favoriteList);
checkHasNoId(favoriteList);
PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
user.addFavoriteList(favoriteList);
- user = getPersistenceContext().getPollenUserDao().merge(user);
+ getPersistenceContext().getPollenUserDao().merge(user);
getPersistenceContext().commit();
- return user.getFavoriteListById(favoriteList.getId());
+ FavoriteList result = getFavoriteList(favoriteList.getId());
+ return result;
}
- public FavoriteList editFavoriteList(String userId, FavoriteList favoriteList) {
- Preconditions.checkNotNull(userId);
+ public FavoriteList editFavoriteList(FavoriteList favoriteList) throws EntityNotFoundException{
Preconditions.checkNotNull(favoriteList);
checkHasId(favoriteList);
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
+ getFavoriteList(favoriteList.getId());
- FavoriteList persisted = user.getFavoriteListById(favoriteList.getId());
- Preconditions.checkNotNull(persisted);
+ getPersistenceContext().getFavoriteListDao().merge(favoriteList);
- getPersistenceContext().getFavoriteListDao().persist(favoriteList);
-
getPersistenceContext().commit();
- return favoriteList;
+ FavoriteList result = getFavoriteList(favoriteList.getId());
+ return result;
}
- public void deleteFavoriteList(String userId, String favoriteListId) {
+ public void deleteFavoriteList(String userId, String favoriteListId) throws EntityNotFoundException{
Preconditions.checkNotNull(userId);
Preconditions.checkNotNull(favoriteListId);
PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
- FavoriteList persisted = user.getFavoriteListById(favoriteListId);
- Preconditions.checkNotNull(persisted);
+ FavoriteList persisted = getFavoriteList(favoriteListId);
user.removeFavoriteList(persisted);
getPersistenceContext().getPollenUserDao().merge(user);
@@ -104,89 +97,59 @@
getPersistenceContext().commit();
}
- public List<FavoriteListMember> getMembers(String userId, String favoriteListId) {
- Preconditions.checkNotNull(userId);
+ public List<FavoriteListMember> getFavoriteListMembers(String favoriteListId)throws EntityNotFoundException {
Preconditions.checkNotNull(favoriteListId);
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
+ FavoriteList favoriteList = getFavoriteList(favoriteListId);
- FavoriteList favoriteList = user.getFavoriteListById(favoriteListId);
- Preconditions.checkNotNull(favoriteList);
-
return favoriteList.getFavoriteListMember();
}
- public FavoriteListMember getMember(String userId, String favoriteListId, String memberId) {
- Preconditions.checkNotNull(userId);
- Preconditions.checkNotNull(favoriteListId);
+ public FavoriteListMember getFavoriteListMember(String memberId)throws EntityNotFoundException {
Preconditions.checkNotNull(memberId);
-
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
-
- FavoriteList favoriteList = user.getFavoriteListById(favoriteListId);
- Preconditions.checkNotNull(favoriteList);
-
- FavoriteListMember member = favoriteList.getFavoriteListMemberById(memberId);
- return member;
+ FavoriteListMember result = getPersistenceContext().getFavoriteListMemberDao().findById(memberId);
+ checkEntityExists(FavoriteListMember.class, result, memberId);
+ return result;
}
- public FavoriteListMember addMember(String userId, String favoriteListId, FavoriteListMember member) {
- Preconditions.checkNotNull(userId);
+ public FavoriteListMember addFavoriteListMember(String favoriteListId,
+ FavoriteListMember member)throws EntityNotFoundException {
Preconditions.checkNotNull(favoriteListId);
Preconditions.checkNotNull(member);
checkHasNoId(member);
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
+ FavoriteList favoriteList = getFavoriteList(favoriteListId);
- FavoriteList favoriteList = user.getFavoriteListById(favoriteListId);
- Preconditions.checkNotNull(favoriteList);
-
favoriteList.addFavoriteListMember(member);
- favoriteList = getPersistenceContext().getFavoriteListDao().merge(favoriteList);
+ getPersistenceContext().getFavoriteListDao().merge(favoriteList);
getPersistenceContext().commit();
- FavoriteListMember result = favoriteList.getFavoriteListMemberById(member.getId());
+ FavoriteListMember result = getFavoriteListMember(member.getId());
return result;
}
- public FavoriteListMember editMember(String userId, String favoriteListId, FavoriteListMember member) {
- Preconditions.checkNotNull(userId);
- Preconditions.checkNotNull(favoriteListId);
+ public FavoriteListMember editFavoriteListMember(FavoriteListMember member)throws EntityNotFoundException {
Preconditions.checkNotNull(member);
checkHasId(member);
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
- FavoriteList favoriteList = user.getFavoriteListById(favoriteListId);
- Preconditions.checkNotNull(favoriteList);
+ getFavoriteListMember(member.getId());
- FavoriteListMember persisted = favoriteList.getFavoriteListMemberById(member.getId());
- Preconditions.checkNotNull(persisted);
-
member = getPersistenceContext().getFavoriteListMemberDao().merge(member);
getPersistenceContext().commit();
- return member;
+ FavoriteListMember result = getFavoriteListMember(member.getId());
+ return result;
}
- public void removeMember(String userId, String favoriteListId, String memberId) {
- Preconditions.checkNotNull(userId);
+ public void removeFavoriteListMember(String favoriteListId, String memberId) throws EntityNotFoundException{
Preconditions.checkNotNull(favoriteListId);
Preconditions.checkNotNull(memberId);
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
+ FavoriteList favoriteList = getFavoriteList(favoriteListId);
- FavoriteList favoriteList = user.getFavoriteListById(favoriteListId);
- Preconditions.checkNotNull(favoriteList);
+ FavoriteListMember member = getFavoriteListMember(memberId);
- FavoriteListMember member = favoriteList.getFavoriteListMemberById(memberId);
- Preconditions.checkNotNull(member);
-
favoriteList.removeFavoriteListMember(member);
getPersistenceContext().getFavoriteListDao().merge(favoriteList);
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FixturesService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FixturesService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/FixturesService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -84,6 +84,7 @@
for (PollenUser user : users) {
+ user.setPassword(serviceContext.encodePassword(user.getPassword()));
userDao.persist(user);
}
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -27,6 +27,7 @@
import org.chorem.pollen.persistence.entity.Choice;
import org.chorem.pollen.persistence.entity.Poll;
import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import java.io.File;
import java.util.List;
@@ -40,168 +41,156 @@
*/
public class PollService extends AbstractPollenService {
- public Set<Poll> getCreatedPolls(String userId) {
+ public Set<Poll> getCreatedPolls(String userId) throws EntityNotFoundException {
Preconditions.checkNotNull(userId);
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
+ getUserService().getUser(userId);
return getPersistenceContext().getPollDao().findAllCreated(userId);
}
- public Set<Poll> getInvitedPolls(String userId) {
+ public Set<Poll> getInvitedPolls(String userId) throws EntityNotFoundException {
Preconditions.checkNotNull(userId);
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
+ getUserService().getUser(userId);
return getPersistenceContext().getPollDao().findAllInvited(userId);
}
- public Set<Poll> getParticipatedPolls(String userId) {
+ public Set<Poll> getParticipatedPolls(String userId) throws EntityNotFoundException {
Preconditions.checkNotNull(userId);
- PollenUser user = getUserService().getUser(userId);
- Preconditions.checkNotNull(user);
+ getUserService().getUser(userId);
return getPersistenceContext().getPollDao().findAllParticipated(userId);
}
- public Poll getPoll(String pollId) {
+ public Poll getPoll(String pollId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Poll result = getPersistenceContext().getPollDao().findById(pollId);
+ checkEntityExists(Poll.class, result, pollId);
return result;
}
- public Poll createPoll(String userId, Poll poll) {
+ public Poll createPoll(String userId, Poll poll) throws EntityNotFoundException {
Preconditions.checkNotNull(userId);
Preconditions.checkNotNull(poll);
checkHasNoId(poll);
- PollenUser user = getUserService().getUser(userId);
+ if (userId != null) {
- if (user != null) {
+ // get user
+ PollenUser user = getUserService().getUser(userId);
- // link to creator
- //TODO
+ // link it to creator
+
}
+
getPersistenceContext().getPollDao().persist(poll);
getPersistenceContext().commit();
return poll;
}
- public Poll editPoll(Poll poll) {
+ public Poll editPoll(Poll poll) throws EntityNotFoundException {
Preconditions.checkNotNull(poll);
checkHasId(poll);
- Poll persisted = getPoll(poll.getId());
- Preconditions.checkNotNull(persisted);
+ getPoll(poll.getId());
- Poll result = getPersistenceContext().getPollDao().merge(poll);
+ getPersistenceContext().getPollDao().merge(poll);
getPersistenceContext().commit();
+
+ Poll result = getPoll(poll.getId());
return result;
}
- public void deletePoll(String pollId) {
+ public void deletePoll(String pollId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Poll poll = getPoll(pollId);
- Preconditions.checkNotNull(poll);
getPersistenceContext().getPollDao().remove(poll);
getPersistenceContext().commit();
}
- public Poll clonePoll(String pollId) {
+ public Poll clonePoll(String pollId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Poll poll = getPoll(pollId);
- Preconditions.checkNotNull(poll);
-
+ //TODO
getPersistenceContext().commit();
return null;
}
- public File closePoll(String pollId) {
+ public File closePoll(String pollId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Poll poll = getPoll(pollId);
- Preconditions.checkNotNull(poll);
-
+ //TODO
getPersistenceContext().commit();
return null;
}
- public File exportPoll(String pollId) {
+ public File exportPoll(String pollId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
+ Poll poll = getPoll(pollId);
//TODO
return null;
}
- public List<Choice> getChoices(String pollId) {
+ public List<Choice> getChoices(String pollId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Poll poll = getPoll(pollId);
- Preconditions.checkNotNull(poll);
return poll.getChoice();
}
- public Choice getChoice(String pollId, String choiceId) {
- Preconditions.checkNotNull(pollId);
+ public Choice getChoice(String choiceId) throws EntityNotFoundException {
Preconditions.checkNotNull(choiceId);
- Poll poll = getPoll(pollId);
- Preconditions.checkNotNull(poll);
-
- Choice result = poll.getChoiceById(choiceId);
+ Choice result = getPersistenceContext().getChoiceDao().findById(choiceId);
+ checkEntityExists(Choice.class, result, choiceId);
return result;
}
- public Choice addChoice(String pollId, Choice choice) {
+ public Choice addChoice(String pollId, Choice choice) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Preconditions.checkNotNull(choice);
checkHasNoId(choice);
Poll poll = getPoll(pollId);
- Preconditions.checkNotNull(poll);
poll.addChoice(choice);
getPersistenceContext().getPollDao().merge(poll);
getPersistenceContext().commit();
- return null;
+ Choice result = getChoice(choice.getId());
+ return result;
}
- public Choice editChoice(String pollId, Choice choice) {
- Preconditions.checkNotNull(pollId);
+ public Choice editChoice(Choice choice) throws EntityNotFoundException {
Preconditions.checkNotNull(choice);
checkHasId(choice);
- Poll poll = getPoll(pollId);
- Preconditions.checkNotNull(poll);
+ getChoice(choice.getId());
- Choice persisted = poll.getChoiceById(choice.getId());
- Preconditions.checkNotNull(persisted);
-
- Choice result = getPersistenceContext().getChoiceDao().merge(choice);
-
+ getPersistenceContext().getChoiceDao().merge(choice);
getPersistenceContext().commit();
+
+ Choice result = getChoice(choice.getId());
return result;
}
- public void deleteChoice(String pollId, String choiceId) {
+ public void deleteChoice(String pollId, String choiceId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Preconditions.checkNotNull(choiceId);
Poll poll = getPoll(pollId);
- Preconditions.checkNotNull(poll);
+ Choice choice = getChoice(choiceId);
- Choice choice = poll.getChoiceById(choiceId);
- Preconditions.checkNotNull(choice);
-
poll.removeChoice(choice);
getPersistenceContext().getPollDao().merge(poll);
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/PollenServiceContext.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -58,4 +58,9 @@
VoteService getVoteService();
+ EmailService getEmailService();
+
+ String generatePassword();
+
+ String encodePassword(String password);
}
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/UserService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -25,8 +25,16 @@
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
import org.chorem.pollen.persistence.dao.PollenUserJpaDao;
import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.service.exception.UserEmailAlreadyUsedException;
+import org.chorem.pollen.service.exception.UserInvalidEmailActiviationTokenException;
+import org.chorem.pollen.service.exception.UserInvalidPasswordException;
+import org.chorem.pollen.service.exception.UserLoginAlreadyUsedException;
+import org.nuiton.util.beans.Binder;
+import org.nuiton.util.beans.BinderFactory;
import java.util.List;
@@ -42,70 +50,134 @@
return getPollenUserDao().findAll();
}
- public PollenUser getUser(String userId) {
+ public PollenUser getUser(String userId) throws EntityNotFoundException {
Preconditions.checkNotNull(userId);
- return getPollenUserDao().findById(userId);
+ PollenUser result = getPollenUserDao().findById(userId);
+ checkEntityExists(PollenUser.class, result, userId);
+ return result;
}
- public PollenUser createUserByAdmin(PollenUser user) {
+ public PollenUser createUser(PollenUser user, boolean generatePassword) throws UserLoginAlreadyUsedException, UserEmailAlreadyUsedException {
Preconditions.checkNotNull(user);
checkHasNoId(user);
+ Preconditions.checkNotNull(user.getLogin());
+ Preconditions.checkNotNull(user.getEmail());
- getPollenUserDao().persist(user);
- getPersistenceContext().commit();
+ PollenUserJpaDao dao = getPollenUserDao();
- // send a notification to user (to validate his email changed)
- notifyUserCreated(user, true);
- return user;
- }
+ // check login is available
+ boolean loginExists = dao.loginExists(user.getLogin());
+ if (loginExists) {
+ throw new UserLoginAlreadyUsedException(user.getLogin());
+ }
- public PollenUser createUser(PollenUser user) {
- Preconditions.checkNotNull(user);
- checkHasNoId(user);
+ // check email is available
+ boolean emailExists = dao.emailExists(user.getEmail());
+ if (emailExists) {
+ throw new UserEmailAlreadyUsedException(user.getEmail());
+ }
+ PollenUser toCreate = dao.newInstance();
+
// add a emailValidationToken
String emailValidationToken = generateId();
- user.setEmailActivationToken(emailValidationToken);
- PollenUserJpaDao dao = getPollenUserDao();
- dao.persist(user);
+ String password;
+ if (generatePassword) {
+ // let's generate the new password
+ password = serviceContext.generatePassword();
+ } else {
+ password = user.getPassword();
+ }
+
+ // encode the password
+ String encodedPassword = serviceContext.encodePassword(password);
+
+ toCreate.setLogin(user.getLogin());
+ toCreate.setEmailActivationToken(emailValidationToken);
+ toCreate.setPassword(encodedPassword);
+
+ copyPollenUser(user, toCreate, true);
+
+ dao.persist(toCreate);
getPersistenceContext().commit();
- // send a notification to user (to validate his email changed)
- notifyUserCreated(user, false);
- return user;
+ notifyUserCreated(toCreate);
+
+ return toCreate;
}
- public PollenUser editUser(PollenUser user) {
+ public PollenUser editUser(PollenUser user) throws UserInvalidPasswordException, UserEmailAlreadyUsedException, EntityNotFoundException {
Preconditions.checkNotNull(user);
checkHasId(user);
+
PollenUser persisted = getUser(user.getId());
- Preconditions.checkNotNull(persisted);
+ PollenUserJpaDao dao = getPollenUserDao();
- boolean emailChanged = ObjectUtils.notEqual(persisted.getEmail(), user.getEmail());
+ // check current password
+ String encodedPassword = serviceContext.encodePassword(user.getPassword());
+ if (!encodedPassword.equals(persisted.getPassword())) {
+ throw new UserInvalidPasswordException();
+ }
+ boolean emailChanged = ObjectUtils.notEqual(persisted.getEmail(),
+ user.getEmail());
+
if (emailChanged) {
+ // check this email is not used by another user
+ boolean emailUsed = dao.emailExists(user.getEmail());
+ if (emailUsed) {
+ throw new UserEmailAlreadyUsedException(user.getEmail());
+ }
+
// add a new emailValidationtoken
String emailValidationToken = generateId();
- user.setEmailActivationToken(emailValidationToken);
+ persisted.setEmailActivationToken(emailValidationToken);
}
- user = getPollenUserDao().merge(user);
+ copyPollenUser(user, persisted, true);
+
+ persisted = dao.merge(persisted);
getPersistenceContext().commit();
if (emailChanged) {
- // send a notification to user (to validate his email changed)
notifyEmailChanged(persisted);
}
- return user;
+ return persisted;
}
- public void validateUserEmail(String userId, String token) {
+ public void changePassword(String userId,
+ String oldPassword,
+ String newPassword) throws UserInvalidPasswordException, EntityNotFoundException {
+ Preconditions.checkNotNull(userId);
+ Preconditions.checkNotNull(oldPassword);
+ Preconditions.checkNotNull(newPassword);
+ PollenUser user = getUser(userId);
+
+ // check current password
+ String encodedPassword = serviceContext.encodePassword(user.getPassword());
+ if (!encodedPassword.equals(user.getPassword())) {
+ throw new UserInvalidPasswordException();
+ }
+
+ // encode new password and store it in user account
+ String newEncodedPassword = serviceContext.encodePassword(newPassword);
+ user.setPassword(newEncodedPassword);
+
+ user = getPollenUserDao().merge(user);
+ getPersistenceContext().commit();
+
+ notifyPasswordChanged(user);
+ }
+
+ public void validateUserEmail(String userId,
+ String token) throws EntityNotFoundException, UserInvalidEmailActiviationTokenException {
+
Preconditions.checkNotNull(userId);
Preconditions.checkNotNull(token);
@@ -116,23 +188,57 @@
boolean valid = ObjectUtils.equals(
user.getEmailActivationToken(), token);
- if (valid) {
- user.setEmailActivationToken(null);
+ if (!valid) {
+ throw new UserInvalidEmailActiviationTokenException();
}
+ // reset token in database
+ user.setEmailActivationToken(null);
+
getPollenUserDao().merge(user);
getPersistenceContext().commit();
}
+ protected void notifyUserCreated(PollenUser user) {
+
+ //TODO
+ }
+
protected void notifyEmailChanged(PollenUser user) {
+
//TODO
}
- protected void notifyUserCreated(PollenUser user, boolean createByAdmin) {
+ protected void notifyPasswordChanged(PollenUser user) {
+
//TODO
}
protected PollenUserJpaDao getPollenUserDao() {
return getPersistenceContext().getPollenUserDao();
}
+
+ /**
+ * Copy {@code source} user account to {@code destination} one.
+ * The email is lower cased in the {@code destination} user account.
+ *
+ * @param source user account to copy
+ * @param destination which receive the copy
+ */
+ protected void copyPollenUser(PollenUser source,
+ PollenUser destination,
+ boolean copyEmail) {
+ Binder<PollenUser, PollenUser> binder =
+ BinderFactory.newBinder(PollenUser.class);
+
+ binder.copy(source, destination,
+ PollenUser.PROPERTY_ADMINISTRATOR,
+ PollenUser.PROPERTY_NAME,
+ PollenUser.PROPERTY_LANGUAGE);
+
+ if (copyEmail) {
+ // Don't keep case for email
+ destination.setEmail(StringUtils.lowerCase(source.getEmail()));
+ }
+ }
}
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteCountingService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteCountingService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteCountingService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -25,6 +25,7 @@
import com.google.common.base.Preconditions;
import org.chorem.pollen.persistence.entity.Poll;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
/**
* TODO
@@ -35,10 +36,9 @@
public class VoteCountingService extends AbstractPollenService {
//GET /poll/{pollId}/results
- public PollResult getResult(String pollId) {
+ public PollResult getResult(String pollId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
//TODO
return null;
}
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoteService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -26,6 +26,7 @@
import com.google.common.base.Preconditions;
import org.chorem.pollen.persistence.entity.Poll;
import org.chorem.pollen.persistence.entity.Vote;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import java.util.List;
@@ -37,66 +38,57 @@
*/
public class VoteService extends AbstractPollenService {
- public List<Vote> getVotes(String pollId) {
+ public List<Vote> getVotes(String pollId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
-
- return poll.getVote();
+ List<Vote> result = poll.getVote();
+ return result;
}
- public Vote getVote(String pollId, String voteId) {
- Preconditions.checkNotNull(pollId);
+ public Vote getVote(String voteId) throws EntityNotFoundException{
Preconditions.checkNotNull(voteId);
- Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
-
- Vote result = poll.getVoteById(voteId);
+ Vote result = getPersistenceContext().getVoteDao().findById(voteId);
+ checkEntityExists(Vote.class, result, voteId);
return result;
}
- public Vote addVote(String pollId, Vote vote) {
+ public Vote addVote(String pollId, Vote vote)throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Preconditions.checkNotNull(vote);
checkHasNoId(vote);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
poll.addVote(vote);
getPersistenceContext().getPollDao().merge(poll);
getPersistenceContext().commit();
- return null;
+ Vote result = getVote(vote.getId());
+ return result;
}
- public Vote editVote(String pollId, Vote vote) {
- Preconditions.checkNotNull(pollId);
+ public Vote editVote(Vote vote)throws EntityNotFoundException {
Preconditions.checkNotNull(vote);
checkHasId(vote);
- Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
+ getVote(vote.getId());
- Preconditions.checkState(poll.containsVoteById(vote.getId()));
-
- Vote result = getPersistenceContext().getVoteDao().merge(vote);
-
+ getPersistenceContext().getVoteDao().merge(vote);
getPersistenceContext().commit();
+
+ Vote result = getVote(vote.getId());
return result;
}
- public void deleteVote(String pollId, String voteId) {
+ public void deleteVote(String pollId, String voteId)throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Preconditions.checkNotNull(voteId);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
- Vote vote = getVote(pollId, voteId);
- Preconditions.checkNotNull(vote);
+ Vote vote = getVote(voteId);
poll.removeVote(vote);
Modified: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoterListService.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoterListService.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/VoterListService.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -31,6 +31,7 @@
import org.chorem.pollen.persistence.entity.Poll;
import org.chorem.pollen.persistence.entity.VoterList;
import org.chorem.pollen.persistence.entity.VoterListMember;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
import java.util.List;
import java.util.Set;
@@ -43,16 +44,14 @@
*/
public class VoterListService extends AbstractPollenService {
- public VoterList importFavoriteList(String userId, String pollId, String favoriteListId) {
- Preconditions.checkNotNull(userId);
+ public VoterList importFavoriteList(String pollId,
+ String favoriteListId) throws EntityNotFoundException {
Preconditions.checkNotNull(pollId);
Preconditions.checkNotNull(favoriteListId);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
- FavoriteList favoriteList = getFavoriteListService().getFavoriteList(userId, favoriteListId);
- Preconditions.checkNotNull(favoriteList);
+ FavoriteList favoriteList = getFavoriteListService().getFavoriteList(favoriteListId);
VoterListJpaDao dao = getPersistenceContext().getVoterListDao();
VoterList result = dao.newInstance();
@@ -71,158 +70,130 @@
result.addVoterListMember(voterListMember);
}
- dao.persist(result);
+ poll.addVoterList(result);
+ getPersistenceContext().getPollDao().merge(poll);
+
getPersistenceContext().commit();
return result;
}
- public List<VoterList> getVoterLists(String pollId) {
+ public List<VoterList> getVoterLists(String pollId) throws EntityNotFoundException{
Preconditions.checkNotNull(pollId);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
List<VoterList> result = poll.getVoterList();
return result;
}
- public VoterList getVoterList(String pollId, String voterListId) {
- Preconditions.checkNotNull(pollId);
-
- Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
-
- if (voterListId == null) {
-
- Preconditions.checkState(!poll.isVoterListEmpty());
-
- // use the first poll one
- voterListId = poll.getVoterList(0).getId();
- }
-
+ public VoterList getVoterList(String voterListId) throws EntityNotFoundException{
Preconditions.checkNotNull(voterListId);
- VoterList result = poll.getVoterListById(voterListId);
+ VoterList result = getPersistenceContext().getVoterListDao().findById(voterListId);
+ checkEntityExists(VoterList.class, result, voterListId);
+
return result;
}
- public VoterList addVoterList(String pollId, VoterList voterList) {
+ public VoterList addVoterList(String pollId, VoterList voterList) throws EntityNotFoundException{
Preconditions.checkNotNull(pollId);
Preconditions.checkNotNull(voterList);
checkHasNoId(voterList);
Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
- getPersistenceContext().getVoterListDao().persist(voterList);
+ poll.addVoterList(voterList);
+
+ getPersistenceContext().getPollDao().merge(poll);
getPersistenceContext().commit();
- return voterList;
+ VoterList result = getVoterList(voterList.getId());
+ return result;
}
- public VoterList editVoterList(String pollId, VoterList voterList) {
- Preconditions.checkNotNull(pollId);
+ public VoterList editVoterList(VoterList voterList) throws EntityNotFoundException{
Preconditions.checkNotNull(voterList);
checkHasId(voterList);
- Poll poll = getPollService().getPoll(pollId);
- Preconditions.checkNotNull(poll);
+ getVoterList(voterList.getId());
- Preconditions.checkState(poll.containsVoterListById(voterList.getId()));
-
- VoterList result = getPersistenceContext().getVoterListDao().merge(voterList);
+ getPersistenceContext().getVoterListDao().merge(voterList);
getPersistenceContext().commit();
+ VoterList result = getVoterList(voterList.getId());
return result;
}
- public void deleteVoterList(String pollId, String voterListId) {
+ public void deleteVoterList(String pollId, String voterListId) throws EntityNotFoundException{
Preconditions.checkNotNull(pollId);
Preconditions.checkNotNull(voterListId);
- VoterList voterList = getVoterList(pollId, voterListId);
- Preconditions.checkNotNull(voterList);
+ Poll poll = getPollService().getPoll(pollId);
- getPersistenceContext().getVoterListDao().remove(voterList);
+ VoterList voterList = getVoterList(voterListId);
+ poll.removeVoterList(voterList);
+
+ getPersistenceContext().getPollDao().merge(poll);
+
getPersistenceContext().commit();
}
- public Set<VoterListMember> getMembers(String pollId, String voterListId) {
- Preconditions.checkNotNull(pollId);
+ public Set<VoterListMember> getMembers(String voterListId) throws EntityNotFoundException{
Preconditions.checkNotNull(voterListId);
- VoterList voterList = getVoterList(pollId, voterListId);
- Preconditions.checkNotNull(voterList);
+ VoterList voterList = getVoterList(voterListId);
Set<VoterListMember> result = voterList.getVoterListMember();
return result;
}
- public VoterListMember getMember(String pollId, String voterListId, String memberId) {
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(voterListId);
+ public VoterListMember getMember(String memberId) throws EntityNotFoundException{
Preconditions.checkNotNull(memberId);
- VoterList voterList = getVoterList(pollId, voterListId);
- Preconditions.checkNotNull(voterList);
-
VoterListMember result = getPersistenceContext().getVoterListMemberDao().findById(memberId);
-
+ checkEntityExists(VoterListMember.class, result, memberId);
return result;
}
- public VoterListMember addMember(String pollId, String voterListId, VoterListMember member) {
- Preconditions.checkNotNull(pollId);
+ public VoterListMember addMember(String voterListId, VoterListMember member)throws EntityNotFoundException {
Preconditions.checkNotNull(voterListId);
Preconditions.checkNotNull(member);
checkHasNoId(member);
- VoterList voterList = getVoterList(pollId, voterListId);
- Preconditions.checkNotNull(voterList);
+ VoterList voterList = getVoterList(voterListId);
voterList.addVoterListMember(member);
- getPersistenceContext().getVoterListDao().persist(voterList);
+ getPersistenceContext().getVoterListDao().merge(voterList);
getPersistenceContext().commit();
- return member;
+ VoterListMember result = getMember(member.getId());
+ return result;
}
- public VoterListMember editMember(String pollId, String voterListId, VoterListMember member) {
- Preconditions.checkNotNull(pollId);
- Preconditions.checkNotNull(voterListId);
+ public VoterListMember editMember(VoterListMember member) throws EntityNotFoundException{
Preconditions.checkNotNull(member);
checkHasId(member);
- VoterList voterList = getVoterList(pollId, voterListId);
- Preconditions.checkNotNull(voterList);
+ getMember(member.getId());
- VoterListMemberJpaDao dao = getPersistenceContext().getVoterListMemberDao();
+ getPersistenceContext().getVoterListMemberDao().merge(member);
- VoterListMember persisted = dao.findById(member.getId());
- Preconditions.checkNotNull(persisted);
-
- VoterListMember result =
- dao.merge(member);
-
getPersistenceContext().commit();
+ VoterListMember result = getMember(member.getId());
return result;
}
- public void deleteMember(String pollId, String voterListId, String memberId) {
- Preconditions.checkNotNull(pollId);
+ public void deleteMember(String voterListId, String memberId) throws EntityNotFoundException{
Preconditions.checkNotNull(voterListId);
Preconditions.checkNotNull(memberId);
- VoterList voterList = getVoterList(pollId, voterListId);
- Preconditions.checkNotNull(voterList);
+ VoterList voterList = getVoterList(voterListId);
- VoterListMemberJpaDao dao = getPersistenceContext().getVoterListMemberDao();
+ VoterListMember member = getMember(memberId);
+ voterList.removeVoterListMember(member);
- VoterListMember result = dao.findById(memberId);
- Preconditions.checkNotNull(result);
+ getPersistenceContext().getVoterListDao().merge(voterList);
- dao.remove(result);
-
getPersistenceContext().commit();
}
Added: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/EntityNotFoundException.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/EntityNotFoundException.java (rev 0)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/EntityNotFoundException.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,55 @@
+package org.chorem.pollen.service.exception;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import org.nuiton.jpa.api.JpaEntity;
+
+/**
+ * When an entity is not found in database.
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class EntityNotFoundException extends Exception {
+
+ private static final long serialVersionUID = -5760536098822762990L;
+
+ protected final Class<? extends JpaEntity> entityType;
+
+ protected final String entityId;
+
+ public EntityNotFoundException(Class<? extends JpaEntity> entityType,
+ String entityId) {
+ this.entityType = entityType;
+ this.entityId = entityId;
+ }
+
+ public Class<? extends JpaEntity> getEntityType() {
+ return entityType;
+ }
+
+ public String getEntityId() {
+ return entityId;
+ }
+}
Property changes on: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/EntityNotFoundException.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Copied: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserEmailAlreadyUsedException.java (from rev 3815, branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exceptions/UserEmailAlreadyUsedException.java)
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserEmailAlreadyUsedException.java (rev 0)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserEmailAlreadyUsedException.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,45 @@
+package org.chorem.pollen.service.exception;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class UserEmailAlreadyUsedException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ protected final String email;
+
+ public UserEmailAlreadyUsedException(String email) {
+ this.email = email;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+}
Added: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidEmailActiviationTokenException.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidEmailActiviationTokenException.java (rev 0)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidEmailActiviationTokenException.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,34 @@
+package org.chorem.pollen.service.exception;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class UserInvalidEmailActiviationTokenException extends Exception {
+ private static final long serialVersionUID = 1L;
+}
Property changes on: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidEmailActiviationTokenException.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Copied: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidPasswordException.java (from rev 3815, branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exceptions/UserInvalidPasswordException.java)
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidPasswordException.java (rev 0)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserInvalidPasswordException.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,34 @@
+package org.chorem.pollen.service.exception;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+/**
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class UserInvalidPasswordException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+}
Copied: branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserLoginAlreadyUsedException.java (from rev 3815, branches/pollen-2.0/pollen-services/src/main/java/org/chorem/pollen/services/exceptions/UserLoginAlreadyUsedException.java)
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserLoginAlreadyUsedException.java (rev 0)
+++ branches/pollen-2.0/pollen-service/src/main/java/org/chorem/pollen/service/exception/UserLoginAlreadyUsedException.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -0,0 +1,45 @@
+package org.chorem.pollen.service.exception;
+
+/*
+ * #%L
+ * Pollen :: Service
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2009 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+/**
+ * TODO
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0
+ */
+public class UserLoginAlreadyUsedException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ protected final String login;
+
+ public UserLoginAlreadyUsedException(String login) {
+ this.login=login;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+}
Modified: branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml
===================================================================
--- branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/main/resources/fixtures.yaml 2013-06-06 16:43:31 UTC (rev 3817)
@@ -20,6 +20,7 @@
&julien !user
id: pollen_user_julien
login: julien
+ password: fake
name: J
email: julien(a)pollen.fake
administrator: true
Modified: branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/AbstractPollenServiceTest.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -23,6 +23,8 @@
* #L%
*/
+import org.chorem.pollen.persistence.JpaEntityIdFactoryIfNotEmpty;
+import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
import org.chorem.pollen.service.config.PollenServiceConfig;
import org.junit.Rule;
import org.nuiton.jpa.junit.JpaEntityManagerRule;
@@ -64,7 +66,10 @@
EntityManager entityManager = getJpaEntityManagerRule().getEntityManager();
- serviceContext.setEntityManager(entityManager);
+ JpaEntityIdFactoryIfNotEmpty idGenerator = new JpaEntityIdFactoryIfNotEmpty();
+ JpaPollenPersistenceContext persistenceContext = new JpaPollenPersistenceContext(idGenerator, entityManager);
+
+ serviceContext.setPersistenceContext(persistenceContext);
}
}
Modified: branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/FakePollenServiceContext.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/FakePollenServiceContext.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/FakePollenServiceContext.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -26,9 +26,6 @@
import com.google.common.base.Preconditions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.chorem.pollen.persistence.JpaEntityIdFactoryIfNotEmpty;
-import org.chorem.pollen.persistence.JpaPollenPersistenceContext;
-import org.chorem.pollen.persistence.PollenPersistenceContext;
import java.util.Date;
@@ -48,15 +45,6 @@
return date;
}
- @Override
- public PollenPersistenceContext getPersistenceContext() {
- if (persistenceContext == null) {
- JpaEntityIdFactoryIfNotEmpty idGenerator = new JpaEntityIdFactoryIfNotEmpty();
- persistenceContext = new JpaPollenPersistenceContext(idGenerator, entityManager);
- }
- return persistenceContext;
- }
-
public void setDate(Date date) {
this.date = date;
}
Modified: branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java
===================================================================
--- branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java 2013-06-05 16:41:46 UTC (rev 3816)
+++ branches/pollen-2.0/pollen-service/src/test/java/org/chorem/pollen/service/UserServiceTest.java 2013-06-06 16:43:31 UTC (rev 3817)
@@ -25,6 +25,11 @@
import org.apache.commons.collections.CollectionUtils;
import org.chorem.pollen.persistence.entity.PollenUser;
+import org.chorem.pollen.service.exception.EntityNotFoundException;
+import org.chorem.pollen.service.exception.UserEmailAlreadyUsedException;
+import org.chorem.pollen.service.exception.UserInvalidEmailActiviationTokenException;
+import org.chorem.pollen.service.exception.UserInvalidPasswordException;
+import org.chorem.pollen.service.exception.UserLoginAlreadyUsedException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -67,11 +72,130 @@
}
@Test
- public void testGetPollenUser() {
+ public void testGetPollenUser() throws EntityNotFoundException {
+ try {
+ service.getUser("pollen_user_tony_" + System.nanoTime());
+
+ } catch (EntityNotFoundException e) {
+ Assert.assertTrue(true);
+ }
+
PollenUser user = service.getUser("pollen_user_tony");
Assert.assertNotNull(user);
Assert.assertEquals(this.user, user);
}
+
+ @Test
+ public void testCreatePollenUser() throws Exception {
+
+ try {
+ service.createUser(user, false);
+ Assert.fail();
+ } catch (IllegalStateException e) {
+ // Should having id
+ Assert.assertTrue(true);
+ }
+
+ PollenUser newUser = new PollenUser();
+ newUser.setLogin("pollen");
+ newUser.setEmail("pollen(a)pollen.org");
+
+ PollenUser savedUser = service.createUser(newUser, true);
+ Assert.assertNotNull(savedUser);
+ Assert.assertNotNull(savedUser.getId());
+
+ PollenUser newUser2 = new PollenUser();
+ newUser2.setLogin("pollen");
+ newUser2.setEmail("pollen(a)pollen.org");
+
+ try {
+ service.createUser(newUser2, true);
+ Assert.fail();
+ } catch (UserLoginAlreadyUsedException e) {
+ Assert.assertTrue(true);
+ }
+
+ newUser2.setLogin("pollen2");
+ try {
+ service.createUser(newUser2, true);
+ Assert.fail();
+ } catch (UserEmailAlreadyUsedException e) {
+ Assert.assertTrue(true);
+ }
+
+ newUser2.setEmail("pollen2(a)pollen.org");
+ PollenUser savedUser2 = service.createUser(newUser2, true);
+ Assert.assertNotNull(savedUser2);
+ Assert.assertNotNull(savedUser2.getId());
+ }
+
+ @Test
+ public void testEditUser() throws EntityNotFoundException, UserInvalidPasswordException, UserEmailAlreadyUsedException {
+
+ PollenUser user = service.getUser("pollen_user_tony");
+
+ Assert.assertNotNull(user);
+ Assert.assertNull(user.getEmailActivationToken());
+
+ serviceContext.getPersistenceContext().detach(user);
+
+ String originalLogin = user.getLogin();
+
+ user.setLogin("yetanotherlogin");
+ String email = "tony(a)pollen.org";
+ user.setEmail(email);
+
+ try {
+ service.editUser(user);
+ Assert.fail();
+ } catch (UserInvalidPasswordException e) {
+ Assert.assertTrue(true);
+ }
+
+ user.setPassword("fake");
+ PollenUser savedUser = service.editUser(user);
+ Assert.assertNotNull(savedUser);
+ Assert.assertEquals(originalLogin, savedUser.getLogin());
+ Assert.assertEquals(email, savedUser.getEmail());
+ Assert.assertNotNull(savedUser.getEmailActivationToken());
+ }
+
+ @Test
+ public void testValidateEmail() throws EntityNotFoundException, UserInvalidPasswordException, UserEmailAlreadyUsedException, UserInvalidEmailActiviationTokenException {
+
+ PollenUser user = service.getUser("pollen_user_tony");
+ Assert.assertNotNull(user);
+ Assert.assertNull(user.getEmailActivationToken());
+
+ serviceContext.getPersistenceContext().detach(user);
+
+ String email = "tony(a)pollen.org";
+ user.setEmail(email);
+ user.setPassword("fake");
+
+ PollenUser savedUser = service.editUser(user);
+ Assert.assertNotNull(savedUser);
+
+ Assert.assertEquals(email, savedUser.getEmail());
+ Assert.assertNotNull(savedUser.getEmailActivationToken());
+
+ try {
+ service.validateUserEmail(user.getId(), "fakeToken");
+ Assert.fail();
+ } catch (UserInvalidEmailActiviationTokenException e) {
+ Assert.assertTrue(true);
+ }
+
+ Assert.assertFalse(savedUser.isEmailActivated());
+
+ service.validateUserEmail(user.getId(), savedUser.getEmailActivationToken());
+
+
+
+ PollenUser reloadedUser = service.getUser("pollen_user_tony");
+ Assert.assertTrue(reloadedUser.isEmailActivated());
+
+ }
}
1
0