Copy disabled (too large)
Download .txt
Showing preview only (14,137K chars total). Download the full file to get everything.
Repository: ippontech/tatami
Branch: master
Commit: 90fdbfc474dc
Files: 1921
Total size: 12.9 MB
Directory structure:
gitextract_2urwtjut/
├── .gitignore
├── CONTRIBUTING.md
├── README.md
├── etc/
│ └── installation/
│ └── ubuntu/
│ ├── files/
│ │ └── maven/
│ │ └── settings.xml
│ ├── install.sh
│ ├── uninstall.sh
│ └── update.sh
├── jenkinsScripts/
│ ├── insertGoogleAuthKeys.sh
│ ├── restoreDatabase.sh
│ ├── saveDatabase.sh
│ ├── startTatami.sh
│ └── stopTatami.sh
├── mobile/
│ ├── .bowerrc
│ ├── .editorconfig
│ ├── .gitignore
│ ├── README.md
│ ├── bower.json
│ ├── config.xml
│ ├── gulpfile.js
│ ├── hooks/
│ │ ├── README.md
│ │ └── after_prepare/
│ │ └── 010_add_platform_class.js
│ ├── ionic.project
│ ├── karma.ci.conf.js
│ ├── package.json
│ ├── pom.xml
│ ├── resources/
│ │ ├── icon.psd
│ │ └── splash.psd
│ ├── scss/
│ │ └── ionic.app.scss
│ └── www/
│ ├── app/
│ │ ├── components/
│ │ │ ├── follow/
│ │ │ │ ├── follow.html
│ │ │ │ ├── follow.js
│ │ │ │ ├── follower/
│ │ │ │ │ ├── follower.controller.js
│ │ │ │ │ ├── follower.html
│ │ │ │ │ └── follower.js
│ │ │ │ ├── following/
│ │ │ │ │ ├── following.controller.js
│ │ │ │ │ ├── following.html
│ │ │ │ │ └── following.js
│ │ │ │ └── suggested/
│ │ │ │ ├── suggested.controller.js
│ │ │ │ ├── suggested.html
│ │ │ │ └── suggested.js
│ │ │ ├── home/
│ │ │ │ ├── favorites/
│ │ │ │ │ ├── favorites.controller.js
│ │ │ │ │ ├── favorites.html
│ │ │ │ │ └── favorites.js
│ │ │ │ ├── home.html
│ │ │ │ ├── home.js
│ │ │ │ ├── mentions/
│ │ │ │ │ ├── mentions.controller.js
│ │ │ │ │ ├── mentions.html
│ │ │ │ │ └── mentions.js
│ │ │ │ ├── more/
│ │ │ │ │ ├── all_users/
│ │ │ │ │ │ ├── all.users.controller.js
│ │ │ │ │ │ ├── all.users.html
│ │ │ │ │ │ └── all.users.js
│ │ │ │ │ ├── blocked_users/
│ │ │ │ │ │ ├── blocked.users.controller.js
│ │ │ │ │ │ ├── blocked.users.html
│ │ │ │ │ │ └── blocked.users.js
│ │ │ │ │ ├── company/
│ │ │ │ │ │ ├── company-timeline.html
│ │ │ │ │ │ ├── company.timeline.controller.js
│ │ │ │ │ │ └── company.timeline.js
│ │ │ │ │ ├── more.controller.js
│ │ │ │ │ ├── more.html
│ │ │ │ │ ├── more.js
│ │ │ │ │ ├── reportedStatus/
│ │ │ │ │ │ ├── reportedStatus.controller.js
│ │ │ │ │ │ ├── reportedStatus.html
│ │ │ │ │ │ └── reportedStatus.js
│ │ │ │ │ └── settings/
│ │ │ │ │ ├── settings.controller.js
│ │ │ │ │ ├── settings.html
│ │ │ │ │ └── settings.js
│ │ │ │ └── timeline/
│ │ │ │ ├── timeline.controller.js
│ │ │ │ ├── timeline.html
│ │ │ │ └── timeline.js
│ │ │ ├── login/
│ │ │ │ ├── login.controller.js
│ │ │ │ ├── login.html
│ │ │ │ ├── login.js
│ │ │ │ └── server/
│ │ │ │ ├── server.controller.js
│ │ │ │ ├── server.html
│ │ │ │ └── server.js
│ │ │ └── post/
│ │ │ ├── post.controller.js
│ │ │ ├── post.html
│ │ │ ├── post.js
│ │ │ └── postbar.directive.js
│ │ ├── shared/
│ │ │ ├── config/
│ │ │ │ ├── marked.config.js
│ │ │ │ ├── marked.filter.js
│ │ │ │ └── tatami.marked.js
│ │ │ ├── interceptor/
│ │ │ │ └── auth.interceptor.js
│ │ │ ├── providers/
│ │ │ │ ├── provider.js
│ │ │ │ └── tatami.state.provider.js
│ │ │ ├── services/
│ │ │ │ ├── HomeService.js
│ │ │ │ ├── ProfileService.js
│ │ │ │ ├── StatusService.js
│ │ │ │ ├── UserService.js
│ │ │ │ ├── account.service.js
│ │ │ │ ├── block.service.js
│ │ │ │ ├── localStorage.service.js
│ │ │ │ ├── path.service.js
│ │ │ │ ├── report.service.js
│ │ │ │ ├── service.js
│ │ │ │ ├── tag.service.js
│ │ │ │ └── toast.service.js
│ │ │ ├── state/
│ │ │ │ ├── conversation/
│ │ │ │ │ ├── conversation.controller.js
│ │ │ │ │ └── conversation.html
│ │ │ │ ├── profile/
│ │ │ │ │ ├── profile.controller.js
│ │ │ │ │ ├── profile.html
│ │ │ │ │ └── userOptionsMenu.html
│ │ │ │ └── tag/
│ │ │ │ ├── tag.controller.js
│ │ │ │ └── tag.html
│ │ │ ├── status/
│ │ │ │ ├── blockUserMenu.html
│ │ │ │ ├── list/
│ │ │ │ │ ├── status-list.html
│ │ │ │ │ └── status.list.directive.js
│ │ │ │ ├── status.directive.js
│ │ │ │ ├── status.html
│ │ │ │ └── status.refresher.service.js
│ │ │ └── user/
│ │ │ ├── user-detail.html
│ │ │ ├── user.detail.directive.js
│ │ │ ├── user.directive.js
│ │ │ ├── user.html
│ │ │ ├── user.refresher.service.js
│ │ │ ├── users.directive.js
│ │ │ └── users.html
│ │ ├── tatami.controller.js
│ │ ├── tatami.endpoint.js
│ │ ├── tatami.html
│ │ └── tatamiApp.js
│ ├── css/
│ │ ├── ionic.app.css
│ │ └── style.css
│ ├── i18n/
│ │ ├── en/
│ │ │ ├── conversation.json
│ │ │ ├── follow.json
│ │ │ ├── home.json
│ │ │ ├── login.json
│ │ │ ├── more.json
│ │ │ ├── post.json
│ │ │ ├── server.json
│ │ │ ├── status.json
│ │ │ └── user.json
│ │ └── fr/
│ │ ├── conversation.json
│ │ ├── follow.json
│ │ ├── home.json
│ │ ├── login.json
│ │ ├── more.json
│ │ ├── post.json
│ │ ├── server.json
│ │ ├── status.json
│ │ └── user.json
│ ├── index.html
│ └── test/
│ └── javascript/
│ └── components/
│ └── profile/
│ └── profile.controller.spec.js
├── pom.xml
├── scripts/
│ └── insertBuildVersion.sh
├── services/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── fr/
│ │ │ │ └── ippon/
│ │ │ │ └── tatami/
│ │ │ │ ├── config/
│ │ │ │ │ ├── ApplicationConfiguration.java
│ │ │ │ │ ├── AsyncConfiguration.java
│ │ │ │ │ ├── CacheConfiguration.java
│ │ │ │ │ ├── CassandraConfiguration.java
│ │ │ │ │ ├── ColumnFamilyKeys.java
│ │ │ │ │ ├── Constants.java
│ │ │ │ │ ├── DispatcherServletConfig.java
│ │ │ │ │ ├── GroupRoles.java
│ │ │ │ │ ├── MailConfiguration.java
│ │ │ │ │ ├── MetricsConfiguration.java
│ │ │ │ │ ├── SearchConfiguration.java
│ │ │ │ │ └── metrics/
│ │ │ │ │ ├── CassandraHealthCheck.java
│ │ │ │ │ └── JavaMailHealthCheck.java
│ │ │ │ ├── domain/
│ │ │ │ │ ├── Attachment.java
│ │ │ │ │ ├── Avatar.java
│ │ │ │ │ ├── DigestType.java
│ │ │ │ │ ├── Domain.java
│ │ │ │ │ ├── DomainConfiguration.java
│ │ │ │ │ ├── Group.java
│ │ │ │ │ ├── User.java
│ │ │ │ │ ├── UserStatusStat.java
│ │ │ │ │ ├── status/
│ │ │ │ │ │ ├── AbstractStatus.java
│ │ │ │ │ │ ├── Announcement.java
│ │ │ │ │ │ ├── MentionFriend.java
│ │ │ │ │ │ ├── MentionShare.java
│ │ │ │ │ │ ├── Share.java
│ │ │ │ │ │ ├── Status.java
│ │ │ │ │ │ ├── StatusDetails.java
│ │ │ │ │ │ └── StatusType.java
│ │ │ │ │ └── validation/
│ │ │ │ │ ├── ContraintsAttachmentCreation.java
│ │ │ │ │ └── ContraintsUserCreation.java
│ │ │ │ ├── repository/
│ │ │ │ │ ├── AppleDeviceRepository.java
│ │ │ │ │ ├── AppleDeviceUserRepository.java
│ │ │ │ │ ├── AttachmentRepository.java
│ │ │ │ │ ├── AvatarRepository.java
│ │ │ │ │ ├── BlockRepository.java
│ │ │ │ │ ├── CounterRepository.java
│ │ │ │ │ ├── DaylineRepository.java
│ │ │ │ │ ├── DiscussionRepository.java
│ │ │ │ │ ├── DomainConfigurationRepository.java
│ │ │ │ │ ├── DomainRepository.java
│ │ │ │ │ ├── DomainlineRepository.java
│ │ │ │ │ ├── FavoritelineRepository.java
│ │ │ │ │ ├── FollowerRepository.java
│ │ │ │ │ ├── FriendRepository.java
│ │ │ │ │ ├── GroupCounterRepository.java
│ │ │ │ │ ├── GroupDetailsRepository.java
│ │ │ │ │ ├── GroupMembersRepository.java
│ │ │ │ │ ├── GroupRepository.java
│ │ │ │ │ ├── GrouplineRepository.java
│ │ │ │ │ ├── IdempotentRepository.java
│ │ │ │ │ ├── MailDigestRepository.java
│ │ │ │ │ ├── MentionlineRepository.java
│ │ │ │ │ ├── RegistrationRepository.java
│ │ │ │ │ ├── ResolvedReportRepository.java
│ │ │ │ │ ├── RssUidRepository.java
│ │ │ │ │ ├── SharesRepository.java
│ │ │ │ │ ├── StatusAttachmentRepository.java
│ │ │ │ │ ├── StatusReportRepository.java
│ │ │ │ │ ├── StatusRepository.java
│ │ │ │ │ ├── TagCounterRepository.java
│ │ │ │ │ ├── TagFollowerRepository.java
│ │ │ │ │ ├── TaglineRepository.java
│ │ │ │ │ ├── TimelineRepository.java
│ │ │ │ │ ├── TrendRepository.java
│ │ │ │ │ ├── UserAttachmentRepository.java
│ │ │ │ │ ├── UserGroupRepository.java
│ │ │ │ │ ├── UserRepository.java
│ │ │ │ │ ├── UserTagRepository.java
│ │ │ │ │ ├── UserTrendRepository.java
│ │ │ │ │ ├── UserlineRepository.java
│ │ │ │ │ └── cassandra/
│ │ │ │ │ ├── AbstractCassandraFollowerRepository.java
│ │ │ │ │ ├── AbstractCassandraFriendRepository.java
│ │ │ │ │ ├── AbstractCassandraLineRepository.java
│ │ │ │ │ ├── CassandraAppleDeviceRepository.java
│ │ │ │ │ ├── CassandraAppleDeviceUserRepository.java
│ │ │ │ │ ├── CassandraAttachmentRepository.java
│ │ │ │ │ ├── CassandraAvatarRepository.java
│ │ │ │ │ ├── CassandraBlockRepository.java
│ │ │ │ │ ├── CassandraCounterRepository.java
│ │ │ │ │ ├── CassandraDaylineRepository.java
│ │ │ │ │ ├── CassandraDiscussionRepository.java
│ │ │ │ │ ├── CassandraDomainConfigurationRepository.java
│ │ │ │ │ ├── CassandraDomainRepository.java
│ │ │ │ │ ├── CassandraDomainlineRepository.java
│ │ │ │ │ ├── CassandraFavoritelineRepository.java
│ │ │ │ │ ├── CassandraFollowerRepository.java
│ │ │ │ │ ├── CassandraFriendRepository.java
│ │ │ │ │ ├── CassandraGroupCounterRepository.java
│ │ │ │ │ ├── CassandraGroupDetailsRepository.java
│ │ │ │ │ ├── CassandraGroupMembersRepository.java
│ │ │ │ │ ├── CassandraGroupRepository.java
│ │ │ │ │ ├── CassandraGrouplineRepository.java
│ │ │ │ │ ├── CassandraIdempotentRepository.java
│ │ │ │ │ ├── CassandraMailDigestRepository.java
│ │ │ │ │ ├── CassandraMentionlineRepository.java
│ │ │ │ │ ├── CassandraRegistrationRepository.java
│ │ │ │ │ ├── CassandraRssUidRepository.java
│ │ │ │ │ ├── CassandraSharesRepository.java
│ │ │ │ │ ├── CassandraStatusAttachmentRepository.java
│ │ │ │ │ ├── CassandraStatusReportRepository.java
│ │ │ │ │ ├── CassandraStatusRepository.java
│ │ │ │ │ ├── CassandraTagCounterRepository.java
│ │ │ │ │ ├── CassandraTagFollowerRepository.java
│ │ │ │ │ ├── CassandraTaglineRepository.java
│ │ │ │ │ ├── CassandraTimelineRepository.java
│ │ │ │ │ ├── CassandraTrendRepository.java
│ │ │ │ │ ├── CassandraUserAttachmentRepository.java
│ │ │ │ │ ├── CassandraUserGroupRepository.java
│ │ │ │ │ ├── CassandraUserRepository.java
│ │ │ │ │ ├── CassandraUserTagRepository.java
│ │ │ │ │ ├── CassandraUserTrendRepository.java
│ │ │ │ │ └── CassandraUserlineRepository.java
│ │ │ │ ├── security/
│ │ │ │ │ ├── AjaxAuthenticationFailureHandler.java
│ │ │ │ │ ├── AjaxAuthenticationSuccessHandler.java
│ │ │ │ │ ├── AjaxLogoutSuccessHandler.java
│ │ │ │ │ ├── AuthenticationService.java
│ │ │ │ │ ├── DomainViolationException.java
│ │ │ │ │ ├── GoogleApiAuthenticationProvider.java
│ │ │ │ │ ├── GoogleAuthenticationProvider.java
│ │ │ │ │ ├── GoogleAuthenticationToken.java
│ │ │ │ │ ├── GoogleAutoRegisteringUserDetailsService.java
│ │ │ │ │ ├── Http401UnauthorizedEntryPoint.java
│ │ │ │ │ ├── OpenIdAutoRegisteringUserDetailsService.java
│ │ │ │ │ ├── TatamiAuthenticationSuccessHandler.java
│ │ │ │ │ ├── TatamiLdapAuthenticationProvider.java
│ │ │ │ │ ├── TatamiUserDetailsService.java
│ │ │ │ │ └── xauth/
│ │ │ │ │ ├── Token.java
│ │ │ │ │ ├── TokenProvider.java
│ │ │ │ │ └── XAuthTokenFilter.java
│ │ │ │ ├── service/
│ │ │ │ │ ├── AdminService.java
│ │ │ │ │ ├── ApplePushService.java
│ │ │ │ │ ├── AtmosphereService.java
│ │ │ │ │ ├── AttachmentService.java
│ │ │ │ │ ├── AvatarService.java
│ │ │ │ │ ├── BlockService.java
│ │ │ │ │ ├── CounterService.java
│ │ │ │ │ ├── FriendshipService.java
│ │ │ │ │ ├── GroupService.java
│ │ │ │ │ ├── MailDigestService.java
│ │ │ │ │ ├── MailService.java
│ │ │ │ │ ├── MentionService.java
│ │ │ │ │ ├── SearchService.java
│ │ │ │ │ ├── StatsService.java
│ │ │ │ │ ├── StatusUpdateService.java
│ │ │ │ │ ├── SuggestionService.java
│ │ │ │ │ ├── TagMembershipService.java
│ │ │ │ │ ├── TimelineService.java
│ │ │ │ │ ├── TrendService.java
│ │ │ │ │ ├── UserService.java
│ │ │ │ │ ├── dto/
│ │ │ │ │ │ ├── StatusDTO.java
│ │ │ │ │ │ ├── UserDTO.java
│ │ │ │ │ │ └── UserGroupDTO.java
│ │ │ │ │ ├── elasticsearch/
│ │ │ │ │ │ ├── ElasticsearchEngine.java
│ │ │ │ │ │ ├── ElasticsearchSearchService.java
│ │ │ │ │ │ ├── EmbeddedElasticsearchEngine.java
│ │ │ │ │ │ └── RemoteElasticsearchEngine.java
│ │ │ │ │ ├── exception/
│ │ │ │ │ │ ├── ArchivedGroupException.java
│ │ │ │ │ │ ├── ReplyStatusException.java
│ │ │ │ │ │ └── StorageSizeException.java
│ │ │ │ │ └── util/
│ │ │ │ │ ├── AnalysisUtil.java
│ │ │ │ │ ├── DomainUtil.java
│ │ │ │ │ ├── RandomUtil.java
│ │ │ │ │ └── ValueComparator.java
│ │ │ │ └── web/
│ │ │ │ ├── atmosphere/
│ │ │ │ │ └── TatamiNotification.java
│ │ │ │ ├── rest/
│ │ │ │ │ └── dto/
│ │ │ │ │ ├── ActionStatus.java
│ │ │ │ │ ├── EmailAndUsername.java
│ │ │ │ │ ├── Preferences.java
│ │ │ │ │ ├── Reply.java
│ │ │ │ │ ├── SearchResults.java
│ │ │ │ │ ├── Tag.java
│ │ │ │ │ ├── Trend.java
│ │ │ │ │ ├── UserActionStatus.java
│ │ │ │ │ └── UserPassword.java
│ │ │ │ └── syndic/
│ │ │ │ ├── SyndicTimelineController.java
│ │ │ │ ├── SyndicView.java
│ │ │ │ └── UnknownRssChannelException.java
│ │ │ └── me/
│ │ │ └── prettyprint/
│ │ │ └── hom/
│ │ │ └── CassandraPersistenceProvider.java
│ │ ├── resources/
│ │ │ ├── META-INF/
│ │ │ │ ├── elasticsearch/
│ │ │ │ │ ├── elasticsearch-embedded.yml
│ │ │ │ │ ├── index/
│ │ │ │ │ │ ├── group.json
│ │ │ │ │ │ ├── status.json
│ │ │ │ │ │ └── user.json
│ │ │ │ │ └── logging.yml
│ │ │ │ ├── spring/
│ │ │ │ │ ├── applicationContext-metrics.xml
│ │ │ │ │ └── applicationContext-security.xml
│ │ │ │ └── tatami/
│ │ │ │ ├── customization.properties
│ │ │ │ ├── mails/
│ │ │ │ │ ├── common
│ │ │ │ │ ├── dailyDigestEmail
│ │ │ │ │ ├── deactivatedUserEmail
│ │ │ │ │ ├── invitationMessageEmail
│ │ │ │ │ ├── lostPasswordEmail
│ │ │ │ │ ├── messages/
│ │ │ │ │ │ ├── messages_en.properties
│ │ │ │ │ │ └── messages_fr.properties
│ │ │ │ │ ├── passwordReinitializedEmail
│ │ │ │ │ ├── registrationEmail
│ │ │ │ │ ├── reportedStatusEmail
│ │ │ │ │ ├── userMentionEmail
│ │ │ │ │ ├── userPrivateMessageEmail
│ │ │ │ │ ├── validationEmail
│ │ │ │ │ └── weeklyDigestEmail
│ │ │ │ └── tatami.properties
│ │ │ ├── ehcache.xml
│ │ │ └── logback.xml
│ │ └── webapp/
│ │ └── app/
│ │ └── shared/
│ │ └── services/
│ │ ├── AuthenticationService.js
│ │ ├── GeolocService.js
│ │ ├── GroupService.js
│ │ ├── HomeService.js
│ │ ├── ProfileService.js
│ │ ├── SearchService.js
│ │ ├── StatusService.js
│ │ ├── TagService.js
│ │ ├── TopPostersService.js
│ │ ├── UserService.js
│ │ └── UserSession.js
│ └── test/
│ ├── java/
│ │ └── fr/
│ │ └── ippon/
│ │ └── tatami/
│ │ ├── AbstractCassandraTatamiTest.java
│ │ ├── repository/
│ │ │ ├── MailDigestRepositoryTest.java
│ │ │ ├── StatusReportRepositoryTest.java
│ │ │ ├── StatusRepositoryTest.java
│ │ │ ├── TagFollowerRepositoryTest.java
│ │ │ └── UserRepositoryTest.java
│ │ ├── service/
│ │ │ ├── FriendshipServiceTest.java
│ │ │ ├── GroupServiceTest.java
│ │ │ ├── MailDigestServiceTest.java
│ │ │ ├── StatsServiceTest.java
│ │ │ ├── StatusDeletionTest.java
│ │ │ ├── StatusUpdateServiceTest.java
│ │ │ ├── TagMembershipServiceTest.java
│ │ │ ├── TimelineServiceTest.java
│ │ │ ├── TrendServiceTest.java
│ │ │ ├── UserServiceTest.java
│ │ │ └── elasticsearch/
│ │ │ └── ElasticsearchSearchServiceTest.java
│ │ ├── test/
│ │ │ ├── MockUtils.java
│ │ │ └── application/
│ │ │ ├── ApplicationTestConfiguration.java
│ │ │ └── WebApplicationTestConfiguration.java
│ │ └── web/
│ │ └── syndic/
│ │ └── SyndicTimelineControllerTest.java
│ ├── jmeter/
│ │ ├── tatami-create-users.jmx
│ │ └── tatami-stress-test.jmx
│ └── resources/
│ ├── dataset/
│ │ └── dataset.json
│ ├── logback.xml
│ └── tatami/
│ └── tatami-test.properties
├── src/
│ ├── integration/
│ │ ├── java/
│ │ │ ├── fr/
│ │ │ │ └── ippon/
│ │ │ │ └── tatami/
│ │ │ │ ├── test/
│ │ │ │ │ └── support/
│ │ │ │ │ ├── LdapTestServer.java
│ │ │ │ │ └── LdapTestServerJunitLauncher.java
│ │ │ │ └── uitest/
│ │ │ │ ├── AuthenticationSpec.groovy
│ │ │ │ ├── NewRegistrationSpec.groovy
│ │ │ │ └── support/
│ │ │ │ ├── AccountUtils.groovy
│ │ │ │ ├── CassandraAccessUtils.groovy
│ │ │ │ ├── RegistrationUtils.groovy
│ │ │ │ └── TatamiBaseGebSpec.groovy
│ │ │ └── pages/
│ │ │ ├── EmailVerifiedPage.groovy
│ │ │ ├── HomePage.groovy
│ │ │ ├── LoginPage.groovy
│ │ │ ├── TatamiBasePage.groovy
│ │ │ └── google/
│ │ │ ├── GoogleAuthenticationPage.groovy
│ │ │ └── GoogleOpenIdPage.groovy
│ │ └── resources/
│ │ ├── GebConfig.groovy
│ │ └── fr/
│ │ └── ippon/
│ │ └── tatami/
│ │ └── test/
│ │ └── support/
│ │ └── ipponTestLdapExport.ldif
│ └── main/
│ └── cql/
│ ├── install.cql
│ └── upgrade/
│ ├── upgrade_from_1.0.27_to_2.0.0.cql
│ ├── upgrade_from_2.0.0_to_2.1.0.cql
│ ├── upgrade_from_2.1.3_to_2.2.0.cql
│ └── upgrade_from_3.0.26_to_3.0.27.cql
├── tatamibot/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── fr/
│ │ │ └── ippon/
│ │ │ └── tatami/
│ │ │ ├── bot/
│ │ │ │ ├── Tatamibot.java
│ │ │ │ ├── config/
│ │ │ │ │ └── TatamibotConfiguration.java
│ │ │ │ ├── processor/
│ │ │ │ │ ├── LastUpdateDateTatamibotConfigurationUpdater.java
│ │ │ │ │ └── TatamiStatusProcessor.java
│ │ │ │ └── route/
│ │ │ │ ├── CommonRouteBuilder.java
│ │ │ │ ├── GitHubRouteBuilder.java
│ │ │ │ ├── RssRouteBuilder.java
│ │ │ │ ├── SourceRouteBuilderBase.java
│ │ │ │ └── TwitterRouteBuilder.java
│ │ │ ├── repository/
│ │ │ │ ├── TatamibotConfigurationRepository.java
│ │ │ │ └── cassandra/
│ │ │ │ └── CassandraTatamibotConfigurationRepository.java
│ │ │ └── web/
│ │ │ └── bot/
│ │ │ └── TatamibotController.java
│ │ └── resources/
│ │ └── META-INF/
│ │ └── spring/
│ │ └── applicationContext-tatamibot.xml
│ └── test/
│ ├── java/
│ │ └── fr/
│ │ └── ippon/
│ │ └── tatami/
│ │ ├── bot/
│ │ │ ├── TatamibotTest.java
│ │ │ └── route/
│ │ │ ├── CommonRouteBuilderTest.java
│ │ │ ├── RssRouteBuilderCamelTest.java
│ │ │ ├── RssRouteBuilderUnitTest.java
│ │ │ ├── SourceRouteBuilderBaseCamelTest.java
│ │ │ └── TwitterRouteBuilderCamelTest.java
│ │ └── test/
│ │ └── MockUtils.java
│ └── resources/
│ └── fr/
│ └── ippon/
│ └── tatami/
│ └── bot/
│ └── route/
│ └── rss.xml
└── web/
├── gruntfile.js
├── karma.ci.conf.js
├── karma.conf.js
├── package.json
├── pom.xml
└── src/
├── main/
│ ├── java/
│ │ └── fr/
│ │ └── ippon/
│ │ └── tatami/
│ │ └── web/
│ │ ├── atmosphere/
│ │ │ └── RealtimeService.java
│ │ ├── controller/
│ │ │ ├── ErrorController.java
│ │ │ ├── HomeController.java
│ │ │ └── Pac4JSecurityCheckController.java
│ │ ├── fileupload/
│ │ │ ├── FileController.java
│ │ │ ├── Message.java
│ │ │ ├── StatusResponse.java
│ │ │ └── UploadedFile.java
│ │ ├── filter/
│ │ │ ├── IeRefreshWrapper.java
│ │ │ └── TatamiGzipFilter.java
│ │ ├── init/
│ │ │ └── WebConfigurer.java
│ │ └── rest/
│ │ ├── AccountController.java
│ │ ├── AttachmentController.java
│ │ ├── BlockController.java
│ │ ├── CompanyWallController.java
│ │ ├── FavoritesController.java
│ │ ├── FriendshipController.java
│ │ ├── GroupController.java
│ │ ├── MentionsController.java
│ │ ├── SearchController.java
│ │ ├── StatsController.java
│ │ ├── TagController.java
│ │ ├── TimelineController.java
│ │ ├── TrendController.java
│ │ ├── UserController.java
│ │ └── UserXAuthController.java
│ └── webapp/
│ ├── .bowerrc
│ ├── WEB-INF/
│ │ ├── messages/
│ │ │ ├── messages_en.properties
│ │ │ └── messages_fr.properties
│ │ ├── pages/
│ │ │ ├── errors/
│ │ │ │ ├── 404.jsp
│ │ │ │ ├── 500.jsp
│ │ │ │ └── file_not_found.jsp
│ │ │ ├── home.jsp
│ │ │ ├── includes/
│ │ │ │ ├── footer.jsp
│ │ │ │ ├── header.jsp
│ │ │ │ ├── help-home.jsp
│ │ │ │ ├── navigation-admin.jsp
│ │ │ │ ├── template-search-engine.jsp
│ │ │ │ ├── templates-admin.jsp
│ │ │ │ ├── templates.jsp
│ │ │ │ ├── topavatar.jsp
│ │ │ │ └── topmenu.jsp
│ │ │ └── login.jsp
│ │ └── web.xml
│ ├── app/
│ │ ├── TatamiApp.js
│ │ ├── components/
│ │ │ ├── about/
│ │ │ │ ├── AboutModule.js
│ │ │ │ ├── AboutView.html
│ │ │ │ ├── license/
│ │ │ │ │ ├── LicenseController.js
│ │ │ │ │ └── LicenseView.html
│ │ │ │ ├── presentation/
│ │ │ │ │ └── PresentationView.html
│ │ │ │ └── tos/
│ │ │ │ └── ToSView.html
│ │ │ ├── account/
│ │ │ │ ├── AccountController.js
│ │ │ │ ├── AccountModule.js
│ │ │ │ ├── AccountView.html
│ │ │ │ ├── FormController.js
│ │ │ │ ├── FormView.html
│ │ │ │ ├── files/
│ │ │ │ │ ├── FilesController.js
│ │ │ │ │ ├── FilesModule.js
│ │ │ │ │ ├── FilesService.js
│ │ │ │ │ └── FilesView.html
│ │ │ │ ├── groups/
│ │ │ │ │ ├── GroupsController.js
│ │ │ │ │ ├── GroupsModule.js
│ │ │ │ │ ├── GroupsView.html
│ │ │ │ │ ├── creation/
│ │ │ │ │ │ ├── GroupsCreateController.js
│ │ │ │ │ │ └── GroupsCreateView.html
│ │ │ │ │ ├── list/
│ │ │ │ │ │ ├── GroupListController.js
│ │ │ │ │ │ └── GroupsListView.html
│ │ │ │ │ └── manage/
│ │ │ │ │ ├── GroupsManageController.js
│ │ │ │ │ └── GroupsManageView.html
│ │ │ │ ├── password/
│ │ │ │ │ ├── PasswordController.js
│ │ │ │ │ ├── PasswordModule.js
│ │ │ │ │ ├── PasswordService.js
│ │ │ │ │ └── PasswordView.html
│ │ │ │ ├── preferences/
│ │ │ │ │ ├── PreferencesController.js
│ │ │ │ │ ├── PreferencesModule.js
│ │ │ │ │ ├── PreferencesService.js
│ │ │ │ │ └── PreferencesView.html
│ │ │ │ ├── profile/
│ │ │ │ │ ├── ProfileController.js
│ │ │ │ │ ├── ProfileModule.js
│ │ │ │ │ └── ProfileView.html
│ │ │ │ ├── tags/
│ │ │ │ │ ├── TagsController.js
│ │ │ │ │ ├── TagsModule.js
│ │ │ │ │ └── TagsView.html
│ │ │ │ ├── topPosters/
│ │ │ │ │ ├── TopPostersController.js
│ │ │ │ │ ├── TopPostersModule.js
│ │ │ │ │ └── TopPostersView.html
│ │ │ │ └── users/
│ │ │ │ ├── UsersController.js
│ │ │ │ ├── UsersModule.js
│ │ │ │ ├── UsersView.html
│ │ │ │ └── directives/
│ │ │ │ ├── UserAccountController.js
│ │ │ │ ├── UserAccountDirective.js
│ │ │ │ └── UserAccountView.html
│ │ │ ├── admin/
│ │ │ │ ├── AdminController.js
│ │ │ │ ├── AdminModule.js
│ │ │ │ ├── AdminService.js
│ │ │ │ └── AdminView.html
│ │ │ ├── home/
│ │ │ │ ├── HomeModule.js
│ │ │ │ ├── HomeView.html
│ │ │ │ ├── group/
│ │ │ │ │ ├── GroupHeaderController.js
│ │ │ │ │ └── GroupHeaderView.html
│ │ │ │ ├── profile/
│ │ │ │ │ ├── ProfileHeaderController.js
│ │ │ │ │ └── ProfileHeaderView.html
│ │ │ │ ├── search/
│ │ │ │ │ ├── SearchHeaderController.js
│ │ │ │ │ └── SearchHeaderView.html
│ │ │ │ ├── status/
│ │ │ │ │ ├── StatusController.js
│ │ │ │ │ └── StatusView.html
│ │ │ │ ├── tag/
│ │ │ │ │ ├── TagHeaderController.js
│ │ │ │ │ └── TagHeaderView.html
│ │ │ │ ├── timeline/
│ │ │ │ │ └── TimelineHeaderView.html
│ │ │ │ └── welcome/
│ │ │ │ ├── WelcomeController.js
│ │ │ │ └── WelcomeView.html
│ │ │ └── login/
│ │ │ ├── LoginController.js
│ │ │ ├── LoginModule.js
│ │ │ ├── LoginView.html
│ │ │ ├── RegistrationService.js
│ │ │ ├── email/
│ │ │ │ ├── EmailRegistration.html
│ │ │ │ └── EmailRegistrationController.js
│ │ │ ├── google/
│ │ │ │ ├── GoogleLoginController.js
│ │ │ │ └── GoogleLoginView.html
│ │ │ ├── manual/
│ │ │ │ ├── ManualLoginController.js
│ │ │ │ └── ManualLoginView.html
│ │ │ ├── recoverPassword/
│ │ │ │ ├── RecoverPasswordController.js
│ │ │ │ └── RecoverPasswordView.html
│ │ │ └── register/
│ │ │ ├── RegisterController.js
│ │ │ └── RegisterView.html
│ │ └── shared/
│ │ ├── configs/
│ │ │ ├── MarkedConfig.js
│ │ │ ├── MomentConfig.js
│ │ │ └── TranslateConfig.js
│ │ ├── error/
│ │ │ ├── 404View.html
│ │ │ └── 500View.html
│ │ ├── filters/
│ │ │ ├── EmoticonFilter.js
│ │ │ ├── MarkdownFilter.js
│ │ │ └── PlaceholderFilter.js
│ │ ├── footer/
│ │ │ ├── FooterController.js
│ │ │ ├── FooterModule.js
│ │ │ └── FooterView.html
│ │ ├── lists/
│ │ │ ├── status/
│ │ │ │ ├── withContext/
│ │ │ │ │ ├── StatusListContextController.js
│ │ │ │ │ └── StatusListContextView.html
│ │ │ │ └── withoutContext/
│ │ │ │ ├── StatusListController.js
│ │ │ │ └── StatusListView.html
│ │ │ └── user/
│ │ │ ├── UserListController.js
│ │ │ └── UserListView.html
│ │ ├── services/
│ │ │ ├── AuthenticationService.js
│ │ │ ├── GeolocService.js
│ │ │ ├── GroupService.js
│ │ │ ├── HomeService.js
│ │ │ ├── ProfileService.js
│ │ │ ├── SearchService.js
│ │ │ ├── StatusService.js
│ │ │ ├── TagService.js
│ │ │ ├── TopPostersService.js
│ │ │ ├── UserService.js
│ │ │ └── UserSession.js
│ │ ├── sidebars/
│ │ │ ├── home/
│ │ │ │ ├── HomeSidebarController.js
│ │ │ │ ├── HomeSidebarModule.js
│ │ │ │ └── HomeSidebarView.html
│ │ │ └── profile/
│ │ │ ├── ProfileSidebarController.js
│ │ │ ├── ProfileSidebarModule.js
│ │ │ └── ProfileSidebarView.html
│ │ └── topMenu/
│ │ ├── SearchView.html
│ │ ├── TopMenuController.js
│ │ ├── TopMenuModule.js
│ │ ├── TopMenuView.html
│ │ └── post/
│ │ ├── DropdownTagTemplate.html
│ │ ├── DropdownUserTemplate.html
│ │ ├── PostController.js
│ │ ├── PostModule.js
│ │ └── PostView.html
│ ├── assets/
│ │ ├── bower_components/
│ │ │ ├── angular/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-csp.css
│ │ │ │ ├── angular.min.js.gzip
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-animate/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-bootstrap/
│ │ │ │ ├── .bower.json
│ │ │ │ └── bower.json
│ │ │ ├── angular-bootstrap-tour/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── app/
│ │ │ │ │ ├── angular-bootstrap-tour.js
│ │ │ │ │ ├── tour_config_provider.js
│ │ │ │ │ ├── tour_controller.js
│ │ │ │ │ ├── tour_directive.js
│ │ │ │ │ ├── tour_helpers.js
│ │ │ │ │ └── tour_step_directive.js
│ │ │ │ ├── bower.json
│ │ │ │ ├── demo/
│ │ │ │ │ └── angular-bootstrap-tour.js
│ │ │ │ ├── dist/
│ │ │ │ │ └── angular-bootstrap-tour.js
│ │ │ │ ├── gruntfile.js
│ │ │ │ ├── karma.conf.js
│ │ │ │ └── test/
│ │ │ │ └── spec/
│ │ │ │ └── angular-bootstrap-tour.spec.js
│ │ │ ├── angular-cookies/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-mocks/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-mocks.js
│ │ │ │ ├── bower.json
│ │ │ │ ├── ngAnimateMock.js
│ │ │ │ ├── ngMock.js
│ │ │ │ ├── ngMockE2E.js
│ │ │ │ └── package.json
│ │ │ ├── angular-moment/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── .editorconfig
│ │ │ │ ├── .gitignore
│ │ │ │ ├── .jshintrc
│ │ │ │ ├── .npmignore
│ │ │ │ ├── .travis.yml
│ │ │ │ ├── CHANGELOG.md
│ │ │ │ ├── CONTRIBUTING.md
│ │ │ │ ├── Gruntfile.js
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-moment.nuspec
│ │ │ │ ├── bower.json
│ │ │ │ ├── karma.conf.js
│ │ │ │ ├── package.json
│ │ │ │ └── tests.js
│ │ │ ├── angular-resource/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-route/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-route.js
│ │ │ │ └── bower.json
│ │ │ ├── angular-sanitize/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-touch/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-translate/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ └── bower.json
│ │ │ ├── angular-translate-storage-cookie/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ └── bower.json
│ │ │ ├── angular-ui-router/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── CHANGELOG.md
│ │ │ │ ├── CONTRIBUTING.md
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── api/
│ │ │ │ │ └── angular-ui-router.d.ts
│ │ │ │ ├── bower.json
│ │ │ │ ├── release/
│ │ │ │ │ └── angular-ui-router.js
│ │ │ │ └── src/
│ │ │ │ ├── common.js
│ │ │ │ ├── resolve.js
│ │ │ │ ├── state.js
│ │ │ │ ├── stateDirectives.js
│ │ │ │ ├── stateFilters.js
│ │ │ │ ├── templateFactory.js
│ │ │ │ ├── urlMatcherFactory.js
│ │ │ │ ├── urlRouter.js
│ │ │ │ ├── view.js
│ │ │ │ ├── viewDirective.js
│ │ │ │ └── viewScroll.js
│ │ │ ├── bootstrap/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── DOCS-LICENSE
│ │ │ │ ├── LICENSE
│ │ │ │ ├── LICENSE-MIT
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── dist/
│ │ │ │ │ ├── css/
│ │ │ │ │ │ ├── bootstrap-theme.css
│ │ │ │ │ │ └── bootstrap.css
│ │ │ │ │ └── js/
│ │ │ │ │ └── bootstrap.js
│ │ │ │ ├── js/
│ │ │ │ │ ├── affix.js
│ │ │ │ │ ├── alert.js
│ │ │ │ │ ├── button.js
│ │ │ │ │ ├── carousel.js
│ │ │ │ │ ├── collapse.js
│ │ │ │ │ ├── dropdown.js
│ │ │ │ │ ├── modal.js
│ │ │ │ │ ├── popover.js
│ │ │ │ │ ├── scrollspy.js
│ │ │ │ │ ├── tab.js
│ │ │ │ │ ├── tooltip.js
│ │ │ │ │ └── transition.js
│ │ │ │ └── less/
│ │ │ │ ├── alerts.less
│ │ │ │ ├── badges.less
│ │ │ │ ├── bootstrap.less
│ │ │ │ ├── breadcrumbs.less
│ │ │ │ ├── button-groups.less
│ │ │ │ ├── buttons.less
│ │ │ │ ├── carousel.less
│ │ │ │ ├── close.less
│ │ │ │ ├── code.less
│ │ │ │ ├── component-animations.less
│ │ │ │ ├── dropdowns.less
│ │ │ │ ├── forms.less
│ │ │ │ ├── glyphicons.less
│ │ │ │ ├── grid.less
│ │ │ │ ├── input-groups.less
│ │ │ │ ├── jumbotron.less
│ │ │ │ ├── labels.less
│ │ │ │ ├── list-group.less
│ │ │ │ ├── media.less
│ │ │ │ ├── mixins.less
│ │ │ │ ├── modals.less
│ │ │ │ ├── navbar.less
│ │ │ │ ├── navs.less
│ │ │ │ ├── normalize.less
│ │ │ │ ├── pager.less
│ │ │ │ ├── pagination.less
│ │ │ │ ├── panels.less
│ │ │ │ ├── popovers.less
│ │ │ │ ├── print.less
│ │ │ │ ├── progress-bars.less
│ │ │ │ ├── responsive-utilities.less
│ │ │ │ ├── scaffolding.less
│ │ │ │ ├── tables.less
│ │ │ │ ├── theme.less
│ │ │ │ ├── thumbnails.less
│ │ │ │ ├── tooltip.less
│ │ │ │ ├── type.less
│ │ │ │ ├── utilities.less
│ │ │ │ ├── variables.less
│ │ │ │ └── wells.less
│ │ │ ├── jquery/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── MIT-LICENSE.txt
│ │ │ │ ├── bower.json
│ │ │ │ ├── dist/
│ │ │ │ │ └── jquery.js
│ │ │ │ └── src/
│ │ │ │ ├── ajax/
│ │ │ │ │ ├── jsonp.js
│ │ │ │ │ ├── load.js
│ │ │ │ │ ├── parseJSON.js
│ │ │ │ │ ├── parseXML.js
│ │ │ │ │ ├── script.js
│ │ │ │ │ ├── var/
│ │ │ │ │ │ ├── nonce.js
│ │ │ │ │ │ └── rquery.js
│ │ │ │ │ └── xhr.js
│ │ │ │ ├── ajax.js
│ │ │ │ ├── attributes/
│ │ │ │ │ ├── attr.js
│ │ │ │ │ ├── classes.js
│ │ │ │ │ ├── prop.js
│ │ │ │ │ ├── support.js
│ │ │ │ │ └── val.js
│ │ │ │ ├── attributes.js
│ │ │ │ ├── callbacks.js
│ │ │ │ ├── core/
│ │ │ │ │ ├── access.js
│ │ │ │ │ ├── init.js
│ │ │ │ │ ├── parseHTML.js
│ │ │ │ │ ├── ready.js
│ │ │ │ │ └── var/
│ │ │ │ │ └── rsingleTag.js
│ │ │ │ ├── core.js
│ │ │ │ ├── css/
│ │ │ │ │ ├── addGetHookIf.js
│ │ │ │ │ ├── curCSS.js
│ │ │ │ │ ├── defaultDisplay.js
│ │ │ │ │ ├── hiddenVisibleSelectors.js
│ │ │ │ │ ├── support.js
│ │ │ │ │ ├── swap.js
│ │ │ │ │ └── var/
│ │ │ │ │ ├── cssExpand.js
│ │ │ │ │ ├── isHidden.js
│ │ │ │ │ ├── rmargin.js
│ │ │ │ │ └── rnumnonpx.js
│ │ │ │ ├── css.js
│ │ │ │ ├── data.js
│ │ │ │ ├── deferred.js
│ │ │ │ ├── deprecated.js
│ │ │ │ ├── dimensions.js
│ │ │ │ ├── effects/
│ │ │ │ │ ├── Tween.js
│ │ │ │ │ ├── animatedSelector.js
│ │ │ │ │ └── support.js
│ │ │ │ ├── effects.js
│ │ │ │ ├── event/
│ │ │ │ │ ├── alias.js
│ │ │ │ │ └── support.js
│ │ │ │ ├── event.js
│ │ │ │ ├── exports/
│ │ │ │ │ ├── amd.js
│ │ │ │ │ └── global.js
│ │ │ │ ├── intro.js
│ │ │ │ ├── jquery.js
│ │ │ │ ├── manipulation/
│ │ │ │ │ ├── _evalUrl.js
│ │ │ │ │ ├── support.js
│ │ │ │ │ └── var/
│ │ │ │ │ └── rcheckableType.js
│ │ │ │ ├── manipulation.js
│ │ │ │ ├── offset.js
│ │ │ │ ├── outro.js
│ │ │ │ ├── queue/
│ │ │ │ │ └── delay.js
│ │ │ │ ├── queue.js
│ │ │ │ ├── selector-sizzle.js
│ │ │ │ ├── selector.js
│ │ │ │ ├── serialize.js
│ │ │ │ ├── sizzle/
│ │ │ │ │ └── dist/
│ │ │ │ │ └── sizzle.js
│ │ │ │ ├── support.js
│ │ │ │ ├── traversing/
│ │ │ │ │ ├── findFilter.js
│ │ │ │ │ └── var/
│ │ │ │ │ └── rneedsContext.js
│ │ │ │ ├── traversing.js
│ │ │ │ ├── var/
│ │ │ │ │ ├── class2type.js
│ │ │ │ │ ├── concat.js
│ │ │ │ │ ├── deletedIds.js
│ │ │ │ │ ├── hasOwn.js
│ │ │ │ │ ├── indexOf.js
│ │ │ │ │ ├── pnum.js
│ │ │ │ │ ├── push.js
│ │ │ │ │ ├── rnotwhite.js
│ │ │ │ │ ├── slice.js
│ │ │ │ │ ├── strundefined.js
│ │ │ │ │ ├── support.js
│ │ │ │ │ └── toString.js
│ │ │ │ └── wrap.js
│ │ │ ├── ment.io/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── LICENSE-MIT
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── dist/
│ │ │ │ │ ├── mentio.js
│ │ │ │ │ └── templates.js
│ │ │ │ ├── gulpfile.js
│ │ │ │ ├── karma.conf.js
│ │ │ │ ├── ment.io/
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── peopledata.json
│ │ │ │ │ ├── productdata.json
│ │ │ │ │ ├── scripts.js
│ │ │ │ │ ├── simplepeopledata.json
│ │ │ │ │ └── styles.css
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ ├── mentio-menu.tpl.html
│ │ │ │ ├── mentio.directive.js
│ │ │ │ └── mentio.service.js
│ │ │ ├── moment/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── CHANGELOG.md
│ │ │ │ ├── LICENSE
│ │ │ │ ├── Moment.js.nuspec
│ │ │ │ ├── README.md
│ │ │ │ ├── benchmarks/
│ │ │ │ │ └── clone.js
│ │ │ │ ├── bower.json
│ │ │ │ ├── locale/
│ │ │ │ │ ├── af.js
│ │ │ │ │ ├── ar-ma.js
│ │ │ │ │ ├── ar-sa.js
│ │ │ │ │ ├── ar-tn.js
│ │ │ │ │ ├── ar.js
│ │ │ │ │ ├── az.js
│ │ │ │ │ ├── be.js
│ │ │ │ │ ├── bg.js
│ │ │ │ │ ├── bn.js
│ │ │ │ │ ├── bo.js
│ │ │ │ │ ├── br.js
│ │ │ │ │ ├── bs.js
│ │ │ │ │ ├── ca.js
│ │ │ │ │ ├── cs.js
│ │ │ │ │ ├── cv.js
│ │ │ │ │ ├── cy.js
│ │ │ │ │ ├── da.js
│ │ │ │ │ ├── de-at.js
│ │ │ │ │ ├── de.js
│ │ │ │ │ ├── el.js
│ │ │ │ │ ├── en-au.js
│ │ │ │ │ ├── en-ca.js
│ │ │ │ │ ├── en-gb.js
│ │ │ │ │ ├── eo.js
│ │ │ │ │ ├── es.js
│ │ │ │ │ ├── et.js
│ │ │ │ │ ├── eu.js
│ │ │ │ │ ├── fa.js
│ │ │ │ │ ├── fi.js
│ │ │ │ │ ├── fo.js
│ │ │ │ │ ├── fr-ca.js
│ │ │ │ │ ├── fr.js
│ │ │ │ │ ├── fy.js
│ │ │ │ │ ├── gl.js
│ │ │ │ │ ├── he.js
│ │ │ │ │ ├── hi.js
│ │ │ │ │ ├── hr.js
│ │ │ │ │ ├── hu.js
│ │ │ │ │ ├── hy-am.js
│ │ │ │ │ ├── id.js
│ │ │ │ │ ├── is.js
│ │ │ │ │ ├── it.js
│ │ │ │ │ ├── ja.js
│ │ │ │ │ ├── ka.js
│ │ │ │ │ ├── km.js
│ │ │ │ │ ├── ko.js
│ │ │ │ │ ├── lb.js
│ │ │ │ │ ├── lt.js
│ │ │ │ │ ├── lv.js
│ │ │ │ │ ├── mk.js
│ │ │ │ │ ├── ml.js
│ │ │ │ │ ├── mr.js
│ │ │ │ │ ├── ms-my.js
│ │ │ │ │ ├── my.js
│ │ │ │ │ ├── nb.js
│ │ │ │ │ ├── ne.js
│ │ │ │ │ ├── nl.js
│ │ │ │ │ ├── nn.js
│ │ │ │ │ ├── pl.js
│ │ │ │ │ ├── pt-br.js
│ │ │ │ │ ├── pt.js
│ │ │ │ │ ├── ro.js
│ │ │ │ │ ├── ru.js
│ │ │ │ │ ├── sk.js
│ │ │ │ │ ├── sl.js
│ │ │ │ │ ├── sq.js
│ │ │ │ │ ├── sr-cyrl.js
│ │ │ │ │ ├── sr.js
│ │ │ │ │ ├── sv.js
│ │ │ │ │ ├── ta.js
│ │ │ │ │ ├── th.js
│ │ │ │ │ ├── tl-ph.js
│ │ │ │ │ ├── tr.js
│ │ │ │ │ ├── tzm-latn.js
│ │ │ │ │ ├── tzm.js
│ │ │ │ │ ├── uk.js
│ │ │ │ │ ├── uz.js
│ │ │ │ │ ├── vi.js
│ │ │ │ │ ├── zh-cn.js
│ │ │ │ │ └── zh-tw.js
│ │ │ │ ├── meteor/
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── export.js
│ │ │ │ │ └── test.js
│ │ │ │ ├── min/
│ │ │ │ │ ├── locales.js
│ │ │ │ │ ├── moment-with-locales.js
│ │ │ │ │ └── tests.js
│ │ │ │ ├── moment.js
│ │ │ │ ├── scripts/
│ │ │ │ │ └── npm_prepublish.sh
│ │ │ │ ├── src/
│ │ │ │ │ ├── lib/
│ │ │ │ │ │ ├── create/
│ │ │ │ │ │ │ ├── check-overflow.js
│ │ │ │ │ │ │ ├── date-from-array.js
│ │ │ │ │ │ │ ├── default-parsing-flags.js
│ │ │ │ │ │ │ ├── from-anything.js
│ │ │ │ │ │ │ ├── from-array.js
│ │ │ │ │ │ │ ├── from-object.js
│ │ │ │ │ │ │ ├── from-string-and-array.js
│ │ │ │ │ │ │ ├── from-string-and-format.js
│ │ │ │ │ │ │ ├── from-string.js
│ │ │ │ │ │ │ ├── local.js
│ │ │ │ │ │ │ ├── utc.js
│ │ │ │ │ │ │ └── valid.js
│ │ │ │ │ │ ├── duration/
│ │ │ │ │ │ │ ├── abs.js
│ │ │ │ │ │ │ ├── add-subtract.js
│ │ │ │ │ │ │ ├── as.js
│ │ │ │ │ │ │ ├── bubble.js
│ │ │ │ │ │ │ ├── constructor.js
│ │ │ │ │ │ │ ├── create.js
│ │ │ │ │ │ │ ├── duration.js
│ │ │ │ │ │ │ ├── get.js
│ │ │ │ │ │ │ ├── humanize.js
│ │ │ │ │ │ │ ├── iso-string.js
│ │ │ │ │ │ │ └── prototype.js
│ │ │ │ │ │ ├── format/
│ │ │ │ │ │ │ └── format.js
│ │ │ │ │ │ ├── locale/
│ │ │ │ │ │ │ ├── calendar.js
│ │ │ │ │ │ │ ├── constructor.js
│ │ │ │ │ │ │ ├── en.js
│ │ │ │ │ │ │ ├── formats.js
│ │ │ │ │ │ │ ├── invalid.js
│ │ │ │ │ │ │ ├── lists.js
│ │ │ │ │ │ │ ├── locale.js
│ │ │ │ │ │ │ ├── locales.js
│ │ │ │ │ │ │ ├── ordinal.js
│ │ │ │ │ │ │ ├── pre-post-format.js
│ │ │ │ │ │ │ ├── prototype.js
│ │ │ │ │ │ │ ├── relative.js
│ │ │ │ │ │ │ └── set.js
│ │ │ │ │ │ ├── moment/
│ │ │ │ │ │ │ ├── add-subtract.js
│ │ │ │ │ │ │ ├── calendar.js
│ │ │ │ │ │ │ ├── clone.js
│ │ │ │ │ │ │ ├── compare.js
│ │ │ │ │ │ │ ├── constructor.js
│ │ │ │ │ │ │ ├── diff.js
│ │ │ │ │ │ │ ├── format.js
│ │ │ │ │ │ │ ├── from.js
│ │ │ │ │ │ │ ├── get-set.js
│ │ │ │ │ │ │ ├── locale.js
│ │ │ │ │ │ │ ├── min-max.js
│ │ │ │ │ │ │ ├── moment.js
│ │ │ │ │ │ │ ├── prototype.js
│ │ │ │ │ │ │ ├── start-end-of.js
│ │ │ │ │ │ │ ├── to-type.js
│ │ │ │ │ │ │ └── valid.js
│ │ │ │ │ │ ├── parse/
│ │ │ │ │ │ │ ├── regex.js
│ │ │ │ │ │ │ └── token.js
│ │ │ │ │ │ ├── units/
│ │ │ │ │ │ │ ├── aliases.js
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── day-of-month.js
│ │ │ │ │ │ │ ├── day-of-week.js
│ │ │ │ │ │ │ ├── day-of-year.js
│ │ │ │ │ │ │ ├── hour.js
│ │ │ │ │ │ │ ├── millisecond.js
│ │ │ │ │ │ │ ├── minute.js
│ │ │ │ │ │ │ ├── month.js
│ │ │ │ │ │ │ ├── offset.js
│ │ │ │ │ │ │ ├── quarter.js
│ │ │ │ │ │ │ ├── second.js
│ │ │ │ │ │ │ ├── timestamp.js
│ │ │ │ │ │ │ ├── timezone.js
│ │ │ │ │ │ │ ├── units.js
│ │ │ │ │ │ │ ├── week-year.js
│ │ │ │ │ │ │ ├── week.js
│ │ │ │ │ │ │ └── year.js
│ │ │ │ │ │ └── utils/
│ │ │ │ │ │ ├── abs-floor.js
│ │ │ │ │ │ ├── compare-arrays.js
│ │ │ │ │ │ ├── defaults.js
│ │ │ │ │ │ ├── deprecate.js
│ │ │ │ │ │ ├── extend.js
│ │ │ │ │ │ ├── has-own-prop.js
│ │ │ │ │ │ ├── hooks.js
│ │ │ │ │ │ ├── is-array.js
│ │ │ │ │ │ ├── is-date.js
│ │ │ │ │ │ ├── map.js
│ │ │ │ │ │ ├── to-int.js
│ │ │ │ │ │ └── zero-fill.js
│ │ │ │ │ ├── locale/
│ │ │ │ │ │ ├── af.js
│ │ │ │ │ │ ├── ar-ma.js
│ │ │ │ │ │ ├── ar-sa.js
│ │ │ │ │ │ ├── ar-tn.js
│ │ │ │ │ │ ├── ar.js
│ │ │ │ │ │ ├── az.js
│ │ │ │ │ │ ├── be.js
│ │ │ │ │ │ ├── bg.js
│ │ │ │ │ │ ├── bn.js
│ │ │ │ │ │ ├── bo.js
│ │ │ │ │ │ ├── br.js
│ │ │ │ │ │ ├── bs.js
│ │ │ │ │ │ ├── ca.js
│ │ │ │ │ │ ├── cs.js
│ │ │ │ │ │ ├── cv.js
│ │ │ │ │ │ ├── cy.js
│ │ │ │ │ │ ├── da.js
│ │ │ │ │ │ ├── de-at.js
│ │ │ │ │ │ ├── de.js
│ │ │ │ │ │ ├── el.js
│ │ │ │ │ │ ├── en-au.js
│ │ │ │ │ │ ├── en-ca.js
│ │ │ │ │ │ ├── en-gb.js
│ │ │ │ │ │ ├── eo.js
│ │ │ │ │ │ ├── es.js
│ │ │ │ │ │ ├── et.js
│ │ │ │ │ │ ├── eu.js
│ │ │ │ │ │ ├── fa.js
│ │ │ │ │ │ ├── fi.js
│ │ │ │ │ │ ├── fo.js
│ │ │ │ │ │ ├── fr-ca.js
│ │ │ │ │ │ ├── fr.js
│ │ │ │ │ │ ├── fy.js
│ │ │ │ │ │ ├── gl.js
│ │ │ │ │ │ ├── he.js
│ │ │ │ │ │ ├── hi.js
│ │ │ │ │ │ ├── hr.js
│ │ │ │ │ │ ├── hu.js
│ │ │ │ │ │ ├── hy-am.js
│ │ │ │ │ │ ├── id.js
│ │ │ │ │ │ ├── is.js
│ │ │ │ │ │ ├── it.js
│ │ │ │ │ │ ├── ja.js
│ │ │ │ │ │ ├── ka.js
│ │ │ │ │ │ ├── km.js
│ │ │ │ │ │ ├── ko.js
│ │ │ │ │ │ ├── lb.js
│ │ │ │ │ │ ├── lt.js
│ │ │ │ │ │ ├── lv.js
│ │ │ │ │ │ ├── mk.js
│ │ │ │ │ │ ├── ml.js
│ │ │ │ │ │ ├── mr.js
│ │ │ │ │ │ ├── ms-my.js
│ │ │ │ │ │ ├── my.js
│ │ │ │ │ │ ├── nb.js
│ │ │ │ │ │ ├── ne.js
│ │ │ │ │ │ ├── nl.js
│ │ │ │ │ │ ├── nn.js
│ │ │ │ │ │ ├── pl.js
│ │ │ │ │ │ ├── pt-br.js
│ │ │ │ │ │ ├── pt.js
│ │ │ │ │ │ ├── ro.js
│ │ │ │ │ │ ├── ru.js
│ │ │ │ │ │ ├── sk.js
│ │ │ │ │ │ ├── sl.js
│ │ │ │ │ │ ├── sq.js
│ │ │ │ │ │ ├── sr-cyrl.js
│ │ │ │ │ │ ├── sr.js
│ │ │ │ │ │ ├── sv.js
│ │ │ │ │ │ ├── ta.js
│ │ │ │ │ │ ├── th.js
│ │ │ │ │ │ ├── tl-ph.js
│ │ │ │ │ │ ├── tr.js
│ │ │ │ │ │ ├── tzm-latn.js
│ │ │ │ │ │ ├── tzm.js
│ │ │ │ │ │ ├── uk.js
│ │ │ │ │ │ ├── uz.js
│ │ │ │ │ │ ├── vi.js
│ │ │ │ │ │ ├── zh-cn.js
│ │ │ │ │ │ └── zh-tw.js
│ │ │ │ │ └── moment.js
│ │ │ │ └── templates/
│ │ │ │ ├── amd-named.js
│ │ │ │ ├── amd.js
│ │ │ │ ├── globals.js
│ │ │ │ ├── locale-header.js
│ │ │ │ └── test-header.js
│ │ │ ├── ng-file-upload/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── FileAPI.flash.swf
│ │ │ │ ├── FileAPI.js
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-file-upload-all.js
│ │ │ │ ├── angular-file-upload-shim.js
│ │ │ │ ├── angular-file-upload.js
│ │ │ │ ├── bower.json
│ │ │ │ └── ng-file-upload-all.js
│ │ │ ├── ngInfiniteScroll/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── build/
│ │ │ │ │ └── ng-infinite-scroll.js
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ └── infinite-scroll.coffee
│ │ │ ├── ngtoast/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ └── dist/
│ │ │ │ ├── ngToast-animations.css
│ │ │ │ ├── ngToast.css
│ │ │ │ └── ngToast.js
│ │ │ └── openlayers/
│ │ │ ├── .bower.json
│ │ │ ├── .gitignore
│ │ │ ├── apidoc_config/
│ │ │ │ ├── Languages.txt
│ │ │ │ ├── Menu.txt
│ │ │ │ ├── OL.css
│ │ │ │ └── Topics.txt
│ │ │ ├── authors.txt
│ │ │ ├── build/
│ │ │ │ ├── README.txt
│ │ │ │ ├── build.py
│ │ │ │ ├── buildUncompressed.py
│ │ │ │ ├── closure-compiler/
│ │ │ │ │ └── Externs.js
│ │ │ │ ├── full.cfg
│ │ │ │ ├── license.txt
│ │ │ │ ├── light.cfg
│ │ │ │ ├── lite.cfg
│ │ │ │ ├── mobile.cfg
│ │ │ │ └── tests.cfg
│ │ │ ├── doc_config/
│ │ │ │ ├── Languages.txt
│ │ │ │ ├── Menu.txt
│ │ │ │ ├── OL.css
│ │ │ │ └── Topics.txt
│ │ │ ├── lib/
│ │ │ │ ├── Firebug/
│ │ │ │ │ ├── firebug.css
│ │ │ │ │ ├── firebug.html
│ │ │ │ │ ├── firebug.js
│ │ │ │ │ ├── firebugx.js
│ │ │ │ │ ├── license.txt
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── OpenLayers/
│ │ │ │ │ ├── Animation.js
│ │ │ │ │ ├── BaseTypes/
│ │ │ │ │ │ ├── Bounds.js
│ │ │ │ │ │ ├── Class.js
│ │ │ │ │ │ ├── Date.js
│ │ │ │ │ │ ├── Element.js
│ │ │ │ │ │ ├── LonLat.js
│ │ │ │ │ │ ├── Pixel.js
│ │ │ │ │ │ └── Size.js
│ │ │ │ │ ├── BaseTypes.js
│ │ │ │ │ ├── Console.js
│ │ │ │ │ ├── Control/
│ │ │ │ │ │ ├── ArgParser.js
│ │ │ │ │ │ ├── Attribution.js
│ │ │ │ │ │ ├── Button.js
│ │ │ │ │ │ ├── CacheRead.js
│ │ │ │ │ │ ├── CacheWrite.js
│ │ │ │ │ │ ├── DragFeature.js
│ │ │ │ │ │ ├── DragPan.js
│ │ │ │ │ │ ├── DrawFeature.js
│ │ │ │ │ │ ├── EditingToolbar.js
│ │ │ │ │ │ ├── Geolocate.js
│ │ │ │ │ │ ├── GetFeature.js
│ │ │ │ │ │ ├── Graticule.js
│ │ │ │ │ │ ├── KeyboardDefaults.js
│ │ │ │ │ │ ├── LayerSwitcher.js
│ │ │ │ │ │ ├── Measure.js
│ │ │ │ │ │ ├── ModifyFeature/
│ │ │ │ │ │ │ └── BySegment.js
│ │ │ │ │ │ ├── ModifyFeature.js
│ │ │ │ │ │ ├── MousePosition.js
│ │ │ │ │ │ ├── NavToolbar.js
│ │ │ │ │ │ ├── Navigation.js
│ │ │ │ │ │ ├── NavigationHistory.js
│ │ │ │ │ │ ├── OverviewMap.js
│ │ │ │ │ │ ├── Pan.js
│ │ │ │ │ │ ├── PanPanel.js
│ │ │ │ │ │ ├── PanZoom.js
│ │ │ │ │ │ ├── PanZoomBar.js
│ │ │ │ │ │ ├── Panel.js
│ │ │ │ │ │ ├── Permalink.js
│ │ │ │ │ │ ├── PinchZoom.js
│ │ │ │ │ │ ├── SLDSelect.js
│ │ │ │ │ │ ├── Scale.js
│ │ │ │ │ │ ├── ScaleLine.js
│ │ │ │ │ │ ├── SelectFeature.js
│ │ │ │ │ │ ├── Snapping.js
│ │ │ │ │ │ ├── Split.js
│ │ │ │ │ │ ├── TextButtonPanel.js
│ │ │ │ │ │ ├── TouchNavigation.js
│ │ │ │ │ │ ├── TransformFeature.js
│ │ │ │ │ │ ├── UTFGrid.js
│ │ │ │ │ │ ├── WMSGetFeatureInfo.js
│ │ │ │ │ │ ├── WMTSGetFeatureInfo.js
│ │ │ │ │ │ ├── Zoom.js
│ │ │ │ │ │ ├── ZoomBox.js
│ │ │ │ │ │ ├── ZoomIn.js
│ │ │ │ │ │ ├── ZoomOut.js
│ │ │ │ │ │ ├── ZoomPanel.js
│ │ │ │ │ │ └── ZoomToMaxExtent.js
│ │ │ │ │ ├── Control.js
│ │ │ │ │ ├── Events/
│ │ │ │ │ │ ├── buttonclick.js
│ │ │ │ │ │ └── featureclick.js
│ │ │ │ │ ├── Events.js
│ │ │ │ │ ├── Feature/
│ │ │ │ │ │ └── Vector.js
│ │ │ │ │ ├── Feature.js
│ │ │ │ │ ├── Filter/
│ │ │ │ │ │ ├── Comparison.js
│ │ │ │ │ │ ├── FeatureId.js
│ │ │ │ │ │ ├── Function.js
│ │ │ │ │ │ ├── Logical.js
│ │ │ │ │ │ └── Spatial.js
│ │ │ │ │ ├── Filter.js
│ │ │ │ │ ├── Format/
│ │ │ │ │ │ ├── ArcXML/
│ │ │ │ │ │ │ └── Features.js
│ │ │ │ │ │ ├── ArcXML.js
│ │ │ │ │ │ ├── Atom.js
│ │ │ │ │ │ ├── CQL.js
│ │ │ │ │ │ ├── CSWGetDomain/
│ │ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ │ ├── CSWGetDomain.js
│ │ │ │ │ │ ├── CSWGetRecords/
│ │ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ │ ├── CSWGetRecords.js
│ │ │ │ │ │ ├── Context.js
│ │ │ │ │ │ ├── EncodedPolyline.js
│ │ │ │ │ │ ├── Filter/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ ├── v2.js
│ │ │ │ │ │ │ └── v2_0_0.js
│ │ │ │ │ │ ├── Filter.js
│ │ │ │ │ │ ├── GML/
│ │ │ │ │ │ │ ├── Base.js
│ │ │ │ │ │ │ ├── v2.js
│ │ │ │ │ │ │ └── v3.js
│ │ │ │ │ │ ├── GML.js
│ │ │ │ │ │ ├── GPX.js
│ │ │ │ │ │ ├── GeoJSON.js
│ │ │ │ │ │ ├── GeoRSS.js
│ │ │ │ │ │ ├── JSON.js
│ │ │ │ │ │ ├── KML.js
│ │ │ │ │ │ ├── OGCExceptionReport.js
│ │ │ │ │ │ ├── OSM.js
│ │ │ │ │ │ ├── OWSCommon/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── OWSCommon.js
│ │ │ │ │ │ ├── OWSContext/
│ │ │ │ │ │ │ └── v0_3_1.js
│ │ │ │ │ │ ├── OWSContext.js
│ │ │ │ │ │ ├── QueryStringFilter.js
│ │ │ │ │ │ ├── SLD/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_0_0_GeoServer.js
│ │ │ │ │ │ ├── SLD.js
│ │ │ │ │ │ ├── SOSCapabilities/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── SOSCapabilities.js
│ │ │ │ │ │ ├── SOSGetFeatureOfInterest.js
│ │ │ │ │ │ ├── SOSGetObservation.js
│ │ │ │ │ │ ├── TMSCapabilities.js
│ │ │ │ │ │ ├── Text.js
│ │ │ │ │ │ ├── WCSCapabilities/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── WCSCapabilities.js
│ │ │ │ │ │ ├── WCSDescribeCoverage/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── WCSDescribeCoverage.js
│ │ │ │ │ │ ├── WCSGetCoverage.js
│ │ │ │ │ │ ├── WFS.js
│ │ │ │ │ │ ├── WFSCapabilities/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ └── v2_0_0.js
│ │ │ │ │ │ ├── WFSCapabilities.js
│ │ │ │ │ │ ├── WFSDescribeFeatureType.js
│ │ │ │ │ │ ├── WFST/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ └── v2_0_0.js
│ │ │ │ │ │ ├── WFST.js
│ │ │ │ │ │ ├── WKT.js
│ │ │ │ │ │ ├── WMC/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── WMC.js
│ │ │ │ │ │ ├── WMSCapabilities/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_1.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ ├── v1_1_1.js
│ │ │ │ │ │ │ ├── v1_1_1_WMSC.js
│ │ │ │ │ │ │ ├── v1_3.js
│ │ │ │ │ │ │ └── v1_3_0.js
│ │ │ │ │ │ ├── WMSCapabilities.js
│ │ │ │ │ │ ├── WMSDescribeLayer/
│ │ │ │ │ │ │ └── v1_1.js
│ │ │ │ │ │ ├── WMSDescribeLayer.js
│ │ │ │ │ │ ├── WMSGetFeatureInfo.js
│ │ │ │ │ │ ├── WMTSCapabilities/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── WMTSCapabilities.js
│ │ │ │ │ │ ├── WPSCapabilities/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── WPSCapabilities.js
│ │ │ │ │ │ ├── WPSDescribeProcess/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── WPSDescribeProcess.js
│ │ │ │ │ │ ├── WPSExecute.js
│ │ │ │ │ │ ├── XLS/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── XLS.js
│ │ │ │ │ │ ├── XML/
│ │ │ │ │ │ │ └── VersionedOGC.js
│ │ │ │ │ │ └── XML.js
│ │ │ │ │ ├── Format.js
│ │ │ │ │ ├── Geometry/
│ │ │ │ │ │ ├── Collection.js
│ │ │ │ │ │ ├── Curve.js
│ │ │ │ │ │ ├── LineString.js
│ │ │ │ │ │ ├── LinearRing.js
│ │ │ │ │ │ ├── MultiLineString.js
│ │ │ │ │ │ ├── MultiPoint.js
│ │ │ │ │ │ ├── MultiPolygon.js
│ │ │ │ │ │ ├── Point.js
│ │ │ │ │ │ └── Polygon.js
│ │ │ │ │ ├── Geometry.js
│ │ │ │ │ ├── Handler/
│ │ │ │ │ │ ├── Box.js
│ │ │ │ │ │ ├── Click.js
│ │ │ │ │ │ ├── Drag.js
│ │ │ │ │ │ ├── Feature.js
│ │ │ │ │ │ ├── Hover.js
│ │ │ │ │ │ ├── Keyboard.js
│ │ │ │ │ │ ├── MouseWheel.js
│ │ │ │ │ │ ├── Path.js
│ │ │ │ │ │ ├── Pinch.js
│ │ │ │ │ │ ├── Point.js
│ │ │ │ │ │ ├── Polygon.js
│ │ │ │ │ │ └── RegularPolygon.js
│ │ │ │ │ ├── Handler.js
│ │ │ │ │ ├── Icon.js
│ │ │ │ │ ├── Kinetic.js
│ │ │ │ │ ├── Lang/
│ │ │ │ │ │ ├── ar.js
│ │ │ │ │ │ ├── be-tarask.js
│ │ │ │ │ │ ├── bg.js
│ │ │ │ │ │ ├── br.js
│ │ │ │ │ │ ├── ca.js
│ │ │ │ │ │ ├── cs-CZ.js
│ │ │ │ │ │ ├── da-DK.js
│ │ │ │ │ │ ├── de.js
│ │ │ │ │ │ ├── el.js
│ │ │ │ │ │ ├── en-CA.js
│ │ │ │ │ │ ├── en.js
│ │ │ │ │ │ ├── es.js
│ │ │ │ │ │ ├── fi.js
│ │ │ │ │ │ ├── fr.js
│ │ │ │ │ │ ├── fur.js
│ │ │ │ │ │ ├── gl.js
│ │ │ │ │ │ ├── gsw.js
│ │ │ │ │ │ ├── hr.js
│ │ │ │ │ │ ├── hsb.js
│ │ │ │ │ │ ├── hu.js
│ │ │ │ │ │ ├── ia.js
│ │ │ │ │ │ ├── id.js
│ │ │ │ │ │ ├── io.js
│ │ │ │ │ │ ├── is.js
│ │ │ │ │ │ ├── it.js
│ │ │ │ │ │ ├── ja.js
│ │ │ │ │ │ ├── km.js
│ │ │ │ │ │ ├── ksh.js
│ │ │ │ │ │ ├── lt.js
│ │ │ │ │ │ ├── nb.js
│ │ │ │ │ │ ├── nds.js
│ │ │ │ │ │ ├── nl.js
│ │ │ │ │ │ ├── nn.js
│ │ │ │ │ │ ├── oc.js
│ │ │ │ │ │ ├── pl.js
│ │ │ │ │ │ ├── pt-BR.js
│ │ │ │ │ │ ├── pt.js
│ │ │ │ │ │ ├── ro.js
│ │ │ │ │ │ ├── ru.js
│ │ │ │ │ │ ├── sk.js
│ │ │ │ │ │ ├── sv-SE.js
│ │ │ │ │ │ ├── te.js
│ │ │ │ │ │ ├── vi.js
│ │ │ │ │ │ ├── zh-CN.js
│ │ │ │ │ │ └── zh-TW.js
│ │ │ │ │ ├── Lang.js
│ │ │ │ │ ├── Layer/
│ │ │ │ │ │ ├── ArcGIS93Rest.js
│ │ │ │ │ │ ├── ArcGISCache.js
│ │ │ │ │ │ ├── ArcIMS.js
│ │ │ │ │ │ ├── Bing.js
│ │ │ │ │ │ ├── Boxes.js
│ │ │ │ │ │ ├── EventPane.js
│ │ │ │ │ │ ├── FixedZoomLevels.js
│ │ │ │ │ │ ├── GeoRSS.js
│ │ │ │ │ │ ├── Google/
│ │ │ │ │ │ │ └── v3.js
│ │ │ │ │ │ ├── Google.js
│ │ │ │ │ │ ├── Grid.js
│ │ │ │ │ │ ├── HTTPRequest.js
│ │ │ │ │ │ ├── Image.js
│ │ │ │ │ │ ├── KaMap.js
│ │ │ │ │ │ ├── KaMapCache.js
│ │ │ │ │ │ ├── MapGuide.js
│ │ │ │ │ │ ├── MapServer.js
│ │ │ │ │ │ ├── Markers.js
│ │ │ │ │ │ ├── OSM.js
│ │ │ │ │ │ ├── PointGrid.js
│ │ │ │ │ │ ├── PointTrack.js
│ │ │ │ │ │ ├── SphericalMercator.js
│ │ │ │ │ │ ├── TMS.js
│ │ │ │ │ │ ├── Text.js
│ │ │ │ │ │ ├── TileCache.js
│ │ │ │ │ │ ├── UTFGrid.js
│ │ │ │ │ │ ├── Vector/
│ │ │ │ │ │ │ └── RootContainer.js
│ │ │ │ │ │ ├── Vector.js
│ │ │ │ │ │ ├── WMS.js
│ │ │ │ │ │ ├── WMTS.js
│ │ │ │ │ │ ├── WorldWind.js
│ │ │ │ │ │ ├── XYZ.js
│ │ │ │ │ │ └── Zoomify.js
│ │ │ │ │ ├── Layer.js
│ │ │ │ │ ├── Map.js
│ │ │ │ │ ├── Marker/
│ │ │ │ │ │ └── Box.js
│ │ │ │ │ ├── Marker.js
│ │ │ │ │ ├── Popup/
│ │ │ │ │ │ ├── Anchored.js
│ │ │ │ │ │ ├── Framed.js
│ │ │ │ │ │ └── FramedCloud.js
│ │ │ │ │ ├── Popup.js
│ │ │ │ │ ├── Projection.js
│ │ │ │ │ ├── Protocol/
│ │ │ │ │ │ ├── CSW/
│ │ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ │ ├── CSW.js
│ │ │ │ │ │ ├── HTTP.js
│ │ │ │ │ │ ├── SOS/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── SOS.js
│ │ │ │ │ │ ├── Script.js
│ │ │ │ │ │ ├── WFS/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ └── v2_0_0.js
│ │ │ │ │ │ └── WFS.js
│ │ │ │ │ ├── Protocol.js
│ │ │ │ │ ├── Renderer/
│ │ │ │ │ │ ├── Canvas.js
│ │ │ │ │ │ ├── Elements.js
│ │ │ │ │ │ ├── SVG.js
│ │ │ │ │ │ └── VML.js
│ │ │ │ │ ├── Renderer.js
│ │ │ │ │ ├── Request/
│ │ │ │ │ │ └── XMLHttpRequest.js
│ │ │ │ │ ├── Request.js
│ │ │ │ │ ├── Rule.js
│ │ │ │ │ ├── SingleFile.js
│ │ │ │ │ ├── Spherical.js
│ │ │ │ │ ├── Strategy/
│ │ │ │ │ │ ├── BBOX.js
│ │ │ │ │ │ ├── Cluster.js
│ │ │ │ │ │ ├── Filter.js
│ │ │ │ │ │ ├── Fixed.js
│ │ │ │ │ │ ├── Paging.js
│ │ │ │ │ │ ├── Refresh.js
│ │ │ │ │ │ └── Save.js
│ │ │ │ │ ├── Strategy.js
│ │ │ │ │ ├── Style.js
│ │ │ │ │ ├── Style2.js
│ │ │ │ │ ├── StyleMap.js
│ │ │ │ │ ├── Symbolizer/
│ │ │ │ │ │ ├── Line.js
│ │ │ │ │ │ ├── Point.js
│ │ │ │ │ │ ├── Polygon.js
│ │ │ │ │ │ ├── Raster.js
│ │ │ │ │ │ └── Text.js
│ │ │ │ │ ├── Symbolizer.js
│ │ │ │ │ ├── Tile/
│ │ │ │ │ │ ├── Image/
│ │ │ │ │ │ │ └── IFrame.js
│ │ │ │ │ │ ├── Image.js
│ │ │ │ │ │ └── UTFGrid.js
│ │ │ │ │ ├── Tile.js
│ │ │ │ │ ├── TileManager.js
│ │ │ │ │ ├── Tween.js
│ │ │ │ │ ├── Util/
│ │ │ │ │ │ └── vendorPrefix.js
│ │ │ │ │ ├── Util.js
│ │ │ │ │ ├── WPSClient.js
│ │ │ │ │ └── WPSProcess.js
│ │ │ │ ├── OpenLayers.js
│ │ │ │ ├── Rico/
│ │ │ │ │ ├── Color.js
│ │ │ │ │ ├── Corner.js
│ │ │ │ │ └── license.js
│ │ │ │ └── deprecated.js
│ │ │ ├── license.txt
│ │ │ ├── licenses/
│ │ │ │ ├── APACHE-2.0.txt
│ │ │ │ ├── BSD-LICENSE.txt
│ │ │ │ └── MIT-LICENSE.txt
│ │ │ ├── notes/
│ │ │ │ ├── 2.12.md
│ │ │ │ ├── 2.13.md
│ │ │ │ └── 2.14.md
│ │ │ ├── readme.md
│ │ │ ├── tests/
│ │ │ │ ├── Animation.html
│ │ │ │ ├── BaseTypes/
│ │ │ │ │ ├── Bounds.html
│ │ │ │ │ ├── Class.html
│ │ │ │ │ ├── Date.html
│ │ │ │ │ ├── Element.html
│ │ │ │ │ ├── LonLat.html
│ │ │ │ │ ├── Pixel.html
│ │ │ │ │ └── Size.html
│ │ │ │ ├── BaseTypes.html
│ │ │ │ ├── Console.html
│ │ │ │ ├── Control/
│ │ │ │ │ ├── ArgParser.html
│ │ │ │ │ ├── Attribution.html
│ │ │ │ │ ├── Button.html
│ │ │ │ │ ├── CacheRead.html
│ │ │ │ │ ├── CacheWrite.html
│ │ │ │ │ ├── DragFeature.html
│ │ │ │ │ ├── DragPan.html
│ │ │ │ │ ├── DrawFeature.html
│ │ │ │ │ ├── EditingToolbar.html
│ │ │ │ │ ├── Geolocate.html
│ │ │ │ │ ├── GetFeature.html
│ │ │ │ │ ├── Graticule.html
│ │ │ │ │ ├── KeyboardDefaults.html
│ │ │ │ │ ├── LayerSwitcher.html
│ │ │ │ │ ├── Measure.html
│ │ │ │ │ ├── ModifyFeature/
│ │ │ │ │ │ └── BySegment.html
│ │ │ │ │ ├── ModifyFeature.html
│ │ │ │ │ ├── MousePosition.html
│ │ │ │ │ ├── NavToolbar.html
│ │ │ │ │ ├── Navigation.html
│ │ │ │ │ ├── NavigationHistory.html
│ │ │ │ │ ├── OverviewMap.html
│ │ │ │ │ ├── Pan.html
│ │ │ │ │ ├── PanPanel.html
│ │ │ │ │ ├── PanZoom.html
│ │ │ │ │ ├── PanZoomBar.html
│ │ │ │ │ ├── Panel.html
│ │ │ │ │ ├── Permalink.html
│ │ │ │ │ ├── PinchZoom.html
│ │ │ │ │ ├── SLDSelect.html
│ │ │ │ │ ├── Scale.html
│ │ │ │ │ ├── ScaleLine.html
│ │ │ │ │ ├── SelectFeature.html
│ │ │ │ │ ├── Snapping.html
│ │ │ │ │ ├── Split.html
│ │ │ │ │ ├── TextButtonPanel.html
│ │ │ │ │ ├── TouchNavigation.html
│ │ │ │ │ ├── TransformFeature.html
│ │ │ │ │ ├── UTFGrid.html
│ │ │ │ │ ├── WMSGetFeatureInfo.html
│ │ │ │ │ ├── WMTSGetFeatureInfo.html
│ │ │ │ │ ├── Zoom.html
│ │ │ │ │ ├── ZoomBox.html
│ │ │ │ │ ├── ZoomIn.html
│ │ │ │ │ ├── ZoomOut.html
│ │ │ │ │ └── ZoomToMaxExtent.html
│ │ │ │ ├── Control.html
│ │ │ │ ├── Events/
│ │ │ │ │ ├── buttonclick.html
│ │ │ │ │ └── featureclick.html
│ │ │ │ ├── Events.html
│ │ │ │ ├── Extras.html
│ │ │ │ ├── Feature/
│ │ │ │ │ └── Vector.html
│ │ │ │ ├── Feature.html
│ │ │ │ ├── Filter/
│ │ │ │ │ ├── Comparison.html
│ │ │ │ │ ├── FeatureId.html
│ │ │ │ │ ├── Logical.html
│ │ │ │ │ └── Spatial.html
│ │ │ │ ├── Filter.html
│ │ │ │ ├── Format/
│ │ │ │ │ ├── ArcXML/
│ │ │ │ │ │ └── Features.html
│ │ │ │ │ ├── ArcXML.html
│ │ │ │ │ ├── Atom.html
│ │ │ │ │ ├── CQL.html
│ │ │ │ │ ├── CSWGetDomain/
│ │ │ │ │ │ ├── v2_0_2.html
│ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ ├── CSWGetDomain.html
│ │ │ │ │ ├── CSWGetRecords/
│ │ │ │ │ │ ├── v2_0_2.html
│ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ ├── CSWGetRecords.html
│ │ │ │ │ ├── EncodedPolyline.html
│ │ │ │ │ ├── Filter/
│ │ │ │ │ │ ├── v1.html
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ ├── v1_1_0.html
│ │ │ │ │ │ └── v2_0_0.html
│ │ │ │ │ ├── Filter.html
│ │ │ │ │ ├── GML/
│ │ │ │ │ │ ├── cases.js
│ │ │ │ │ │ ├── v2.html
│ │ │ │ │ │ └── v3.html
│ │ │ │ │ ├── GML.html
│ │ │ │ │ ├── GPX.html
│ │ │ │ │ ├── GeoJSON.html
│ │ │ │ │ ├── GeoRSS.html
│ │ │ │ │ ├── JSON.html
│ │ │ │ │ ├── KML.html
│ │ │ │ │ ├── OGCExceptionReport.html
│ │ │ │ │ ├── OSM.html
│ │ │ │ │ ├── OWSCommon/
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ └── v1_1_0.html
│ │ │ │ │ ├── OWSContext/
│ │ │ │ │ │ └── v0_3_1.html
│ │ │ │ │ ├── QueryStringFilter.html
│ │ │ │ │ ├── SLD/
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ └── v1_0_0_GeoServer.html
│ │ │ │ │ ├── SLD.html
│ │ │ │ │ ├── SOSCapabilities/
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ ├── SOSGetFeatureOfInterest.html
│ │ │ │ │ ├── SOSGetObservation.html
│ │ │ │ │ ├── TMSCapabilities.html
│ │ │ │ │ ├── Text.html
│ │ │ │ │ ├── WCSCapabilities/
│ │ │ │ │ │ └── v1.html
│ │ │ │ │ ├── WCSCapabilities.html
│ │ │ │ │ ├── WCSDescribeCoverage/
│ │ │ │ │ │ └── v1.html
│ │ │ │ │ ├── WCSDescribeCoverage.html
│ │ │ │ │ ├── WCSGetCoverage.html
│ │ │ │ │ ├── WFS.html
│ │ │ │ │ ├── WFSCapabilities/
│ │ │ │ │ │ ├── v1.html
│ │ │ │ │ │ └── v2.html
│ │ │ │ │ ├── WFSCapabilities.html
│ │ │ │ │ ├── WFSDescribeFeatureType.html
│ │ │ │ │ ├── WFST/
│ │ │ │ │ │ ├── v1.html
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ ├── v1_1_0.html
│ │ │ │ │ │ └── v2_0_0.html
│ │ │ │ │ ├── WFST.html
│ │ │ │ │ ├── WKT.html
│ │ │ │ │ ├── WMC/
│ │ │ │ │ │ ├── v1.html
│ │ │ │ │ │ └── v1_1_0.html
│ │ │ │ │ ├── WMC.html
│ │ │ │ │ ├── WMSCapabilities/
│ │ │ │ │ │ ├── v1_1_1.html
│ │ │ │ │ │ ├── v1_1_1_WMSC.html
│ │ │ │ │ │ └── v1_3_0.html
│ │ │ │ │ ├── WMSCapabilities.html
│ │ │ │ │ ├── WMSDescribeLayer.html
│ │ │ │ │ ├── WMSGetFeatureInfo.html
│ │ │ │ │ ├── WMTSCapabilities/
│ │ │ │ │ │ └── v1_0_0.html
│ │ │ │ │ ├── WMTSCapabilities.html
│ │ │ │ │ ├── WPSCapabilities/
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ ├── WPSDescribeProcess.html
│ │ │ │ │ ├── WPSExecute.html
│ │ │ │ │ ├── XLS/
│ │ │ │ │ │ └── v1_1_0.html
│ │ │ │ │ ├── XML/
│ │ │ │ │ │ └── VersionedOGC.html
│ │ │ │ │ └── XML.html
│ │ │ │ ├── Format.html
│ │ │ │ ├── Geometry/
│ │ │ │ │ ├── Collection.html
│ │ │ │ │ ├── Curve.html
│ │ │ │ │ ├── LineString.html
│ │ │ │ │ ├── LinearRing.html
│ │ │ │ │ ├── MultiLineString.html
│ │ │ │ │ ├── MultiPoint.html
│ │ │ │ │ ├── MultiPolygon.html
│ │ │ │ │ ├── Point.html
│ │ │ │ │ └── Polygon.html
│ │ │ │ ├── Geometry.html
│ │ │ │ ├── Handler/
│ │ │ │ │ ├── Box.html
│ │ │ │ │ ├── Click.html
│ │ │ │ │ ├── Drag.html
│ │ │ │ │ ├── Feature.html
│ │ │ │ │ ├── Hover.html
│ │ │ │ │ ├── Keyboard.html
│ │ │ │ │ ├── MouseWheel.html
│ │ │ │ │ ├── Path.html
│ │ │ │ │ ├── Pinch.html
│ │ │ │ │ ├── Point.html
│ │ │ │ │ ├── Polygon.html
│ │ │ │ │ └── RegularPolygon.html
│ │ │ │ ├── Handler.html
│ │ │ │ ├── Icon.html
│ │ │ │ ├── Kinetic.html
│ │ │ │ ├── Lang.html
│ │ │ │ ├── Layer/
│ │ │ │ │ ├── ArcGIS93Rest.html
│ │ │ │ │ ├── ArcGISCache.html
│ │ │ │ │ ├── ArcGISCache.json
│ │ │ │ │ ├── ArcIMS.html
│ │ │ │ │ ├── Bing.html
│ │ │ │ │ ├── EventPane.html
│ │ │ │ │ ├── FixedZoomLevels.html
│ │ │ │ │ ├── GeoRSS.html
│ │ │ │ │ ├── Google/
│ │ │ │ │ │ └── v3.html
│ │ │ │ │ ├── Grid.html
│ │ │ │ │ ├── HTTPRequest.html
│ │ │ │ │ ├── Image.html
│ │ │ │ │ ├── KaMap.html
│ │ │ │ │ ├── MapGuide.html
│ │ │ │ │ ├── MapServer.html
│ │ │ │ │ ├── Markers.html
│ │ │ │ │ ├── OSM.html
│ │ │ │ │ ├── PointGrid.html
│ │ │ │ │ ├── PointTrack.html
│ │ │ │ │ ├── SphericalMercator.html
│ │ │ │ │ ├── TMS.html
│ │ │ │ │ ├── Text.html
│ │ │ │ │ ├── TileCache.html
│ │ │ │ │ ├── UTFGrid.html
│ │ │ │ │ ├── Vector/
│ │ │ │ │ │ └── RootContainer.html
│ │ │ │ │ ├── Vector.html
│ │ │ │ │ ├── WMS.html
│ │ │ │ │ ├── WMTS.html
│ │ │ │ │ ├── WrapDateLine.html
│ │ │ │ │ ├── XYZ.html
│ │ │ │ │ ├── atom-1.0.xml
│ │ │ │ │ ├── data_Layer_Text_textfile.txt
│ │ │ │ │ ├── data_Layer_Text_textfile_2.txt
│ │ │ │ │ ├── data_Layer_Text_textfile_overflow.txt
│ │ │ │ │ └── georss.txt
│ │ │ │ ├── Layer.html
│ │ │ │ ├── Map.html
│ │ │ │ ├── Marker/
│ │ │ │ │ └── Box.html
│ │ │ │ ├── Marker.html
│ │ │ │ ├── OLLoader.js
│ │ │ │ ├── OpenLayers1.html
│ │ │ │ ├── OpenLayers2.html
│ │ │ │ ├── OpenLayers3.html
│ │ │ │ ├── OpenLayers4.html
│ │ │ │ ├── OpenLayersJsFiles.html
│ │ │ │ ├── Popup/
│ │ │ │ │ ├── Anchored.html
│ │ │ │ │ └── FramedCloud.html
│ │ │ │ ├── Popup.html
│ │ │ │ ├── Projection.html
│ │ │ │ ├── Protocol/
│ │ │ │ │ ├── CSW.html
│ │ │ │ │ ├── HTTP.html
│ │ │ │ │ ├── SOS.html
│ │ │ │ │ ├── Script.html
│ │ │ │ │ └── WFS.html
│ │ │ │ ├── Protocol.html
│ │ │ │ ├── README.txt
│ │ │ │ ├── Renderer/
│ │ │ │ │ ├── Canvas.html
│ │ │ │ │ ├── Elements.html
│ │ │ │ │ ├── SVG.html
│ │ │ │ │ └── VML.html
│ │ │ │ ├── Renderer.html
│ │ │ │ ├── Request/
│ │ │ │ │ └── XMLHttpRequest.html
│ │ │ │ ├── Request.html
│ │ │ │ ├── Rule.html
│ │ │ │ ├── SingleFile1.html
│ │ │ │ ├── SingleFile2.html
│ │ │ │ ├── SingleFile3.html
│ │ │ │ ├── Strategy/
│ │ │ │ │ ├── BBOX.html
│ │ │ │ │ ├── Cluster.html
│ │ │ │ │ ├── Filter.html
│ │ │ │ │ ├── Fixed.html
│ │ │ │ │ ├── Paging.html
│ │ │ │ │ ├── Refresh.html
│ │ │ │ │ └── Save.html
│ │ │ │ ├── Strategy.html
│ │ │ │ ├── Style.html
│ │ │ │ ├── Style2.html
│ │ │ │ ├── StyleMap.html
│ │ │ │ ├── Symbolizer/
│ │ │ │ │ ├── Line.html
│ │ │ │ │ ├── Point.html
│ │ │ │ │ ├── Polygon.html
│ │ │ │ │ ├── Raster.html
│ │ │ │ │ └── Text.html
│ │ │ │ ├── Symbolizer.html
│ │ │ │ ├── Test.AnotherWay.baseadditions.js
│ │ │ │ ├── Test.AnotherWay.css
│ │ │ │ ├── Test.AnotherWay.geom_eq.js
│ │ │ │ ├── Test.AnotherWay.js
│ │ │ │ ├── Test.AnotherWay.xml_eq.js
│ │ │ │ ├── Tile/
│ │ │ │ │ ├── Image/
│ │ │ │ │ │ └── IFrame.html
│ │ │ │ │ ├── Image.html
│ │ │ │ │ └── UTFGrid.html
│ │ │ │ ├── Tile.html
│ │ │ │ ├── TileManager.html
│ │ │ │ ├── Tween.html
│ │ │ │ ├── Util/
│ │ │ │ │ └── vendorPrefix.html
│ │ │ │ ├── Util.html
│ │ │ │ ├── Util_common.js
│ │ │ │ ├── Util_w3c.html
│ │ │ │ ├── WPSClient.html
│ │ │ │ ├── WPSProcess.html
│ │ │ │ ├── atom-1.0.xml
│ │ │ │ ├── auto-tests.html
│ │ │ │ ├── data_Layer_Text_textfile.txt
│ │ │ │ ├── data_Layer_Text_textfile_2.txt
│ │ │ │ ├── data_Layer_Text_textfile_overflow.txt
│ │ │ │ ├── deprecated/
│ │ │ │ │ ├── Ajax.html
│ │ │ │ │ ├── BaseTypes/
│ │ │ │ │ │ ├── Class.html
│ │ │ │ │ │ └── Element.html
│ │ │ │ │ ├── Control/
│ │ │ │ │ │ └── MouseToolbar.html
│ │ │ │ │ ├── Geometry/
│ │ │ │ │ │ └── Rectangle.html
│ │ │ │ │ ├── Layer/
│ │ │ │ │ │ ├── GML.html
│ │ │ │ │ │ ├── MapServer/
│ │ │ │ │ │ │ └── Untiled.html
│ │ │ │ │ │ ├── MapServer.html
│ │ │ │ │ │ ├── WFS.html
│ │ │ │ │ │ ├── WMS/
│ │ │ │ │ │ │ └── Post.html
│ │ │ │ │ │ ├── WMS.html
│ │ │ │ │ │ ├── Yahoo.html
│ │ │ │ │ │ ├── mice.xml
│ │ │ │ │ │ └── owls.xml
│ │ │ │ │ ├── Popup/
│ │ │ │ │ │ └── AnchoredBubble.html
│ │ │ │ │ ├── Protocol/
│ │ │ │ │ │ ├── SQL/
│ │ │ │ │ │ │ └── Gears.html
│ │ │ │ │ │ └── SQL.html
│ │ │ │ │ ├── Renderer/
│ │ │ │ │ │ └── SVG2.html
│ │ │ │ │ ├── Tile/
│ │ │ │ │ │ └── WFS.html
│ │ │ │ │ └── Util.html
│ │ │ │ ├── georss.txt
│ │ │ │ ├── grid_inittiles.html
│ │ │ │ ├── index.html
│ │ │ │ ├── list-tests.html
│ │ │ │ ├── manual/
│ │ │ │ │ ├── ajax.html
│ │ │ │ │ ├── ajax.txt
│ │ │ │ │ ├── alloverlays-mixed.html
│ │ │ │ │ ├── arcims-2117.html
│ │ │ │ │ ├── arkansas.rss
│ │ │ │ │ ├── big-georss.html
│ │ │ │ │ ├── box-quirks.html
│ │ │ │ │ ├── box-strict.html
│ │ │ │ │ ├── clip-features-svg.html
│ │ │ │ │ ├── dateline-sketch.html
│ │ │ │ │ ├── dateline-smallextent.html
│ │ │ │ │ ├── draw-feature.html
│ │ │ │ │ ├── feature-handler.html
│ │ │ │ │ ├── geodesic.html
│ │ │ │ │ ├── geojson-geomcoll-reprojection.html
│ │ │ │ │ ├── google-fullscreen-overlay.html
│ │ │ │ │ ├── google-panning.html
│ │ │ │ │ ├── google-resize.html
│ │ │ │ │ ├── google-tilt.html
│ │ │ │ │ ├── google-v3-resize.html
│ │ │ │ │ ├── loadend.html
│ │ │ │ │ ├── map-events.html
│ │ │ │ │ ├── memory/
│ │ │ │ │ │ ├── Marker-2258.html
│ │ │ │ │ │ ├── PanZoom-2323.html
│ │ │ │ │ │ ├── RemoveChild-2170.html
│ │ │ │ │ │ └── VML-2170.html
│ │ │ │ │ ├── multiple-google-layers.html
│ │ │ │ │ ├── overviewmap-projection.html
│ │ │ │ │ ├── page-position.html
│ │ │ │ │ ├── pan-redraw-svg.html
│ │ │ │ │ ├── popup-keepInMap.html
│ │ │ │ │ ├── reflow.html
│ │ │ │ │ ├── renderedDimensions.html
│ │ │ │ │ ├── select-feature-right-click.html
│ │ │ │ │ ├── select-feature.html
│ │ │ │ │ ├── tiles-loading.html
│ │ │ │ │ ├── tween.html
│ │ │ │ │ ├── vector-features-performance.html
│ │ │ │ │ └── vector-layer-zindex.html
│ │ │ │ ├── mice.xml
│ │ │ │ ├── node.js/
│ │ │ │ │ ├── mockdom.js
│ │ │ │ │ ├── node-tests.cfg
│ │ │ │ │ ├── node.js
│ │ │ │ │ ├── run-test.js
│ │ │ │ │ └── run.sh
│ │ │ │ ├── owls.xml
│ │ │ │ ├── run-tests.html
│ │ │ │ ├── selenium/
│ │ │ │ │ └── remotecontrol/
│ │ │ │ │ ├── config.cfg
│ │ │ │ │ ├── selenium.py
│ │ │ │ │ ├── setup.txt
│ │ │ │ │ └── test_ol.py
│ │ │ │ ├── speed/
│ │ │ │ │ ├── geometry.html
│ │ │ │ │ ├── string_format.html
│ │ │ │ │ ├── vector-renderers.html
│ │ │ │ │ ├── vector-renderers.js
│ │ │ │ │ ├── wmc_speed.html
│ │ │ │ │ ├── wmscaps.html
│ │ │ │ │ ├── wmscaps.js
│ │ │ │ │ └── wmscaps.xml
│ │ │ │ └── throws.js
│ │ │ ├── theme/
│ │ │ │ └── default/
│ │ │ │ ├── google.css
│ │ │ │ ├── ie6-style.css
│ │ │ │ ├── style.css
│ │ │ │ └── style.mobile.css
│ │ │ └── tools/
│ │ │ ├── BeautifulSoup.py
│ │ │ ├── README.txt
│ │ │ ├── closure_library_jscompiler.py
│ │ │ ├── closure_ws.py
│ │ │ ├── exampleparser.py
│ │ │ ├── jsmin.c
│ │ │ ├── jsmin.py
│ │ │ ├── mergejs.py
│ │ │ ├── minimize.py
│ │ │ ├── oldot.py
│ │ │ ├── release.sh
│ │ │ ├── shrinksafe.py
│ │ │ ├── toposort.py
│ │ │ ├── uglify_js.py
│ │ │ └── update_dev_dir.sh
│ │ ├── css/
│ │ │ ├── ie-only.css
│ │ │ └── tatami.css
│ │ └── vendor/
│ │ ├── backgroundsize.min.htc
│ │ ├── css/
│ │ │ └── bootstrap/
│ │ │ ├── css/
│ │ │ │ └── bootstrap.css
│ │ │ ├── fonts/
│ │ │ │ └── glyphiconshalflings-regular.otf
│ │ │ └── js/
│ │ │ └── bootstrap.js
│ │ └── js/
│ │ ├── marked/
│ │ │ └── marked.js
│ │ └── respond/
│ │ └── respond.js
│ ├── css/
│ │ ├── ie-only.css
│ │ ├── tatami.css
│ │ └── vendor/
│ │ ├── backgroundsize.min.htc
│ │ ├── css/
│ │ │ ├── bootstrap.css
│ │ │ └── jQueryjGrowl.css
│ │ └── fonts/
│ │ └── glyphiconshalflings-regular.otf
│ ├── index.html
│ ├── index.html.tpl
│ ├── index.jsp
│ ├── robots.txt
│ └── sitemap.xml
└── test/
├── java/
│ └── fr/
│ └── ippon/
│ └── tatami/
│ └── web/
│ └── rest/
│ ├── GroupControllerTest.java
│ ├── TagControllerTest.java
│ ├── TimelineControllerTest.java
│ └── UserControllerTest.java
└── javascript/
└── webapp/
└── app/
└── components/
├── about/
│ └── license/
│ └── LicenseController_spec.js
├── account/
│ ├── PasswordModule_spec.js
│ └── preferences/
│ └── Preferences_spec.js
└── home/
└── status/
└── StatusController_spec.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
data
.idea
*.iml
tatami.iml
tatami.ipr
tatami.iws
.classpath
.project
.settings
target
node_modules/
web/node_modules/
src/main/webapp/WEB-INF/generated-wro4j
.merge_file*
.DS_Store
phantomjsdriver.log
*.log
web/src/main/webapp/app/**/*.CONCAT.js
web/src/main/webapp/app/**/*.min.html
web/src/main/webapp/app/**/*.min.js
web/src/main/webapp/app/**/*.MIN.css
web/src/main/webapp/app/**/*.min.css
web/src/main/webapp/css/tatami.min.css
src/main/webapp/app/shared/footer/FooterView.html.sed.del
================================================
FILE: CONTRIBUTING.md
================================================
Contributing to Tatami
=========================
Open Source
------------------
Tatami is an Open Source project, which uses the Apache 2 [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
license. If you contribute to Tatami, you agree that your code belongs to the Tatami project and follows this license.
Submitting code
------------------
* Create a [GitHub account](https://github.com/signup/free).
* [Submit a ticket for your issue](https://github.com/ippontech/tatami/issues), assuming one does not already exist.
* Clearly describe the issue including steps to reproduce it, when it is a bug.
* Fork the repository on GitHub.
* Make commits of logical units.
* Make sure your commit messages include the ticket number you have created. Github should automatically link
your changes with the ticket.
* Make sure you have added the necessary tests for your changes.
* Run _all_ the tests to assure nothing else was accidentally broken.
* Push your changes in your fork of the repository.
* Submit a pull request to [the repository in the ippontech organization](https://github.com/ippontech/tatami).
* If you need help about making a pull request, [here is the documentation](https://help.github.com/articles/using-pull-requests).
* Your code will be automatically built by [Buildhive](https://buildhive.cloudbees.com/job/ippontech/job/tatami/). Your
pull request should have a Buildhive comment a few minutes after your commit.
================================================
FILE: README.md
================================================
Tatami
================
Presentation
------------------
Tatami is an Open Source enterprise social network.
A public installation of Tatami is provided by [Ippon Technologies](http://www.ippon.fr) at : [https://tatami.ippon.fr](https://tatami.ippon.fr)
Tatami is made with the following technologies :
- HTML5, [AngularJS](https://angularjs.org/) and [Twitter Bootstrap](http://twitter.github.com/bootstrap/)
- [The Spring Framework](http://www.springsource.org/)
- [Apache Cassandra](http://cassandra.apache.org/)
- [Elastic Search](http://www.elasticsearch.org/)
Tatami is developed by [Ippon Technologies](http://www.ippon.fr)
Installation for developers
---------------------------------------
### 5 minute installation
- Clone, fork or download the source code from this Github page
- Install [Maven 3](http://maven.apache.org/)
- Install [npm](https://www.npmjs.com/)
- Point your terminal to the directory you cloned Tatami to.
- `cd web`
- Type `npm install`
- You may need to give root user permissions: `sudo !!`
- `cd ..`
- Run Cassandra with Maven : `mvn cassandra:run`
- Run Jetty from tatami/web with Maven: `mvn jetty:run`
- Connect to the application at http://127.0.0.1:8080
To create users, use the registration form. As we have not configured a SMTP server (you can configure it in src/main/resources/META-INF/tatami/tatami.properties - see below "installation for production use" for more options), the validation URL as well as the password will not be e-mailed to you, but you can see them in the log (look at the Jetty console output).
### Using Tomcat instead of Jetty
If you want to use Tomcat instead of Jetty (which works better in development mode on Windows), just use :
- Run Tomcat from Maven : `mvn tomcat7:run`
### Maven tuning and troubleshooting
If you run into some Permgen or OutOfMemory errors, you can configure your Maven settings accordingly :
```
export MAVEN_OPTS="-XX:PermSize=64m -XX:MaxPermSize=128m -Xms256m -Xmx1024m"
```
If you want to debug remotely the application with your IDE, set up your MAVEN_OPTS :
```
export MAVEN_OPTS="$MAVEN_OPTS -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"
```
### Cassandra troubleshooting
On Mac OS X, you should use JDK 6 and not JDK 7, see [issue #281](https://github.com/ippontech/tatami/issues/281#issuecomment-12430701).
How to Contribute
---------------------------------------
In order to assure code quality, Ippon manages the pull requests for the project, and upholds certain rules regarding how individuals may contribute.
You may find these rules in your Tatami installation in the file `CONTRIBUTING.md`.
Installation for production use
---------------------------------------
### Cassandra installation
- Download [Apache Cassandra](http://cassandra.apache.org/)
- Install Cassandra : the application will work fine with just one node, but ideally you should have a cluster with at least 3 or 5 nodes
- Cassandra is configured with its cassandra.yaml file : don't forget to backup your "data" and "commitlog" directories
### Tatami installation
In order to use a stable version, use one of the [available tags](https://github.com/ippontech/tatami/tags).
Tatami can be configured with the src/main/resources/META-INF/tatami/tatami.properties file. You can configure this file in 2 ways :
- Edit the file in your own Tatami fork
- Properties in this file are replaced at build time by Maven : you can set up your own Maven profile with your specific properties
Once Tatami is started, you will be able to check your properties at runtime in the Administration page.
To deploy Tatami :
- Create the Tatami WAR file : `mvn package`
- The WAR file will be called "root.war", as Tatami should be run as the root application (on the "/" Web context)
- Deploy the WAR file on your favorite Java EE server
- The WAR has been tested on Jetty 8 and Tomcat 7, and should work fine on all Java EE servers
Upgrading from a previous version
---------------------------------------
Upgrading is normally just a matter of using a newer version of the application.
Sometimes, you will need to update the Cassandra keyspace: upgrade scripts are available in the src/main/cql/upgrade directory.
Launching stress tests
---------------------------------------
Stress tests are done with [Apache JMeter](http://jmeter.apache.org/).
- Launch Cassandra
- Run Tatami from Maven with the `stress-tests` profile : `mvn jetty:run -Pstress-tests`
- Launch JMeter
- Run the `src/test/jmeter/tatami-create-users.jmx` script : it will create 200 normal users, which each has 200 follower users
- Run the stress test : `src/test/jmeter/tatami-stress-test.jmx`
Launching functional tests
---------------------------------------
Functional tests are a work in progress, you do not have to run them in order to use the application.
Requirement : all components must run on localhost :
- for LDAP authentication, the tests starts the LDAP server that the Tatami server will use
- for fixture setup and assertions, the test connects directly to the local cassandra
Launching UI Tests from maven :
- add this profile on your settings.xml :
```xml
<profile>
<id>tatami</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<webdriver.chrome.driver>C:\path\to\chromedriver.exe</webdriver.chrome.driver><!--optional-->
<google.password>xxxx</google.password>
<google.email>xxx@xxx.fr</google.email>
</properties>
</profile>
```
- Run Maven with this command : `mvn clean verify -Puitest`
Launching UI Tests from maven with Chrome :
- install ChromeDriver in your system
- configure the property "webdriver.chrome.driver" in your settings pointing to your chrome driver install directory
- add `-Dgeb.env=chrome` to the maven command above
Launching UI Tests from your IDE :
- Enable a groovy plugin on your IDE
- Activate maven profile "uitest" or add src/integration/* in your classpath
- Run Tatami with Maven : `mvn cassandra:delete cassandra:start jetty:run -Djetty.scanIntervalSeconds=0 -Puitest`
- Run Specs (in src\integration\java\fr\ippon\tatami\uitest) as Junit Tests from your IDE
=> you have to set adequate system properties to your running configurations (the same as those that are necessary in setting.xml for maven : see above)
Thanks
------
Jetbrains is providing us free [Intellij IDEA](http://www.jetbrains.com/idea/) licenses,
which definitely allows us to be more productive and have more fun on the project!
YourKit is kindly supporting open source projects with its full-featured Java Profiler.
YourKit, LLC is the creator of innovative and intelligent tools for profiling
Java and .NET applications. Take a look at YourKit's leading software products:
[YourKit Java Profiler](http://www.yourkit.com/java/profiler/index.jsp) and
[YourKit .NET Profiler](http://www.yourkit.com/.net/profiler/index.jsp).
License
-------
Copyright © 2012-2015 [Ippon Technologies](http://www.ippon.fr)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this application except in compliance with the License.
You may obtain a copy of the License at
[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: etc/installation/ubuntu/files/maven/settings.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>/opt/tatami/maven/repository</localRepository>
<pluginGroups></pluginGroups>
<proxies></proxies>
<servers></servers>
<mirrors></mirrors>
<profiles></profiles>
<!-- activeProfiles
| List of profiles that are active for all builds.
|
<activeProfiles>
<activeProfile>alwaysActiveProfile</activeProfile>
<activeProfile>anotherAlwaysActiveProfile</activeProfile>
</activeProfiles>
-->
</settings>
================================================
FILE: etc/installation/ubuntu/install.sh
================================================
#!/bin/sh
#
# description: Installs Tatami on Ubuntu
# This script must be run by the "root" user.
# Run this script directly by typing :
# curl -L https://github.com/ippontech/tatami/raw/master/etc/installation/ubuntu/install.sh | sudo bash
#
# - Tatami is installed in the "/opt/tatami" directory
# - Tatami is run by the "tatami" user
#
echo "Welcome to the Tatami installer"
#################################
# Variables
#################################
echo "Setting up variables"
export USER=tatami
export TATAMI_DIR=/opt/tatami
export MAVEN_VERSION=3.0.4
export JETTY_VERSION=8.1.8.v20121106
#################################
# Install missing packages
#################################
echo "Installing missing packages"
apt-get install git-core curl wget -y --force-yes
#################################
# Install Java
#################################
wget https://github.com/flexiondotorg/oab-java6/raw/0.2.6/oab-java.sh -O oab-java.sh
chmod +x oab-java.sh
sudo ./oab-java.sh
rm oab-java.sh
sudo apt-get install sun-java6-jdk -y
#################################
# Create directories & users
#################################
echo "Creating directories and users"
useradd -m -s /bin/bash $USER
mkdir -p $TATAMI_DIR
mkdir -p $TATAMI_DIR/application
mkdir -p $TATAMI_DIR/maven
mkdir -p $TATAMI_DIR/data
mkdir -p $TATAMI_DIR/data/elasticsearch
mkdir -p $TATAMI_DIR/log
mkdir -p $TATAMI_DIR/log/elasticsearch
#################################
## Download Application
#################################
echo "Getting the application from Github"
cd $TATAMI_DIR/application
git clone https://github.com/ippontech/tatami.git
#################################
## Install Cassandra
#################################
cd $TATAMI_DIR
echo "Installing JNA"
sudo apt-get install libjna-java -y
echo "Configuring OS limits"
cp /etc/security/limits.conf /etc/security/limits.conf.original
echo "* soft nofile 32768" | sudo tee -a /etc/security/limits.conf
echo "* hard nofile 32768" | sudo tee -a /etc/security/limits.conf
echo "root soft nofile 32768" | sudo tee -a /etc/security/limits.conf
echo "root hard nofile 32768" | sudo tee -a /etc/security/limits.conf
echo "* soft nofile 32768" >> /etc/security/limits.conf
echo "* hard nofile 32768" >> /etc/security/limits.conf
echo "root soft nofile 32768" >> /etc/security/limits.conf
echo "root hard nofile 32768" >> /etc/security/limits.conf
echo "* soft memlock unlimited" >> /etc/security/limits.conf
echo "* hard memlock unlimited" >> /etc/security/limits.conf
echo "root soft memlock unlimited" >> /etc/security/limits.conf
echo "root hard memlock unlimited" >> /etc/security/limits.conf
echo "* soft as unlimited" >> /etc/security/limits.conf
echo "* hard as unlimited" >> /etc/security/limits.conf
echo "root soft as unlimited" >> /etc/security/limits.conf
echo "root hard as unlimited" >> /etc/security/limits.conf
sysctl -w vm.max_map_count=131072
sudo swapoff --all
# Cassandra Installation
echo "Installing Cassandra"
echo "deb http://debian.datastax.com/community stable main" >> /etc/apt/sources.list
curl -L http://debian.datastax.com/debian/repo_key | sudo apt-key add -
sudo apt-get update
sudo apt-get install python-cql dsc1.1 -y
sudo apt-get install opscenter-free -y
sudo service opscenterd start
#################################
## Install Jetty
#################################
echo "Installing Jetty"
cd $TATAMI_DIR
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 16384 16777216"
sysctl -w net.core.somaxconn=4096
sysctl -w net.core.netdev_max_backlog=16384
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
sysctl -w net.ipv4.tcp_syncookies=1
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
sysctl -w net.ipv4.tcp_tw_recycle=1
sysctl -w net.ipv4.tcp_congestion_control=cubic
wget http://central.maven.org/maven2/org/mortbay/jetty/dist/jetty-deb/$JETTY_VERSION/jetty-deb-$JETTY_VERSION.deb
dpkg -i jetty-deb-$JETTY_VERSION.deb
rm -f jetty-deb-$JETTY_VERSION.deb
rm -rf /opt/jetty/webapps/*
#################################
## Install Maven
#################################
echo "Installing Maven"
cd $TATAMI_DIR/maven
wget http://mirrors.linsrv.net/apache/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz
tar -xzf apache-maven-$MAVEN_VERSION-bin.tar.gz
rm -f apache-maven-$MAVEN_VERSION-bin.tar.gz
ln -s $TATAMI_DIR/maven/apache-maven-$MAVEN_VERSION $TATAMI_DIR/maven/current
# Configure Maven for the tatami user
echo "# Begin tatami configuration" >> /home/tatami/.profile
echo "export M2_HOME=/opt/tatami/maven/current" >> /home/tatami/.profile
echo "export PATH=/opt/tatami/maven/current/bin:$PATH" >> /home/tatami/.profile
echo "export MAVEN_OPTS=\"-XX:MaxPermSize=64m -Xms256m -Xmx1024m\"" >> /home/tatami/.profile
echo "# End tatami configuration" >> /home/tatami/.profile
# Configure Maven repository
mkdir -p $TATAMI_DIR/maven/repository
cp $TATAMI_DIR/application/tatami/etc/installation/ubuntu/files/maven/settings.xml $TATAMI_DIR/maven/apache-maven-$MAVEN_VERSION/conf
#################################
## Install & run Application
#################################
chown -R $USER $TATAMI_DIR
./update.sh
#################################
## Post install
#################################
================================================
FILE: etc/installation/ubuntu/uninstall.sh
================================================
#!/bin/sh
#
# description: Uninstalls Tatami on Ubuntu
# This script must be run by the "root" user.
#
# Run this script directly by typing :
# curl -L https://github.com/ippontech/tatami/raw/master/etc/installation/ubuntu/uninstall.sh | sudo bash
#
# - Deletes the "/opt/tatami"
# - Deletes the "tatami" user
echo "Tatami uninstaller"
mv /etc/security/limits.conf.original /etc/security/limits.conf
userdel -f -r tatami
echo "Delete Tatami directory"
rm -rf /opt/tatami
================================================
FILE: etc/installation/ubuntu/update.sh
================================================
#!/bin/sh
#
# description: Updates Tatami from Git
# This script must be run by the "tatami" user, who must be a sudoer.
echo "Welcome to the Tatami updater"
#################################
# Variables
#################################
echo "Setting up variables"
export USER=tatami
export TATAMI_DIR=/opt/tatami
#################################
# Update application
#################################
cd $TATAMI_DIR/application/tatami
git pull
cd /opt/tatami/application/tatami && mvn -Pprod -DskipTests clean package
sudo /etc/init.d/jetty stop
sudo cp /opt/tatami/application/tatami/target/root.war /opt/jetty/webapps/root.war
sudo /etc/init.d/jetty start
================================================
FILE: jenkinsScripts/insertGoogleAuthKeys.sh
================================================
#!/bin/bash
#Insert google auth variables into the build.
googleKey=$1
googleSecret=$2
newServer=$3
usage='startTatami <googleKey> <googleSecret> <serverURL>'
if [ "$#" -ne 3 ]; then
echo "Need 3 paremeters"
echo "$usage"
exit 1
fi
replaceKey='${tatami.google.clientId}'
replaceSecret='${tatami.google.clientSecret}'
oldServer="<tatami.url>http:\/\/localhost:8080<\/tatami.url>"
find ../src -name *security.xml | xargs sed -i "s/$replaceSecret/$googleSecret/g"
find ../src -name *security.xml | xargs sed -i "s/$replaceKey/$googleKey/g"
sed -i "s/$oldServer/$newServer/g" ../pom.xml
================================================
FILE: jenkinsScripts/restoreDatabase.sh
================================================
#!/bin/bash
rm -rf ../target/cassandra || true
rm -rf ./target/elasticsearch || true
tar -zxvf save.tar.gz -C ../target/
tar -zxvf db.tar.gz -C ./target/
rm -f save.tar.gz || true
================================================
FILE: jenkinsScripts/saveDatabase.sh
================================================
#!/bin/bash
tar -zcvf save.tar.gz ../target/cassandra ../target/elasticsearch
tar -zcvf db.tar.gz ./target/elasticsearch
================================================
FILE: jenkinsScripts/startTatami.sh
================================================
#!/bin/bash
#Insert google Authentication keys.
./insertGoogleAuthKeys.sh $1 $2 $3
if [ $? -ne 0 ]; then
exit 1
fi
#Start cassandra
mvn -f ../pom.xml cassandra:run 2> cassandra.error >cassandra.log &
echo "$!" >tatamiPID
#start jetty
mvn -f ../pom.xml jetty:run 2> jetty.error >jetty.log &
echo "$!" >> tatamiPID
================================================
FILE: jenkinsScripts/stopTatami.sh
================================================
#!/bin/bash
cat tatamiPID | xargs kill || true
rm tatamiPID || true
================================================
FILE: mobile/.bowerrc
================================================
{
"directory": "www/lib"
}
================================================
FILE: mobile/.editorconfig
================================================
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
================================================
FILE: mobile/.gitignore
================================================
# Specifies intentionally untracked files to ignore when using Git
# http://git-scm.com/docs/gitignore
www/lib/
node_modules/
platforms/
plugins/
================================================
FILE: mobile/README.md
================================================
Tatami Mobile Beta
==================
If interested in the mobile beta, follow these steps:
Prepare Project
---------------
- Clone, fork or download the source code from this Github page
- Install [Maven](http://maven.apache.org/)
- Install [Ionic](http://ionicframework.com/)
- `npm install -g cordova ionic`
- Point your terminal to the directory you cloned Tatami to.
- `cd mobile`
- Run Maven : `mvn -Pmobile-prod install`
Deploy to Device
----------------
### iOS
- Open Xcode
- Open `tatami/mobile/platforms/ios/Tatami.xcodeproj`
- Connect device
- Click play on top left
### Android
- Connect device
- Run the following command
- `ionic build android && ionic run android`
================================================
FILE: mobile/bower.json
================================================
{
"name": "tatami",
"private": "true",
"devDependencies": {
"ionic": "~1.2.4",
"angular-mocks": "1.4.3",
"angular-marked": "~1.0.1",
"angular-animate": "~1.5.3",
"angular-sanitize": "~1.5.3",
"angular-resource": "~1.5.3",
"ngCordova": "~0.1.24-alpha",
"angular-translate": "~2.11.0",
"angular-translate-interpolation-messageformat": "~2.11.0",
"angular-translate-loader-partial": "~2.11.0",
"messageformat": "~0.3.1"
},
"resolutions": {
"angular-sanitize": "~1.5.3",
"angular-animate": "~1.5.3",
"ionic-toast": "v0.2.0"
},
"dependencies": {
"ionic-toast": "^0.4.1"
}
}
================================================
FILE: mobile/config.xml
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<widget id="com.ippon.tatami.mobile" version="1.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>Tatami</name>
<description>
The Tatami mobile app is designed to access the Tatami API, and it is an open source, enterprise social media platform.
</description>
<author email="tatami-dev@ippon.fr">
Ippon Technology, Inc
</author>
<content src="index.html"/>
<access origin="*"/>
<preference name="webviewbounce" value="false"/>
<preference name="UIWebViewBounce" value="false"/>
<preference name="DisallowOverscroll" value="true"/>
<preference name="android-minSdkVersion" value="16"/>
<preference name="BackupWebStorage" value="none"/>
<preference name="SplashScreen" value="screen"/>
<preference name="SplashScreenDelay" value="3000"/>
<feature name="StatusBar">
<param name="ios-package" value="CDVStatusBar" onload="true"/>
</feature>
<platform name="ios">
<icon src="resources/ios/icon/icon.png" width="57" height="57"/>
<icon src="resources/ios/icon/icon@2x.png" width="114" height="114"/>
<icon src="resources/ios/icon/icon-40.png" width="40" height="40"/>
<icon src="resources/ios/icon/icon-40@2x.png" width="80" height="80"/>
<icon src="resources/ios/icon/icon-50.png" width="50" height="50"/>
<icon src="resources/ios/icon/icon-50@2x.png" width="100" height="100"/>
<icon src="resources/ios/icon/icon-60.png" width="60" height="60"/>
<icon src="resources/ios/icon/icon-60@2x.png" width="120" height="120"/>
<icon src="resources/ios/icon/icon-60@3x.png" width="180" height="180"/>
<icon src="resources/ios/icon/icon-72.png" width="72" height="72"/>
<icon src="resources/ios/icon/icon-72@2x.png" width="144" height="144"/>
<icon src="resources/ios/icon/icon-76.png" width="76" height="76"/>
<icon src="resources/ios/icon/icon-76@2x.png" width="152" height="152"/>
<icon src="resources/ios/icon/icon-small.png" width="29" height="29"/>
<icon src="resources/ios/icon/icon-small@2x.png" width="58" height="58"/>
<icon src="resources/ios/icon/icon-small@3x.png" width="87" height="87"/>
<splash src="resources/ios/splash/Default-568h@2x~iphone.png" width="640" height="1136"/>
<splash src="resources/ios/splash/Default-667h.png" width="750" height="1334"/>
<splash src="resources/ios/splash/Default-736h.png" width="1242" height="2208"/>
<splash src="resources/ios/splash/Default-Landscape-736h.png" width="2208" height="1242"/>
<splash src="resources/ios/splash/Default-Landscape@2x~ipad.png" width="2048" height="1536"/>
<splash src="resources/ios/splash/Default-Landscape~ipad.png" width="1024" height="768"/>
<splash src="resources/ios/splash/Default-Portrait@2x~ipad.png" width="1536" height="2048"/>
<splash src="resources/ios/splash/Default-Portrait~ipad.png" width="768" height="1024"/>
<splash src="resources/ios/splash/Default@2x~iphone.png" width="640" height="960"/>
<splash src="resources/ios/splash/Default~iphone.png" width="320" height="480"/>
</platform>
<platform name="android">
<icon src="resources/android/icon/drawable-ldpi-icon.png" density="ldpi"/>
<icon src="resources/android/icon/drawable-mdpi-icon.png" density="mdpi"/>
<icon src="resources/android/icon/drawable-hdpi-icon.png" density="hdpi"/>
<icon src="resources/android/icon/drawable-xhdpi-icon.png" density="xhdpi"/>
<icon src="resources/android/icon/drawable-xxhdpi-icon.png" density="xxhdpi"/>
<icon src="resources/android/icon/drawable-xxxhdpi-icon.png" density="xxxhdpi"/>
<splash src="resources/android/splash/drawable-land-ldpi-screen.png" density="land-ldpi"/>
<splash src="resources/android/splash/drawable-land-mdpi-screen.png" density="land-mdpi"/>
<splash src="resources/android/splash/drawable-land-hdpi-screen.png" density="land-hdpi"/>
<splash src="resources/android/splash/drawable-land-xhdpi-screen.png" density="land-xhdpi"/>
<splash src="resources/android/splash/drawable-land-xxhdpi-screen.png" density="land-xxhdpi"/>
<splash src="resources/android/splash/drawable-land-xxxhdpi-screen.png" density="land-xxxhdpi"/>
<splash src="resources/android/splash/drawable-port-ldpi-screen.png" density="port-ldpi"/>
<splash src="resources/android/splash/drawable-port-mdpi-screen.png" density="port-mdpi"/>
<splash src="resources/android/splash/drawable-port-hdpi-screen.png" density="port-hdpi"/>
<splash src="resources/android/splash/drawable-port-xhdpi-screen.png" density="port-xhdpi"/>
<splash src="resources/android/splash/drawable-port-xxhdpi-screen.png" density="port-xxhdpi"/>
<splash src="resources/android/splash/drawable-port-xxxhdpi-screen.png" density="port-xxxhdpi"/>
</platform>
<icon src="resources/android/icon/drawable-xhdpi-icon.png"/>
</widget>
================================================
FILE: mobile/gulpfile.js
================================================
var gulp = require('gulp');
var gutil = require('gulp-util');
var bower = require('bower');
var concat = require('gulp-concat');
var sass = require('gulp-sass');
var minifyCss = require('gulp-minify-css');
var rename = require('gulp-rename');
var sh = require('shelljs');
var replace = require('replace');
var paths = {
sass: ['./scss/**/*.scss'],
css: ['./www/css/*.css']
};
gulp.task('default', ['sass', 'css']);
gulp.task('sass', function(done) {
gulp.src('./scss/ionic.app.scss')
.pipe(sass())
.on('error', sass.logError)
.pipe(gulp.dest('./www/css/'))
.pipe(minifyCss({
keepSpecialComments: 0
}))
.pipe(rename({ extname: '.min.css' }))
.pipe(gulp.dest('./www/css/'))
.on('end', done);
});
gulp.task('css', function(done) {
gulp.src('./www/css/style.css')
.pipe(minifyCss({
keepSpecialComments: 0
}))
.pipe(rename({ extname: '.min.css' }))
.pipe(gulp.dest('./www/css/'))
.on('end', done);
});
gulp.task('watch', function() {
gulp.watch(paths.sass, ['sass']);
gulp.watch(paths.css, ['css']);
});
gulp.task('install', ['git-check'], function() {
return bower.commands.install()
.on('log', function(data) {
gutil.log('bower', gutil.colors.cyan(data.id), data.message);
});
});
gulp.task('git-check', function(done) {
if (!sh.which('git')) {
console.log(
' ' + gutil.colors.red('Git is not installed.'),
'\n Git, the version control system, is required to download Ionic.',
'\n Download git here:', gutil.colors.cyan('http://git-scm.com/downloads') + '.',
'\n Once git is installed, run \'' + gutil.colors.cyan('gulp install') + '\' again.'
);
process.exit(1);
}
done();
});
var replaceFiles = ['./www/app/tatami.endpoint.js'];
gulp.task('dev', function() {
return replace({
regex: 'http://tatami.ippon.fr|http://10.1.10.202:8100',
replacement: 'http://localhost:8100',
paths: replaceFiles,
recursive: false,
silent: false
});
});
gulp.task('device-dev', function() {
return replace({
regex: 'http://localhost:8100|http://tatami.ippon.fr',
replacement: 'http://10.1.10.202:8100',
paths: replaceFiles,
recursive: false,
silent: false
});
});
gulp.task('prod', function() {
return replace({
regex: 'http://localhost:8100|http://10.1.10.202:8100',
replacement: 'http://tatami.ippon.fr',
paths: replaceFiles,
recursive: false,
silent: false
});
});
================================================
FILE: mobile/hooks/README.md
================================================
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
-->
# Cordova Hooks
This directory may contain scripts used to customize cordova commands. This
directory used to exist at `.cordova/hooks`, but has now been moved to the
project root. Any scripts you add to these directories will be executed before
and after the commands corresponding to the directory name. Useful for
integrating your own build systems or integrating with version control systems.
__Remember__: Make your scripts executable.
## Hook Directories
The following subdirectories will be used for hooks:
after_build/
after_compile/
after_docs/
after_emulate/
after_platform_add/
after_platform_rm/
after_platform_ls/
after_plugin_add/
after_plugin_ls/
after_plugin_rm/
after_plugin_search/
after_prepare/
after_run/
after_serve/
before_build/
before_compile/
before_docs/
before_emulate/
before_platform_add/
before_platform_rm/
before_platform_ls/
before_plugin_add/
before_plugin_ls/
before_plugin_rm/
before_plugin_search/
before_prepare/
before_run/
before_serve/
pre_package/ <-- Windows 8 and Windows Phone only.
## Script Interface
All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables:
* CORDOVA_VERSION - The version of the Cordova-CLI.
* CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios).
* CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer)
* CORDOVA_HOOK - Path to the hook that is being executed.
* CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate)
If a script returns a non-zero exit code, then the parent cordova command will be aborted.
## Writing hooks
We highly recommend writting your hooks using Node.js so that they are
cross-platform. Some good examples are shown here:
[http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/)
================================================
FILE: mobile/hooks/after_prepare/010_add_platform_class.js
================================================
#!/usr/bin/env node
// Add Platform Class
// v1.0
// Automatically adds the platform class to the body tag
// after the `prepare` command. By placing the platform CSS classes
// directly in the HTML built for the platform, it speeds up
// rendering the correct layout/style for the specific platform
// instead of waiting for the JS to figure out the correct classes.
var fs = require('fs');
var path = require('path');
var rootdir = process.argv[2];
function addPlatformBodyTag(indexPath, platform) {
// add the platform class to the body tag
try {
var platformClass = 'platform-' + platform;
var cordovaClass = 'platform-cordova platform-webview';
var html = fs.readFileSync(indexPath, 'utf8');
var bodyTag = findBodyTag(html);
if(!bodyTag) return; // no opening body tag, something's wrong
if(bodyTag.indexOf(platformClass) > -1) return; // already added
var newBodyTag = bodyTag;
var classAttr = findClassAttr(bodyTag);
if(classAttr) {
// body tag has existing class attribute, add the classname
var endingQuote = classAttr.substring(classAttr.length-1);
var newClassAttr = classAttr.substring(0, classAttr.length-1);
newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote;
newBodyTag = bodyTag.replace(classAttr, newClassAttr);
} else {
// add class attribute to the body tag
newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">');
}
html = html.replace(bodyTag, newBodyTag);
fs.writeFileSync(indexPath, html, 'utf8');
process.stdout.write('add to body class: ' + platformClass + '\n');
} catch(e) {
process.stdout.write(e);
}
}
function findBodyTag(html) {
// get the body tag
try{
return html.match(/<body(?=[\s>])(.*?)>/gi)[0];
}catch(e){}
}
function findClassAttr(bodyTag) {
// get the body tag's class attribute
try{
return bodyTag.match(/ class=["|'](.*?)["|']/gi)[0];
}catch(e){}
}
if (rootdir) {
// go through each of the platform directories that have been prepared
var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []);
for(var x=0; x<platforms.length; x++) {
// open up the index.html file at the www root
try {
var platform = platforms[x].trim().toLowerCase();
var indexPath;
if(platform == 'android') {
indexPath = path.join('platforms', platform, 'assets', 'www', 'index.html');
} else {
indexPath = path.join('platforms', platform, 'www', 'index.html');
}
if(fs.existsSync(indexPath)) {
addPlatformBodyTag(indexPath, platform);
}
} catch(e) {
process.stdout.write(e);
}
}
}
================================================
FILE: mobile/ionic.project
================================================
{
"name": "mobile",
"app_id": "",
"proxies": [
{
"path": "/tatami",
"proxyUrl": "http://localhost:8080/tatami"
},
{
"path": "/assets",
"proxyUrl": "http://localhost:8080/assets"
}
],
"gulpStartupTasks": [
"sass",
"watch"
],
"watchPatterns": [
"www/**/*",
"!www/lib/**/*"
]
}
================================================
FILE: mobile/karma.ci.conf.js
================================================
// Karma configuration
// Generated on Wed May 06 2015 15:23:11 GMT-0400 (EDT)
module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
"www/lib/ionic/release/js/ionic.bundle.js",
"www/lib/ionic/js/angular/angular-resource.js",
"www/lib/angular-mocks/angular-mocks.js",
"www/test/javascript/**/*.js"
],
// list of files to exclude
exclude: [
'**/*.swp'
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/**/*.js': ['coverage']
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['dots', 'jenkins', 'coverage', 'progress'],
jenkinsReporter: {
outputFile: 'target/test-results/karma/TESTS-resuts.xml'
},
coverageReporter: {
dir: 'target/test-results/coverage',
reporters: [
{type: 'lcov', subdir: 'report-lcov'}
]
},
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['PhantomJS'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true
});
};
================================================
FILE: mobile/package.json
================================================
{
"name": "mobile",
"version": "1.1.1",
"description": "mobile: An Ionic project",
"dependencies": {
"gulp": "^3.5.6",
"gulp-concat": "^2.2.0",
"gulp-minify-css": "^0.3.0",
"gulp-rename": "^1.2.0",
"gulp-sass": "^2.0.4",
"replace": "^0.3.0"
},
"devDependencies": {
"bower": "^1.3.3",
"gulp-util": "^2.2.14",
"karma": "^0.13.19",
"karma-jasmine": "^0.3.6",
"jasmine-core": "^2.3.4",
"karma-chrome-launcher": "^0.2.0",
"karma-cli": "^0.1.1",
"karma-coverage": "^0.5.2",
"karma-firefox-launcher": "^0.1.6",
"karma-ie-launcher": "^0.2.0",
"karma-jenkins-reporter": "0.0.2",
"karma-jshint": "^0.1.0",
"karma-junit-reporter": "^0.3.6",
"karma-phantomjs-launcher": "^0.2.1",
"karma-safari-launcher": "^0.1.1",
"phantomjs": "^1.9.18",
"shelljs": "^0.3.0"
},
"cordovaPlugins": [
"cordova-plugin-device",
"cordova-plugin-console",
"cordova-plugin-splashscreen",
"cordova-plugin-statusbar",
"ionic-plugin-keyboard",
"cordova-plugin-inappbrowser",
"cordova-plugin-camera",
{
"locator": "https://github.com/apache/cordova-plugin-whitelist.git",
"id": "cordova-plugin-whitelist"
},
"cordova-plugin-file-transfer"
],
"cordovaPlatforms": [
"android",
"ios"
]
}
================================================
FILE: mobile/pom.xml
================================================
<?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">
<parent>
<artifactId>tatami</artifactId>
<groupId>fr.ippon.tatami</groupId>
<version>4.0.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mobile</artifactId>
<dependencies>
<dependency>
<groupId>fr.ippon.tatami</groupId>
<artifactId>services</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>fr.ippon.tatami</groupId>
<artifactId>services</artifactId>
<version>4.0.5</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>dev</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>gulp</id>
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${project.npm.bin}/gulp</executable>
<arguments>
<argument>dev</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>ionic</id>
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>ionic</executable>
<arguments>
<argument>serve</argument>
<argument>-l</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>device-dev</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${project.npm.bin}/gulp</executable>
<arguments>
<argument>device-dev</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>mobile-prod</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>gulp</id>
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${project.npm.bin}/gulp</executable>
<arguments>
<argument>prod</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>ionic</id>
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>ionic</executable>
<arguments>
<argument>build</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<finalName>tatami-mobile-${project.version}</finalName>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.6.1</version>
<configuration>
<filesets>
<fileset>
<directory>${project.basedir}/node_modules/</directory>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>install-npm-mobile-dependencies</id>
<phase>generate-sources</phase>
<configuration>
<executable>npm</executable>
<arguments>
<argument>install</argument>
</arguments>
</configuration>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.kelveden</groupId>
<artifactId>maven-karma-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
</executions>
<configuration>
<karmaExecutable>${project.basedir}/node_modules/.bin/karma</karmaExecutable>
<configFile>${project.basedir}/karma.ci.conf.js</configFile>
</configuration>
</plugin>
</plugins>
</build>
</project>
================================================
FILE: mobile/scss/ionic.app.scss
================================================
/*
To customize the look and feel of Ionic, you can override the variables
in ionic's _variables.scss file.
For example, you might change some of the default colors:
$light: #fff !default;
$stable: #f8f8f8 !default;
$positive: #387ef5 !default;
$calm: #11c1f3 !default;
$balanced: #33cd5f !default;
$energized: #ffc900 !default;
$assertive: #ef473a !default;
$royal: #886aea !default;
$dark: #444 !default;
*/
// The path for our ionicons font files, relative to the built CSS in www/css
$ionicons-font-path: "../lib/ionic/release/fonts" !default;
// Include all of Ionic
@import "../www/lib/ionic/release/css/ionic";
.platform-ios {
.tatami-location {
@extend .ion-ios-location;
}
}
.platform-android {
.tatami-location {
@extend .ion-android-locate;
}
}
.item-image i:last-child {
position: absolute;
border-radius: 50%;
width: 20px;
height: 20px;
background-color: black;
top: 15px;
right: 15px;
}
.link-span {
cursor: pointer;
color: #387ef5;
}
.center {
margin-left: auto;
margin-right: auto;
display: block;
}
p ul {
list-style-type: disc !important;
list-style-position: inside !important;
}
//#list ul {
// margin-top: 30px;
//}
//#list ul li {
// text-align: left;
// list-style: disc;
// margin: 10px 0px;
//}
================================================
FILE: mobile/www/app/components/follow/follow.html
================================================
<ion-view>
<ion-tabs class="tabs-icon-top tabs-color-active-positive">
<ion-tab title="{{ 'tab.suggested.title' | translate }}" icon-off="ion-ios-personadd-outline" icon-on="ion-ios-personadd" ui-sref="suggested">
<ion-nav-view name="suggested"></ion-nav-view>
</ion-tab>
<ion-tab title="{{ 'tab.following' | translate }}" icon-off="ion-ios-people-outline" icon-on="ion-ios-people" ui-sref="following">
<ion-nav-view name="following"></ion-nav-view>
</ion-tab>
<ion-tab title="{{ 'tab.follower' | translate }}" icon-off="ion-person-stalker" icon-on="ion-person-stalker" ui-sref="follower">
<ion-nav-view name="follower"></ion-nav-view>
</ion-tab>
</ion-tabs>
</ion-view>
================================================
FILE: mobile/www/app/components/follow/follow.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(followConfig);
followConfig.$inject = ['$stateProvider'];
function followConfig($stateProvider) {
$stateProvider
.state('follow', {
url: '/follow',
parent: 'tatami',
abstract: true,
templateUrl: 'app/components/follow/follow.html',
resolve: {
currentUser: getCurrentUser,
translatePartialLoader: getTranslatePartialLoader
}
});
getCurrentUser.$inject = ['ProfileService'];
function getCurrentUser(ProfileService) {
return ProfileService.get().$promise;
}
getTranslatePartialLoader.$inject = ['$translate', '$translatePartialLoader'];
function getTranslatePartialLoader($translate, $translatePartialLoader) {
$translatePartialLoader.addPart('follow');
return $translate.refresh();
}
}
})();
================================================
FILE: mobile/www/app/components/follow/follower/follower.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('FollowerCtrl', followerCtrl);
followerCtrl.$inject = ['followers', 'TatamiUserRefresherService', 'currentUser'];
function followerCtrl(followers, TatamiUserRefresherService, currentUser) {
var vm = this;
vm.followers = followers;
vm.getNewFollowers = getNewFollowers;
function getNewFollowers() {
TatamiUserRefresherService.refreshFollowers(currentUser).then(setUsers);
}
setUsers.$inject = ['followers'];
function setUsers(followers) {
vm.followers = followers;
}
}
})();
================================================
FILE: mobile/www/app/components/follow/follower/follower.html
================================================
<ion-view view-title="{{ 'tab.follower' | translate }}">
<ion-content class="tatami-header tatami-footer" ng-style="{'background-color':'#f5f5f5'}">
<ion-refresher on-refresh="vm.getNewFollowers()"></ion-refresher>
<ion-list>
<div ng-repeat="user in vm.followers">
<tatami-user user="user"></tatami-user>
</div>
</ion-list>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/follow/follower/follower.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('follower', {
url: '/follower',
parent: 'follow',
views: {
'follower': {
templateUrl: 'app/components/follow/follower/follower.html',
controller: 'FollowerCtrl',
controllerAs: 'vm'
}
},
resolve: {
followers: followers
}
});
}
followers.$inject = ['UserService', 'currentUser'];
function followers(UserService, currentUser) {
return UserService.getFollowers({ username: currentUser.username }).$promise;
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('follower', 'follow');
TatamiState.addConversationState('follower', 'follow');
TatamiState.addTagState('follower', 'follow');
}
})();
================================================
FILE: mobile/www/app/components/follow/following/following.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('FollowingCtrl', FollowingCtrl);
FollowingCtrl.$inject = ['following', 'TatamiUserRefresherService', 'currentUser'];
function FollowingCtrl(following, TatamiUserRefresherService, currentUser) {
var vm = this;
vm.following = following;
vm.getNewFollowing = getNewFollowing;
function getNewFollowing() {
TatamiUserRefresherService.refreshFollowing(currentUser).then(setUsers);
}
setUsers.$inject = ['following'];
function setUsers(following) {
vm.following = following;
}
}
})();
================================================
FILE: mobile/www/app/components/follow/following/following.html
================================================
<ion-view view-title="{{ 'tab.following' | translate }}">
<ion-content class="tatami-header tatami-footer" ng-style="{'background-color':'#f5f5f5'}">
<ion-refresher on-refresh="vm.getNewFollowing()"></ion-refresher>
<ion-list>
<div ng-repeat="user in vm.following">
<tatami-user user="user"></tatami-user>
</div>
</ion-list>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/follow/following/following.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('following', {
url: '/following',
parent: 'follow',
views: {
'following': {
templateUrl: 'app/components/follow/following/following.html',
controller: 'FollowingCtrl',
controllerAs: 'vm'
}
},
resolve: {
following: getFollowing
}
});
}
getFollowing.$inject = ['UserService', 'currentUser'];
function getFollowing(UserService, currentUser) {
return UserService.getFollowing({ username: currentUser.username }).$promise;
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('following', 'follow');
TatamiState.addConversationState('following', 'follow');
TatamiState.addTagState('following', 'follow');
}
})();
================================================
FILE: mobile/www/app/components/follow/suggested/suggested.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('SuggestedCtrl', suggestedCtrl);
suggestedCtrl.$inject = ['suggested', 'TatamiUserRefresherService'];
function suggestedCtrl(suggested, TatamiUserRefresherService) {
var vm = this;
vm.suggested = suggested;
vm.getNewSuggested = getNewSuggested;
function getNewSuggested() {
TatamiUserRefresherService.refreshSuggested().$promise.then(updateUsers);
}
updateUsers.$inject = ['suggested'];
function updateUsers(suggested) {
vm.suggested = suggested;
}
}
})();
================================================
FILE: mobile/www/app/components/follow/suggested/suggested.html
================================================
<ion-view view-title="{{ 'tab.suggested.who' | translate }}">
<ion-content class="tatami-header tatami-footer" ng-style="{'background-color':'#f5f5f5'}">
<ion-refresher on-refresh="vm.getNewSuggested()"></ion-refresher>
<ion-list>
<div ng-repeat="user in vm.suggested">
<tatami-user user="user"></tatami-user>
</div>
</ion-list>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/follow/suggested/suggested.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('suggested', {
url: '/suggested',
parent: 'follow',
views: {
'suggested': {
templateUrl: 'app/components/follow/suggested/suggested.html',
controller: 'SuggestedCtrl',
controllerAs: 'vm'
}
},
resolve: {
suggested: getSuggested
}
});
}
getSuggested.$inject = ['UserService'];
function getSuggested(UserService) {
return UserService.getSuggestions().$promise;
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('suggested', 'follow');
TatamiState.addConversationState('suggested', 'follow');
TatamiState.addTagState('suggested', 'follow');
}
})();
================================================
FILE: mobile/www/app/components/home/favorites/favorites.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('FavoritesCtrl', favoritesCtrl);
favoritesCtrl.$inject = ['favorites', 'currentUser', 'TatamiStatusRefresherService', '$q'];
function favoritesCtrl(favorites, currentUser, TatamiStatusRefresherService, $q) {
var vm = this;
vm.favorites = favorites;
vm.currentUser = currentUser;
vm.getNewStatuses = getNewStatuses;
vm.getEmpty = getEmpty;
function getNewStatuses() {
return TatamiStatusRefresherService.refreshFavorites();
}
getEmpty.$inject = ['finalStatus'];
function getEmpty(finalStatus) {
var deferred = $q.defer();
deferred.resolve([]);
return deferred.promise;
}
}
})();
================================================
FILE: mobile/www/app/components/home/favorites/favorites.html
================================================
<ion-view view-title="{{ 'tab.favorites' | translate }}" ng-style="{'background-color':'#f5f5f5'}">
<tatami-status-list statuses="vm.favorites"
current-user="vm.currentUser"
tatami-refresher="vm.getNewStatuses()"
tatami-infinite-refresher="vm.getEmpty(finalStatus)"></tatami-status-list>
</ion-view>
================================================
FILE: mobile/www/app/components/home/favorites/favorites.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('favorites', {
url: '/favorites',
parent: 'home',
views: {
'favorites': {
templateUrl: 'app/components/home/favorites/favorites.html',
controller: 'FavoritesCtrl',
controllerAs: 'vm'
}
},
resolve: {
favorites: favorites
}
});
favorites.$inject = ['HomeService'];
function favorites(HomeService) {
return HomeService.getFavorites().$promise;
}
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('favorites', 'home');
TatamiState.addConversationState('favorites', 'home');
TatamiState.addTagState('favorites', 'home');
}
})();
================================================
FILE: mobile/www/app/components/home/home.html
================================================
<ion-tabs class="tabs-icon-top tabs-color-active-positive">
<!-- Dashboard Tab -->
<ion-tab title="{{ 'tab.timeline' | translate }}"
icon-off="ion-ios-list-outline"
icon-on="ion-ios-list"
ui-sref="timeline">
<ion-nav-view name="timeline"></ion-nav-view>
</ion-tab>
<!-- Chats Tab -->
<ion-tab title="{{ 'tab.mentions' | translate }}"
icon-off="ion-ios-chatbubble-outline"
icon-on="ion-ios-chatbubble"
ui-sref="mentions">
<ion-nav-view name="mentions"></ion-nav-view>
</ion-tab>
<!-- Account Tab -->
<ion-tab title="{{ 'tab.favorites' | translate }}"
icon-off="ion-android-star-outline"
icon-on="ion-android-star"
ui-sref="favorites">
<ion-nav-view name="favorites"></ion-nav-view>
</ion-tab>
<ion-tab title="{{ 'tab.more' | translate }}"
icon-off="ion-navicon-round"
icon-on="ion-navicon-round"
ui-sref="more">
<ion-nav-view name="more"></ion-nav-view>
</ion-tab>
</ion-tabs>
================================================
FILE: mobile/www/app/components/home/home.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(homeConfig);
homeConfig.$inject = ['$stateProvider'];
function homeConfig($stateProvider) {
$stateProvider
.state('home', {
parent: 'tatami',
abstract: true,
url: '/home',
templateUrl: 'app/components/home/home.html',
resolve: {
currentUser: getCurrentUser,
translatePartialLoader: getTranslatePartialLoader
}
})
}
getCurrentUser.$inject = ['ProfileService'];
function getCurrentUser(ProfileService) {
return ProfileService.get().$promise.then(function(currentUser) {
console.log(currentUser);
return currentUser;
});
}
getTranslatePartialLoader.$inject = ['$translate', '$translatePartialLoader'];
function getTranslatePartialLoader($translate, $translatePartialLoader) {
$translatePartialLoader.addPart('home');
return $translate.refresh();
}
})();
================================================
FILE: mobile/www/app/components/home/mentions/mentions.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('MentionsCtrl', mentionsCtrl);
mentionsCtrl.$inject = ['mentioned', 'currentUser', 'TatamiStatusRefresherService'];
function mentionsCtrl(mentioned, currentUser, TatamiStatusRefresherService) {
var vm = this;
vm.mentioned = mentioned;
vm.currentUser = currentUser;
vm.remove = remove;
vm.getNewStatuses = getNewStatuses;
vm.getOldStatuses = getOldStatuses;
remove.$inject = ['mention'];
function remove(mention) {
vm.mentioned.splice(vm.mentioned.indexOf(mention), 1);
}
function getNewStatuses() {
return TatamiStatusRefresherService.refreshMentions();
}
getOldStatuses.$inject = ['finalStatus'];
function getOldStatuses(finalStatus) {
return TatamiStatusRefresherService.getOldMentions(finalStatus);
}
}
})();
================================================
FILE: mobile/www/app/components/home/mentions/mentions.html
================================================
<ion-view view-title="{{ 'tab.mentions' | translate }}" ng-style="{'background-color':'#f5f5f5'}">
<tatami-status-list statuses="vm.mentioned"
current-user="vm.currentUser"
tatami-refresher="vm.getNewStatuses()"
tatami-infinite-refresher="vm.getOldStatuses(finalStatus)"></tatami-status-list>
</ion-view>
================================================
FILE: mobile/www/app/components/home/mentions/mentions.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('mentions', {
url: '/mentions',
parent: 'home',
views: {
'mentions': {
templateUrl: 'app/components/home/mentions/mentions.html',
controller: 'MentionsCtrl',
controllerAs: 'vm'
}
},
resolve: {
mentioned: mentioned
}
});
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('mentions', 'home');
TatamiState.addConversationState('mentions', 'home');
TatamiState.addTagState('mentions', 'home');
}
mentioned.$inject = ['HomeService'];
function mentioned(HomeService) {
return HomeService.getMentions().$promise;
}
})();
================================================
FILE: mobile/www/app/components/home/more/all_users/all.users.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('AllUsersController', allUsersController);
allUsersController.$inject = ['currentUser', 'TatamiUserRefresherService', '$scope', '$timeout'];
function allUsersController(currentUser, TatamiUserRefresherService, $scope, $timeout) {
var vm = this;
vm.currentUser = currentUser;
vm.users = [];
vm.isFinished = false;
vm.getNextUsers = getNextUsers;
function getNextUsers() {
return TatamiUserRefresherService.getNextUsers(vm.users.length).then(addUsers);
}
addUsers.$inject = ['users'];
function addUsers(nextUsers) {
$timeout(function() {
$scope.$apply(function() {
vm.users.push.apply(vm.users, nextUsers);
vm.isFinished = nextUsers.length === 0;
});
})
}
}
})();
================================================
FILE: mobile/www/app/components/home/more/all_users/all.users.html
================================================
<ion-view view-title="{{ 'more.allUsers' | translate }}">
<ion-content class="tatami-header tatami-footer" ng-style="{'background-color':'#f5f5f5'}">
<ion-list ng-init="vm.getAllUsers()">
<div ng-repeat="user in vm.users">
<tatami-user user="user" current-user="vm.currentUser"></tatami-user>
</div>
</ion-list>
<ion-infinite-scroll ng-if="!vm.isFinished" on-infinite="vm.getNextUsers()"></ion-infinite-scroll>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/home/more/all_users/all.users.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('allusers', {
url: '/allusers',
parent: 'more',
views: {
'more@home': {
templateUrl: 'app/components/home/more/all_users/all.users.html',
controller: 'AllUsersController',
controllerAs: 'vm'
}
}
});
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('allusers', 'home');
TatamiState.addConversationState('allusers', 'home');
TatamiState.addTagState('allusers', 'home');
}
})();
================================================
FILE: mobile/www/app/components/home/more/blocked_users/blocked.users.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('BlockedUsersController', blockedUsersController);
blockedUsersController.$inject = ['$scope', 'currentUser', 'BlockService'];
function blockedUsersController($scope, currentUser, BlockService) {
var vm = this;
vm.currentUser = currentUser;
vm.blockedUsers = [];
vm.updateUser = updateUser;
vm.getBlockedUsersForUser = getBlockedUsersForUser;
vm.hasBlockedUsers = hasBlockedUsers;
function updateUser() {
BlockService.updateBlockedUser(
{username: vm.status.username}
);
}
function getBlockedUsersForUser() {
BlockService.getBlockedUsersForUser(
{username: vm.currentUser.username},
function (response) {
vm.blockedUsers = response;
}
);
$scope.$broadcast('scroll.refreshComplete');
}
function hasBlockedUsers() {
return vm.blockedUsers.length>0;
}
}
})();
================================================
FILE: mobile/www/app/components/home/more/blocked_users/blocked.users.html
================================================
<ion-view view-title="{{ 'more.blockedUsers.title' | translate }}">
<ion-content ng-style="{'background-color':'#f5f5f5'}">
<ion-refresher on-refresh="vm.getBlockedUsersForUser()"></ion-refresher>
<ion-list ng-init="vm.getBlockedUsersForUser()">
<div class="text-center" ng-if="!vm.hasBlockedUsers()" translate="more.blockedUsers.no" ng-style="{'color':'#ababab','padding':'40px'}"/>
<div ng-if="vm.hasBlockedUsers()" ng-repeat="blockeduser in vm.blockedUsers">
<tatami-user user="blockeduser"></tatami-user>
</div>
</ion-list>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/home/more/blocked_users/blocked.users.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('blockedusers', {
url: '/blockedusers',
parent: 'more',
views: {
'more@home': {
templateUrl: 'app/components/home/more/blocked_users/blocked.users.html',
controller: 'BlockedUsersController',
controllerAs: 'vm'
}
}
});
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('blockedusers', 'home');
TatamiState.addConversationState('blockedusers', 'home');
TatamiState.addTagState('blockedusers', 'home');
}
})();
================================================
FILE: mobile/www/app/components/home/more/company/company-timeline.html
================================================
<ion-view view-title="{{ 'more.company' | translate }}" ng-style="{'background-color':'#f5f5f5'}">
<tatami-status-list statuses="vm.statuses"
current-user="vm.currentUser"
tatami-refresher="vm.getNewStatuses()"
tatami-infinite-refresher="vm.getOldStatuses(finalStatus)"></tatami-status-list>
</ion-view>
================================================
FILE: mobile/www/app/components/home/more/company/company.timeline.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('CompanyTimelineCtrl', companyTimelineCtrl);
companyTimelineCtrl.$inject = ['statuses', 'currentUser', 'TatamiStatusRefresherService'];
function companyTimelineCtrl(statuses, currentUser, TatamiStatusRefresherService) {
var vm = this;
vm.statuses = statuses;
vm.currentUser = currentUser;
vm.getNewStatuses = getNewStatuses;
vm.getOldStatuses = getOldStatuses;
function getNewStatuses() {
return TatamiStatusRefresherService.refreshCompanyTimeline();
}
getOldStatuses.$inject = ['finalStatus'];
function getOldStatuses(finalStatus) {
return TatamiStatusRefresherService.getOldFromCompanyTimeline(finalStatus);
}
}
})();
================================================
FILE: mobile/www/app/components/home/more/company/company.timeline.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('company', {
url: '/company/timeline',
parent: 'more',
views: {
'more@home': {
templateUrl: 'app/components/home/more/company/company-timeline.html',
controller: 'CompanyTimelineCtrl',
controllerAs: 'vm'
}
},
resolve: {
statuses: getStatuses
}
});
getStatuses.$inject = ['HomeService'];
function getStatuses(HomeService) {
return HomeService.getCompanyTimeline().$promise;
}
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('company', 'home');
TatamiState.addConversationState('company', 'home');
TatamiState.addTagState('company', 'home');
}
})();
================================================
FILE: mobile/www/app/components/home/more/more.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('MoreController', moreController);
moreController.$inject = [
'$state',
'$localStorage',
'currentUser'
];
function moreController($state, $localStorage, currentUser) {
var vm = this;
vm.currentUser = currentUser;
vm.logout = logout;
vm.goToCompanyTimeline = goToCompanyTimeline;
vm.goToSettings = goToSettings;
vm.goToBlockedUsers = goToBlockedUsers;
vm.goToAllUsers = goToAllUsers;
vm.goToReportedStatus = goToReportedStatus;
function logout() {
$localStorage.signOut();
$state.go('login');
}
function goToCompanyTimeline() {
$state.go('company');
}
function goToSettings() {
$state.go('settings');
}
function goToBlockedUsers(){
$state.go('blockedusers');
}
function goToReportedStatus(){
$state.go('reportedStatus')
}
function goToAllUsers() {
$state.go('allusers')
}
}
})();
================================================
FILE: mobile/www/app/components/home/more/more.html
================================================
<ion-view view-title="{{ 'tab.more' | translate }}">
<ion-content class="tatami-header tatami-footer" ng-style="{'background-color':'#f5f5f5'}">
<ion-list>
<div>
<tatami-user user="vm.currentUser" current-user="vm.currentUser"></tatami-user>
</div>
<ion-item ng-click="vm.goToCompanyTimeline()" class="text-center">
<span class="ion-briefcase calm padding-right"></span>
<span class="calm" translate="more.company">Company Timeline</span>
</ion-item>
<ion-item class="text-center" ng-click="vm.goToAllUsers()">
<span class="ion-earth padding-right"></span>
<span translate="more.allUsers">All users</span>
</ion-item>
<ion-item class="item-divider"></ion-item>
<ion-item ng-click="vm.goToSettings()" class="text-center">
<span class="ion-gear-a padding-right"></span>
<span translate="more.settings">Settings</span>
</ion-item>
<ion-item class="text-center" ng-click="vm.goToBlockedUsers()">
<span class="ion-close-circled padding-right"></span>
<span translate="more.blockedUsers.title">Manage your blocked users</span>
</ion-item>
<ion-item ng-if="vm.currentUser.isAdmin" class="text-center" ng-click="vm.goToReportedStatus()">
<span class="ion-alert-circled"></span>
<span translate="more.reportedStatus.title">Reported Statuses</span>
</ion-item>
<ion-item class="item-divider"></ion-item>
<ion-item ng-click="vm.logout()" class="text-center">
<span class="ion-power padding-right assertive"></span>
<span class="assertive" translate="more.logout">Logout</span>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/home/more/more.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(moreConfig);
moreConfig.$inject = ['$stateProvider'];
function moreConfig($stateProvider) {
$stateProvider
.state('more', {
url: '/more',
parent: 'home',
views: {
'more': {
templateUrl: 'app/components/home/more/more.html',
controller: 'MoreController',
controllerAs: 'vm'
}
},
resolve: {
translatePartialLoader: getTranslatePartialLoader
}
});
getTranslatePartialLoader.$inject = ['$translate', '$translatePartialLoader'];
function getTranslatePartialLoader($translate, $translatePartialLoader) {
$translatePartialLoader.addPart('more');
return $translate.refresh();
}
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('more', 'home');
}
})();
================================================
FILE: mobile/www/app/components/home/more/reportedStatus/reportedStatus.controller.js
================================================
/**
* Created by emilyklein on 7/11/16.
*/
(function() {
'use strict';
angular.module('tatami')
.controller('ReportedStatusController', reportedStatusController);
reportedStatusController.$inject = ['$state', '$scope', 'currentUser', 'ReportService', '$ionicPopup', '$translate', 'ToastService'];
function reportedStatusController($state, $scope, currentUser, ReportService, $ionicPopup, $translate, ToastService) {
var vm = this;
vm.reportedStatuses = [];
vm.currentUser = currentUser;
vm.getReportedStatuses = getReportedStatuses;
vm.hasReportedStatus = hasReportedStatus;
vm.approveStatus = approveStatus;
vm.deleteStatus = deleteStatus;
function reportStatus() {
ReportService.reportStatus({statusId: vm.status.statusId});
$ionicPopup.alert({
title: 'Report',
template: '<span translate="status.reportMessage"></span>'
});
}
goToProfile.$inject = ['username'];
function goToProfile(username) {
var destinationState = $state.current.name.split('.')[0] + '.profile';
$state.go(destinationState, { username : username });
}
function getReportedStatuses(){
ReportService.getReportedStatuses(null, function(response){
vm.reportedStatuses = response;
}
);
$scope.$broadcast('scroll.refreshComplete');
}
function deleteStatus(statusId){
var confirmPopup = $ionicPopup.confirm({
title: 'Delete Status',
template: '<span translate="status.reportStatus.delete"></span>'
});
confirmPopup.then(deleted);
deleted.$inject = ['decision'];
function deleted(decision) {
if(decision) {
ReportService.deleteStatus({statusId: statusId}, function () {
ToastService.display('status.reportStatus.deleteToast');
}
);
$state.go($state.current, {}, {reload: true});
}
}
}
function approveStatus(statusId){
var confirmPopup = $ionicPopup.confirm({
title: 'Approve Status',
template: '<span translate="status.reportStatus.approve"></span>'
});
confirmPopup.then(approved);
approved.$inject = ['decision'];
function approved(decision) {
if(decision) {
ReportService.approveStatus({statusId: statusId}, function () {
ToastService.display('status.reportStatus.approveToast');
}
);
$state.go($state.current, {}, {reload: true});
}
}
}
remove.$inject = ['status'];
function remove(status) {
vm.statuses.splice(vm.statuses.indexOf(status), 1);
}
function hasReportedStatus() {
return vm.reportedStatuses.length > 0
}
}
})();
================================================
FILE: mobile/www/app/components/home/more/reportedStatus/reportedStatus.html
================================================
<ion-view view-title="{{ 'more.reportedStatus.title' | translate }}">
<ion-content class="tatami-header tatami-footer">
<ion-refresher on-refresh="vm.getReportedStatuses()"></ion-refresher>
<ion-list ng-init="vm.getReportedStatuses()">
<ion-item ng-if="vm.hasReportedStatus()" ng-repeat="status in vm.reportedStatuses" >
<tatami-status status = "status" current-user = "vm.currentUser" on-delete = "vm.remove(status)"></tatami-status>
<div class="row">
<div class="col-25 button button-clear ion-checkmark-round" ng-click="vm.approveStatus(status.statusId)"></div>
<div class="col-25 button button-clear ion-close-round" ng-click="vm.deleteStatus(status.statusId)"></div>
</div>
</ion-item>
<div class="text-center" ng-if="!vm.hasReportedStatus()" translate="more.reportedStatus.no" ng-style="{'color':'#ababab','padding':'40px'}"/>
</ion-list>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/home/more/reportedStatus/reportedStatus.js
================================================
/**
* Created by emilyklein on 7/11/16.
*/
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('reportedStatus', {
cache: false,
url: '/reportedStatus',
parent: 'more',
views: {
'more@home': {
templateUrl: 'app/components/home/more/reportedStatus/reportedStatus.html',
controller: 'ReportedStatusController',
controllerAs: 'vm'
}
}
});
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('reportedStatus', 'home');
TatamiState.addConversationState('reportedStatus', 'home');
TatamiState.addTagState('reportedStatus', 'home');
}
})();
================================================
FILE: mobile/www/app/components/home/more/settings/settings.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('SettingsController', settingsController);
settingsController.$inject = ['$scope', '$translate', 'currentUser'];
function settingsController($scope, $translate, currentUser) {
var vm = this;
vm.currentUser = currentUser;
vm.language = window.localStorage.getItem('language');
vm.languages = [
{
langKey: 'en',
translateKey: 'more.language.english'
},
{
langKey: 'fr',
translateKey: 'more.language.french'
}
];
$scope.$watch('vm.language', updateLanguage);
function updateLanguage(language) {
$translate.use(language);
window.localStorage.setItem('language', language);
}
}
})();
================================================
FILE: mobile/www/app/components/home/more/settings/settings.html
================================================
<ion-view view-title="{{ 'more.settings' | translate }}">
<ion-content ng-style="{'background-color':'#f5f5f5'}">
<ion-list>
<ion-item class="item-divider" translate="more.language.change"></ion-item>
<ion-radio ng-repeat="language in vm.languages"
ng-model="vm.language"
ng-value="language.langKey">
{{ language.translateKey | translate }}
</ion-radio>
</ion-list>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/home/more/settings/settings.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('settings', {
url: '/settings',
parent: 'more',
views: {
'more@home': {
templateUrl: 'app/components/home/more/settings/settings.html',
controller: 'SettingsController',
controllerAs: 'vm'
}
}
});
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('settings', 'home');
TatamiState.addConversationState('settings', 'home');
TatamiState.addTagState('settings', 'home');
}
})();
================================================
FILE: mobile/www/app/components/home/timeline/timeline.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('TimelineCtrl', timelineCtrl);
timelineCtrl.$inject = ['statuses', 'currentUser', 'TatamiStatusRefresherService'];
function timelineCtrl(statuses, currentUser, TatamiStatusRefresherService) {
var vm = this;
vm.statuses = statuses;
vm.currentUser = currentUser;
vm.getNewStatuses = getNewStatuses;
vm.getOldStatuses = getOldStatuses;
function getNewStatuses() {
return TatamiStatusRefresherService.refreshHomeTimeline();
}
getOldStatuses.$inject = ['finalStatus'];
function getOldStatuses(finalStatus) {
return TatamiStatusRefresherService.getOldFromHomeTimeline(finalStatus);
}
}
})();
================================================
FILE: mobile/www/app/components/home/timeline/timeline.html
================================================
<ion-view view-title="{{ 'tab.timeline' | translate }}" ng-style="{'background-color':'#f5f5f5'}">
<tatami-status-list statuses="vm.statuses"
current-user="vm.currentUser"
tatami-refresher="vm.getNewStatuses()"
tatami-infinite-refresher="vm.getOldStatuses(finalStatus)"></tatami-status-list>
</ion-view>
================================================
FILE: mobile/www/app/components/home/timeline/timeline.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('timeline', {
url: '/timeline',
parent: 'home',
views: {
'timeline': {
templateUrl: 'app/components/home/timeline/timeline.html',
controller: 'TimelineCtrl',
controllerAs: 'vm'
}
},
resolve: {
statuses: getStatuses
}
});
getStatuses.$inject = ['StatusService'];
function getStatuses(StatusService) {
return StatusService.getHomeTimeline().$promise;
}
}
angular.module('tatami')
.run(run);
run.$inject = ['TatamiState'];
function run(TatamiState) {
TatamiState.addProfileState('timeline', 'home');
TatamiState.addConversationState('timeline', 'home');
TatamiState.addTagState('timeline', 'home');
}
})();
================================================
FILE: mobile/www/app/components/login/login.controller.js
================================================
(function () {
'use strict';
angular.module('tatami')
.controller('LoginCtrl', loginCtrl);
loginCtrl.$inject = [
'TatamiEndpoint',
'$scope',
'$state',
'$http',
'$localStorage',
'$ionicLoading',
'PathService',
'$ionicHistory',
'ToastService'
];
function loginCtrl(TatamiEndpoint, $scope, $state, $http, $localStorage, $ionicLoading, PathService, $ionicHistory, ToastService) {
var vm = this;
$scope.$on("$ionicView.enter", function () {
$ionicHistory.clearCache();
$ionicHistory.clearHistory();
var newEndpoint = TatamiEndpoint.getEndpoint();
if (vm.lastEndpoint.url !== newEndpoint.url) {
vm.lastEndpoint.url = newEndpoint.url;
vm.failed = false;
}
});
vm.user = {
remember: false
};
vm.failed = false;
vm.login = login;
vm.tryGoogleLogin = tryGoogleLogin;
vm.goToServerConfig = goToServerConfig;
vm.lastEndpoint = {url: ''};
function login() {
var data = "j_username=" + encodeURIComponent(vm.user.email) + "&j_password="
+ encodeURIComponent(vm.user.password);
return $http.post('/tatami/rest/authentication', data, {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json"
}
}).success(function (data) {
$localStorage.set('token', data.token);
vm.user = {remember: false};
$state.go('timeline');
}).error(function () {
vm.failed = true;
});
}
function tryGoogleLogin() {
$http({
url: '/tatami/rest/client/id',
method: 'GET'
}).then(function (data) {
var clientId;
if (data && data.data && data.data.stringList) {
// Old tatami return the clientId in the stringList property
clientId = data.data.stringList[0];
} else if (data && data.data && data.data.clientId) {
clientId = data.data.clientId;
}
// Do Google login or display an error message
if (clientId) {
googleLogin(clientId);
} else {
ToastService.display('login.googleUnavaible');
}
}, function () {
ToastService.display('login.googleUnavaible');
});
}
function googleLogin(clientId) {
var emailScope = 'https://www.googleapis.com/auth/plus.profile.emails.read';
var profileScope = 'https://www.googleapis.com/auth/plus.me';
var googleUrl = 'https://accounts.google.com/o/oauth2/auth?' +
'client_id=' + clientId + '&' +
'redirect_uri=http://localhost/callback&' +
'scope=' + emailScope + ' ' + profileScope + '&' +
'approval_prompt=force&response_type=code&access_type=offline';
var ref = window.open(googleUrl, '_blank', 'location=no');
ref.addEventListener('loadstart', onStart);
onStart.$inject = ['event'];
function onStart(event) {
if (event.url.indexOf('http://localhost/callback') === 0) {
ref.close();
$ionicLoading.show({
template: '<span translate="login.progress">Login in progress...</span>',
hideOnStateChange: true
});
var requestToken = event.url.split("code=")[1];
$http({
url: '/tatami/rest/oauth/token',
method: 'POST',
headers: {
'x-auth-code-header': requestToken
}
}).then(onSuccess, onFail);
}
}
onSuccess.$inject = ['result'];
function onSuccess(result) {
$localStorage.set('token', result.data.token);
$state.go('timeline');
}
onFail.$inject = ['failure'];
function onFail() {
vm.failed = true;
}
}
function goToServerConfig() {
$state.go('server');
}
}
})();
================================================
FILE: mobile/www/app/components/login/login.html
================================================
<ion-view name="login-view" view-title="{{ 'login.title' | translate }}" hide-back-button="true">
<ion-content class="has-header" scroll="false">
<form ng-submit="vm.login()">
<div class="list list-inset">
<label class="item item-input">
<input type="text" autocapitalize="off" autocorrect="off" placeholder="{{ 'login.email' | translate }}" ng-model="vm.user.email">
</label>
<label class="item item-input">
<input type="password" placeholder="{{ 'login.password' | translate }}" ng-model="vm.user.password">
</label>
</div>
<div align="center">
<label class="toggle v-align">
<input type="checkbox" ng-model="vm.tos">
<div class="track">
<div class="handle"></div>
</div>
</label>
<span translate="login.accept"></span>
<a href="http://tatami.ippon.fr/#/about/tos" translate="login.tos"></a>
</div>
<div class="row">
<div class="col col-50">
<button ng-disabled="!vm.user.email && !vm.user.password || !vm.tos"
translate="login.title"
class="button button-block button-calm"
type="submit">
Login
</button>
</div>
<div class="col col-50">
<button ng-disabled="!vm.tos"
ng-click="vm.tryGoogleLogin()"
translate="login.google"
class="button button-block button-stable"
type="button">
Google Login
</button>
</div>
</div>
<div class="row">
<button class="button button-block button-stable"
type="button"
ng-click="vm.goToServerConfig()">
<span>{{ 'login.changeServer' | translate }}</span>
</button>
</div>
<div ng-show="vm.failed" class="bar bar-assertive">
<h1 class="title" translate="login.failed">Failed to log in!</h1>
</div>
</form>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/login/login.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('login', {
url: '/login',
parent: 'tatami',
templateUrl: 'app/components/login/login.html',
controller: 'LoginCtrl',
controllerAs: 'vm',
resolve: {
translatePartialLoader: getTranslatePartialLoader
}
});
getTranslatePartialLoader.$inject = ['$translate', '$translatePartialLoader'];
function getTranslatePartialLoader($translate, $translatePartialLoader) {
$translatePartialLoader.addPart('login');
return $translate.refresh();
}
}
})();
================================================
FILE: mobile/www/app/components/login/server/server.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('ServerController', serverController);
serverController.$inject = [
'$state',
'$http',
'$ionicHistory',
'$translate',
'$ionicPopup',
'PathService',
'TatamiEndpoint'
];
function serverController($state, $http, $ionicHistory, $translate, $ionicPopup, PathService, TatamiEndpoint) {
var vm = this;
vm.endpoint = TatamiEndpoint.getEndpoint().url || TatamiEndpoint.getDefault().url;
vm.success = true;
vm.previous = vm.endpoint;
vm.updateEndpoint = updateEndpoint;
vm.useDefaultEndpoint = useDefaultEndpoint;
vm.isLastAttempt = isLastAttempt;
function updateEndpoint() {
TatamiEndpoint.setEndpoint(vm.endpoint);
$http({
url: '/tatami/rest/client/id',
method: 'GET'
}).then(success, error);
}
function success(result) {
vm.success = true;
vm.previous = vm.endpoint;
var alertPopup = $ionicPopup.alert({
title: $translate.instant('server.endpoint.authenticate.title'),
template: '<span translate="server.endpoint.authenticate.body"></span>'
});
alertPopup.then($state.go('login'));
}
function error(result) {
vm.success = false;
vm.previous = vm.endpoint;
$ionicPopup.alert({
title: $translate.instant('server.endpoint.error.title'),
template: '<span translate="server.endpoint.error.body"></span>'
});
TatamiEndpoint.reset();
}
function isLastAttempt() {
return vm.previous === vm.endpoint;
}
function useDefaultEndpoint() {
vm.endpoint = TatamiEndpoint.getDefault().url;
updateEndpoint();
}
}
})();
================================================
FILE: mobile/www/app/components/login/server/server.html
================================================
<ion-view view-title="">
<ion-content ng-style="{'background-color':'#f5f5f5'}">
<ion-list>
<ion-item class="item-divider item-button-right" translate="server.endpoint.change"></ion-item>
<ion-item class="item-input-inset">
<label class="item-input-wrapper">
<input
class="item-input-wrapper"
type="text"
autocapitalize="off"
autocorrect="off"
ng-model="vm.endpoint"
placeholder="{{ 'server.endpoint.title' | translate }}">
</label>
<button class="button button-small"
ng-class="{ 'button-balanced': vm.isLastAttempt() && vm.success,
'button-assertive': vm.isLastAttempt() && !vm.success }"
ng-disabled="vm.isLastAttempt()"
ng-click="vm.updateEndpoint()">
<span ng-if="vm.isLastAttempt()"
ng-class="{ 'ion-checkmark-round': vm.success,
'ion-close-round': !vm.success }"></span>
<span ng-if="!vm.isLastAttempt()">Submit</span>
</button>
</ion-item>
<ion-item ng-click="vm.useDefaultEndpoint()"
class="text-center"
translate="server.endpoint.default"></ion-item>
</ion-list>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/components/login/server/server.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(config);
config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('server', {
url: '/server',
parent: 'login',
views: {
'@tatami': {
templateUrl: 'app/components/login/server/server.html',
controller: 'ServerController',
controllerAs: 'vm'
}
},
resolve: {
translatePartialLoader: getTranslatePartialLoader
}
});
getTranslatePartialLoader.$inject = ['$translate', '$translatePartialLoader'];
function getTranslatePartialLoader($translate, $translatePartialLoader) {
$translatePartialLoader.addPart('server');
$translate.refresh();
}
}
})();
================================================
FILE: mobile/www/app/components/post/post.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('PostCtrl', postCtrl);
postCtrl.$inject = [
'StatusService',
'PathService',
'$ionicHistory',
'$state',
'$cordovaCamera',
'$q',
'$ionicLoading',
'$ionicPopup',
'repliedToStatus',
'$scope',
'$cordovaGeolocation',
'ToastService'
];
function postCtrl(StatusService, PathService, $ionicHistory, $state, $cordovaCamera, $q, $ionicLoading, $ionicPopup, repliedToStatus, $scope, $cordovaGeolocation, ToastService) {
var vm = this;
vm.charCount = 750;
vm.status = {
content: repliedToStatus ? '@' + repliedToStatus.username : '',
statusPrivate: repliedToStatus ? repliedToStatus.private : false,
replyTo: repliedToStatus ? repliedToStatus.statusId : '',
replyToUsername: repliedToStatus ? repliedToStatus.username : '',
attachmentIds: [],
geoLocalization: ""
};
vm.images = [];
vm.isPosting = false;
vm.remainingLength = vm.charCount;
vm.newLineCount = 0; //This field takes into consideration the '\n' character that counts for 2 chars in the database.
vm.pasteFlag = false;
vm.shareLocation = false;
vm.post = post;
vm.reset = reset;
vm.close = close;
vm.getPicture = getPicture;
vm.getPictureFromLibrary = getPictureFromLibrary;
vm.remove = remove;
vm.paste = paste;
vm.updateLocation = updateLocation;
vm.updatePrivate = updatePrivate;
function post() {
upload().then(createPost);
}
function createPost(attachmentIds) {
vm.status.attachmentIds = attachmentIds;
StatusService.save(vm.status, function() {
reset();
$ionicHistory.clearCache();
$state.go('timeline');
});
}
function reset() {
vm.status = {
content: '',
statusPrivate: false,
attachmentIds: [],
geoLocalization: ""
};
vm.images = [];
vm.isPosting = false;
vm.shareLocation = false;
}
function close() {
$ionicHistory.goBack();
reset();
}
function getPicture() {
var options = {
quality: 10,
correctOrientation : true
};
$cordovaCamera.getPicture(options).then(store);
}
function getPictureFromLibrary() {
var options = {
quality: 10,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
correctOrientation: true
};
$cordovaCamera.getPicture(options).then(store);
}
function store(fileUri) {
vm.images.push(fileUri);
}
function upload() {
var promises = [];
vm.isPosting = true;
var options = new FileUploadOptions();
var fileTransfer = new FileTransfer();
angular.forEach(vm.images, function(image) {
var deferred = $q.defer();
options.fileKey = 'uploadFile';
options.fileName = image.substr(image.lastIndexOf('/') + 1);
$ionicLoading.show({
template: '<span translate="post.progress">Post in progress...</span>',
hideOnStateChange: true
});
fileTransfer.upload(image, '/tatami/rest/fileupload', onSuccess, onFail, options);
promises.push(deferred.promise);
function onSuccess(result) {
var jsonResult = JSON.parse(result.response)[0];
deferred.resolve(jsonResult.attachmentId);
}
function onFail(failure) {
$ionicLoading.hide();
var popupError = $ionicPopup.alert({
title: 'Error',
template: '<span translate="post.error.message"></span>'
});
popupError.then(goToTimeline);
function goToTimeline() {
reset();
$state.go('timeline');
}
deferred.resolve(failure);
}
});
return $q.all(promises);
}
function remove(index) {
vm.images.splice(index, 1);
}
function updateRemainingLength(statusContent) {
vm.remainingLength = vm.charCount - statusContent.length - vm.newLineCount;
}
function updateNewLineCount(statusContent) {
vm.newLineCount = (statusContent.match(/\n/g) || []).length;
}
$scope.$watch('vm.status.content', function (newValue) {
if (newValue) {
updateNewLineCount(newValue);
updateRemainingLength(newValue);
if(vm.remainingLength < 0){
if(vm.pasteFlag){
$ionicLoading.show({
template: '<span translate="post.error.truncated"></span>',
duration: 2500
});
vm.pasteFlag = false;
}
vm.status.content = newValue.slice(0, vm.charCount - vm.newLineCount);
updateNewLineCount(vm.status.content);
updateRemainingLength(vm.status.content);
}
} else {
vm.remainingLength = vm.charCount;
vm.newLineCount = 0;
}
});
function paste(){
vm.pasteFlag = true;
}
function updateLocation() {
vm.shareLocation = !vm.shareLocation;
if(vm.shareLocation){
var posOptions = {timeout: 5000, enableHighAccuracy: false};
$cordovaGeolocation
.getCurrentPosition(posOptions)
.then(function (position) {
vm.status.geoLocalization = position.coords.latitude + ", " + position.coords.longitude;
ToastService.display('post.location.share');
}, function() {
vm.shareLocation = !vm.shareLocation;
ToastService.display('post.location.fail');
});
} else {
vm.status.geoLocalization = "";
}
}
function updatePrivate(){
vm.status.statusPrivate = !vm.status.statusPrivate;
vm.status.statusPrivate ? ToastService.display('post.private.yes') : ToastService.display('post.private.no');
}
}
})();
================================================
FILE: mobile/www/app/components/post/post.html
================================================
<ion-view view-title="{{ 'post.title' | translate }}" hide-back-button="true">
<ion-nav-buttons side="secondary">
<button class="button button-clear button-small icon ion-close-round" style="opacity:0.4;" ng-click="vm.close()">
</button>
</ion-nav-buttons>
<ion-content class="has-subfooter">
<form name="newPost" novalidate="">
<ion-item>
<ion-textarea>
<textarea ng-model="vm.status.content"
rows="15"
placeholder="{{ 'post.message' | translate }}"
ng-required="true"
ng-trim="false"
ng-paste="vm.paste()"
style="width: 100%; height: 100%;">
</textarea>
</ion-textarea>
</ion-item>
</form>
<span ng-repeat="image in vm.images track by $index">
<div class="list card">
<div class="item item-image">
<img class="center" ng-show="vm.images.length > 0" ng-src="{{ image }}">
<i class="icon ion-close-round light" ng-click="vm.remove($index)"></i>
</div>
</div>
</span>
</ion-content>
<ion-footer-bar align-title="right" tatami-post-bar-attach="true" class="bar-subfooter">
<div class="row" style="width:50%;">
<button class="col-33 button button-clear icon ion-camera" ng-click="vm.getPicture()"></button>
<button class="col-33 button button-clear icon ion-images" ng-click="vm.getPictureFromLibrary()"></button>
<button class="col-33 button button-clear icon ion-location"
ng-click="vm.updateLocation()"
ng-class="{ 'button-calm' : vm.shareLocation, 'button-stable' : !vm.shareLocation }"></button>
<button class="col-33 button button-clear icon ion-locked"
ng-click="vm.updatePrivate()"
ng-class="{ 'button-calm' : vm.status.statusPrivate, 'button-stable' : !vm.status.statusPrivate }"></button>
</div>
<h1 class="title">{{vm.remainingLength}}</h1>
<button class="button button-positive"
translate="post.title"
ng-disabled="vm.status.content.length === 0 || !vm.status.content || vm.isPosting"
ng-click="vm.post()">
Post
</button>
</ion-footer-bar>
</ion-view>
================================================
FILE: mobile/www/app/components/post/post.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(postConfig);
postConfig.$inject = ['$stateProvider'];
function postConfig($stateProvider) {
$stateProvider
.state('post', {
url: '/post/:statusId',
parent: 'tatami',
templateUrl: 'app/components/post/post.html',
controller: 'PostCtrl',
controllerAs: 'vm',
resolve: {
repliedToStatus: getRepliedToStatus,
translatePartialProvider: getTranslatePartialLoader
}
})
}
getRepliedToStatus.$inject = ['StatusService', '$stateParams'];
function getRepliedToStatus(StatusService, $stateParams) {
if($stateParams.statusId) {
return StatusService.get({ statusId: $stateParams.statusId }).$promise;
}
}
getTranslatePartialLoader.$inject = ['$translate', '$translatePartialLoader'];
function getTranslatePartialLoader($translate, $translatePartialLoader) {
$translatePartialLoader.addPart('post');
return $translate.refresh();
}
})();
================================================
FILE: mobile/www/app/components/post/postbar.directive.js
================================================
(function() {
'use strict';
angular.module('tatami')
.directive('tatamiPostBarAttach', tatamiPostBar);
function tatamiPostBar() {
var directive = {
restrict: 'A',
link: link
};
return directive;
}
function link(scope, element, attrs) {
ionic.on('native.keyboardshow', onShow, window);
ionic.on('native.keyboardhide', onHide, window);
//deprecated
ionic.on('native.showkeyboard', onShow, window);
ionic.on('native.hidekeyboard', onHide, window);
var scrollCtrl;
function onShow(e) {
if (ionic.Platform.isAndroid() && !ionic.Platform.isFullScreen) {
return;
}
if(attrs['tatamiPostBarAttach'] === 'true') {
var subheaderOffset = 43;
}
//for testing
var keyboardHeight = e.keyboardHeight || e.detail.keyboardHeight;
element.css('bottom', (keyboardHeight + subheaderOffset) + "px");
scrollCtrl = element.controller('$ionicScroll');
if (scrollCtrl) {
scrollCtrl.scrollView.__container.style.bottom = subheaderOffset + keyboardHeight + keyboardAttachGetClientHeight(element[0]) + "px";
}
}
function onHide() {
if (ionic.Platform.isAndroid() && !ionic.Platform.isFullScreen) {
return;
}
element.css('bottom', '');
if (scrollCtrl) {
scrollCtrl.scrollView.__container.style.bottom = '';
}
}
scope.$on('$destroy', function() {
ionic.off('native.keyboardshow', onShow, window);
ionic.off('native.keyboardhide', onHide, window);
//deprecated
ionic.off('native.showkeyboard', onShow, window);
ionic.off('native.hidekeyboard', onHide, window);
});
function keyboardAttachGetClientHeight(element) {
return element.clientHeight;
}
}
})();
================================================
FILE: mobile/www/app/shared/config/marked.config.js
================================================
(function() {
'use strict';
angular.module('tatami')
.config(markedConfig);
markedConfig.$inject = ['markedProvider'];
function markedConfig(markedProvider) {
markedProvider.setOptions({
gfm: true,
pedantic: false,
sanitize: true,
highlight: null,
urls: {
youtube : function(text, url){
var cap;
if((cap = /(youtu\.be\/|youtube\.com\/(watch\?(.*&)?v=|(embed|v)\/))([^\?&"'>]+)/.exec(url))){
return '<iframe width="420" height="315" src="https://www.youtube.com/embed/' +
cap[5] +
'" frameborder="0" allowfullscreen></iframe>';
}
},
vimeo : function(text, url){
var cap;
if((cap = /^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/))?([0-9]+)/.exec(url))){
return '<iframe src="https://player.vimeo.com/video/' +
cap[5] +
'" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>';
}
},
dailymotion : function(text, url){
var cap;
if((cap = /^.+dailymotion.com\/(video|hub)\/([^_]+)[^#]*(#video=([^_&]+))?/.exec(url))){
return '<iframe frameborder="0" width="480" height="271" src="https://www.dailymotion.com/embed/video/' +
cap[2] +
'"></iframe>';
}
},
gist : function(text, url){
var cap;
if((cap = /^.+gist.github.com\/(([A-z0-9-]+)\/)?([0-9A-z]+)/.exec(url))){
$.ajax({
url: cap[0] + '.json',
dataType: 'jsonp',
success: function(response){
if(response.stylesheet && $('link[href="' + response.stylesheet + '"]').length === 0){
var l = document.createElement("link"),
head = document.getElementsByTagName("head")[0];
l.type = "text/css";
l.rel = "stylesheet";
l.href = response.stylesheet;
head.insertBefore(l, head.firstChild);
}
var $elements = $('.gist' + cap[3]);
$elements.html(response.div);
}
});
return '<div class="gist' + cap[3] + '"/>';
}
}
}
});
}
})();
================================================
FILE: mobile/www/app/shared/config/marked.filter.js
================================================
(function() {
'use strict';
angular.module('tatami')
.filter('markdown', markdown);
markdown.$inject = ['$sce'];
function markdown($sce) {
return function(content) {
return content ? marked(content) : '';
};
}
})();
================================================
FILE: mobile/www/app/shared/config/tatami.marked.js
================================================
/**
* marked - a markdown parser
* Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
* https://github.com/chjj/marked
*/
;(function() {
/**
* Block-Level Grammar
*/
var block = {
newline: /^\n+/,
code: /^( {4}[^\n]+\n*)+/,
fences: noop,
hr: /^( *[-*_]){3,} *(?:\n+|$)/,
heading: /^ *(#{1,6} ) *([^\n]+?) *#* *(?:\n+|$)/,
nptable: noop,
lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
table: noop,
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
text: /^[^\n]+/
};
block.bullet = /(?:[*+-]|\d+\.)/;
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
block.item = replace(block.item, 'gm')
(/bull/g, block.bullet)
();
block.list = replace(block.list)
(/bull/g, block.bullet)
('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
();
block._tag = '(?!(?:'
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
block.html = replace(block.html)
('comment', /<!--[\s\S]*?-->/)
('closed', /<(tag)[\s\S]+?<\/\1>/)
('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
(/tag/g, block._tag)
();
block.paragraph = replace(block.paragraph)
('hr', block.hr)
('heading', block.heading)
('lheading', block.lheading)
('blockquote', block.blockquote)
('tag', '<' + block._tag)
('def', block.def)
();
/**
* Normal Block Grammar
*/
block.normal = merge({}, block);
/**
* GFM Block Grammar
*/
block.gfm = merge({}, block.normal, {
fences: /^ *(`{3,}|~{3,}) *(\w+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
paragraph: /^/
});
block.gfm.paragraph = replace(block.paragraph)
('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|')
();
/**
* GFM + Tables Block Grammar
*/
block.tables = merge({}, block.gfm, {
nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
});
/**
* Block Lexer
*/
function Lexer(options) {
this.tokens = [];
this.tokens.links = {};
this.options = options || marked.defaults;
this.rules = block.normal;
if (this.options.gfm) {
if (this.options.tables) {
this.rules = block.tables;
} else {
this.rules = block.gfm;
}
}
}
/**
* Expose Block Rules
*/
Lexer.rules = block;
/**
* Static Lex Method
*/
Lexer.lex = function(src, options) {
var lexer = new Lexer(options);
return lexer.lex(src);
};
/**
* Preprocessing
*/
Lexer.prototype.lex = function(src) {
src = src
.replace(/\r\n|\r/g, '\n')
.replace(/\t/g, ' ')
.replace(/\u00a0/g, ' ')
.replace(/\u2424/g, '\n');
return this.token(src, true);
};
/**
* Lexing
*/
Lexer.prototype.token = function(src, top) {
var src = src.replace(/^ +$/gm, '')
, next
, loose
, cap
, bull
, b
, item
, space
, i
, l;
while (src) {
// newline
if (cap = this.rules.newline.exec(src)) {
src = src.substring(cap[0].length);
if (cap[0].length > 1) {
this.tokens.push({
type: 'space'
});
}
}
// code
if (cap = this.rules.code.exec(src)) {
src = src.substring(cap[0].length);
cap = cap[0].replace(/^ {4}/gm, '');
this.tokens.push({
type: 'code',
text: !this.options.pedantic
? cap.replace(/\n+$/, '')
: cap
});
continue;
}
// fences (gfm)
if (cap = this.rules.fences.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'code',
lang: cap[2],
text: cap[3]
});
continue;
}
// heading
if (cap = this.rules.heading.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'heading',
depth: cap[1].length,
text: cap[2]
});
continue;
}
// table no leading pipe (gfm)
if (top && (cap = this.rules.nptable.exec(src))) {
src = src.substring(cap[0].length);
item = {
type: 'table',
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
cells: cap[3].replace(/\n$/, '').split('\n')
};
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right';
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center';
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left';
} else {
item.align[i] = null;
}
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i].split(/ *\| */);
}
this.tokens.push(item);
continue;
}
// lheading
if (cap = this.rules.lheading.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'heading',
depth: cap[2] === '=' ? 1 : 2,
text: cap[1]
});
continue;
}
// hr
if (cap = this.rules.hr.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'hr'
});
continue;
}
// blockquote
if (cap = this.rules.blockquote.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'blockquote_start'
});
cap = cap[0].replace(/^ *> ?/gm, '');
// Pass `top` to keep the current
// "toplevel" state. This is exactly
// how markdown.pl works.
this.token(cap, top);
this.tokens.push({
type: 'blockquote_end'
});
continue;
}
// list
if (cap = this.rules.list.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'list_start',
ordered: isFinite(cap[2])
});
// Get each top-level item.
cap = cap[0].match(this.rules.item);
// Get bullet.
if (this.options.smartLists) {
bull = block.bullet.exec(cap[0])[0];
}
next = false;
l = cap.length;
i = 0;
for (; i < l; i++) {
item = cap[i];
// Remove the list item's bullet
// so it is seen as the next token.
space = item.length;
item = item.replace(/^ *([*+-]|\d+\.) +/, '');
// Outdent whatever the
// list item contains. Hacky.
if (~item.indexOf('\n ')) {
space -= item.length;
item = !this.options.pedantic
? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
: item.replace(/^ {1,4}/gm, '');
}
// Determine whether the next list item belongs here.
// Backpedal if it does not belong in this list.
if (this.options.smartLists && i !== l - 1) {
b = block.bullet.exec(cap[i+1])[0];
if (bull !== b && !(bull[1] === '.' && b[1] === '.')) {
src = cap.slice(i + 1).join('\n') + src;
i = l - 1;
}
}
// Determine whether item is loose or not.
// Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
// for discount behavior.
loose = next || /\n\n(?!\s*$)/.test(item);
if (i !== l - 1) {
next = item[item.length-1] === '\n';
if (!loose) loose = next;
}
this.tokens.push({
type: loose
? 'loose_item_start'
: 'list_item_start'
});
// Recurse.
this.token(item, false);
this.tokens.push({
type: 'list_item_end'
});
}
this.tokens.push({
type: 'list_end'
});
continue;
}
// html
if (cap = this.rules.html.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: this.options.sanitize
? 'paragraph'
: 'html',
pre: cap[1] === 'pre',
text: cap[0]
});
continue;
}
// def
if (top && (cap = this.rules.def.exec(src))) {
src = src.substring(cap[0].length);
this.tokens.links[cap[1].toLowerCase()] = {
href: cap[2],
title: cap[3]
};
continue;
}
// table (gfm)
if (top && (cap = this.rules.table.exec(src))) {
src = src.substring(cap[0].length);
item = {
type: 'table',
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
};
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right';
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center';
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left';
} else {
item.align[i] = null;
}
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i]
.replace(/^ *\| *| *\| *$/g, '')
.split(/ *\| */);
}
this.tokens.push(item);
continue;
}
// top-level paragraph
if (top && (cap = this.rules.paragraph.exec(src))) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'paragraph',
text: cap[1][cap[1].length-1] === '\n'
? cap[1].slice(0, -1)
: cap[1]
});
continue;
}
// text
if (cap = this.rules.text.exec(src)) {
// Top-level should never reach here.
src = src.substring(cap[0].length);
this.tokens.push({
type: 'text',
text: cap[0]
});
continue;
}
if (src) {
throw new
Error('Infinite loop on byte: ' + src.charCodeAt(0));
}
}
return this.tokens;
};
/**
* Inline-Level Grammar
*/
var inline = {
escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
url: noop,
tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
link: /^!?\[(inside)\]\(href\)/,
reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
br: /^ {2,}\n(?!\s*$)/,
mail: /^([^\s !"#$%'()*+,.\/:;<=>?@\\\[\]\^_`{|}~-]+(@|:\/)[^\s !"#$%'()*+,.\/:;<=>?@\\\[\]\^_`{|}~-]+.[^\s !"#$%'()*+,.\/:;<=>?@\\\[\]\^_`{|}~-]+)/,
mention: /^@([A-Za-z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[A-Za-z0-9!#$%&'*+\/=?\^_`{|}~\-]+)*(?!\*))/,
tags: /^#([^\s!"#$%'()*+,.\/:;<=>?@\\\[\]\^_`{|}~-]+(?:\.[\^!"#$%'()*+,.\/:;<=>?@\\\[\]\^_`{|}~-]+)*)(?!\*)/,
del: noop,
text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
};
inline._inside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
inline._href = /\s*<?([^\s]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
inline.link = replace(inline.link)
('inside', inline._inside)
('href', inline._href)
();
inline.reflink = replace(inline.reflink)
('inside', inline._inside)
();
/**
* Normal Inline Grammar
*/
inline.normal = merge({}, inline);
/**
* Pedantic Inline Grammar
*/
inline.pedantic = merge({}, inline.normal, {
strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
});
/**
* GFM Inline Grammar
*/
inline.gfm = merge({}, inline.normal, {
escape: replace(inline.escape)('])', '~|])')(),
url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
del: /^~~(?=\S)([\s\S]*?\S)~~/,
text: replace(inline.text)
(']|', '#@~]|')
('|', '|https?://|')
('|', '||')
()
});
/**
* GFM + Line Breaks Inline Grammar
*/
inline.breaks = merge({}, inline.gfm, {
br: replace(inline.br)('{2,}', '*')(),
text: replace(inline.gfm.text)('{2,}', '*')()
});
/**
* Inline Lexer & Compiler
*/
function InlineLexer(links, options) {
this.options = options || marked.defaults;
this.links = links;
this.rules = inline.normal;
if (!this.links) {
throw new
Error('Tokens array requires a `links` property.');
}
if (this.options.gfm) {
if (this.options.breaks) {
this.rules = inline.breaks;
} else {
this.rules = inline.gfm;
}
} else if (this.options.pedantic) {
this.rules = inline.pedantic;
}
}
/**
* Expose Inline Rules
*/
InlineLexer.rules = inline;
/**
* Static Lexing/Compiling Method
*/
InlineLexer.output = function(src, links, options) {
var inline = new InlineLexer(links, options);
return inline.output(src);
};
/**
* Lexing/Compiling
*/
InlineLexer.prototype.output = function(src) {
var out = ''
, link
, text
, href
, cap;
while (src) {
// escape
if (cap = this.rules.escape.exec(src)) {
src = src.substring(cap[0].length);
out += cap[1];
continue;
}
// autolink
if (cap = this.rules.autolink.exec(src)) {
src = src.substring(cap[0].length);
if (cap[2] === '@') {
text = cap[1][6] === ':'
? this.mangle(cap[1].substring(7))
: this.mangle(cap[1]);
href = this.mangle('mailto:') + text;
} else {
href = escape(cap[1]);
text = shortenUrl(href);
}
out += '<a href="'
+ href
+ '" target="_blank">'
+ text
+ '</a>';
continue;
}
// autolink
if (cap = this.rules.mail.exec(src)) {
src = src.substring(cap[0].length);
if (cap[2] === '@') {
text = cap[1][6] === ':'
? this.mangle(cap[1].substring(7))
: this.mangle(cap[1]);
href = this.mangle('mailto:') + text;
} else {
href = escape(cap[1]);
text = shortenUrl(href);
}
out += '<a href="'
+ href
+ '" target="_blank">'
+ text
+ '</a>';
continue;
}
// url (gfm)
if (cap = this.rules.url.exec(src)) {
var html;
src = src.substring(cap[0].length);
href = escape(cap[1]);
text = shortenUrl(href);
for(var key in this.options.urls){
html = this.options.urls[key](text, href);
if(html){
out += html;
break;
}
}
if(!html)
out += '<a target="_blank" href="'
+ href
+ '" target="_blank">'
+ text
+ '</a>';
continue;
}
// tag
if (cap = this.rules.tag.exec(src)) {
src = src.substring(cap[0].length);
out += this.options.sanitize
? escape(cap[0])
: cap[0];
continue;
}
// link
if (cap = this.rules.link.exec(src)) {
src = src.substring(cap[0].length);
out += this.outputLink(cap, {
href: cap[2],
title: cap[3]
});
continue;
}
// reflink, nolink
if ((cap = this.rules.reflink.exec(src))
|| (cap = this.rules.nolink.exec(src))) {
src = src.substring(cap[0].length);
link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
link = this.links[link.toLowerCase()];
if (!link || !link.href) {
out += cap[0][0];
src = cap[0].substring(1) + src;
continue;
}
out += this.outputLink(cap, link);
continue;
}
// strong
if (cap = this.rules.strong.exec(src)) {
src = src.substring(cap[0].length);
out += '<strong>'
+ this.output(cap[2] || cap[1])
+ '</strong>';
continue;
}
// em
if (cap = this.rules.em.exec(src)) {
src = src.substring(cap[0].length);
out += '<em>'
+ this.output(cap[2] || cap[1])
+ '</em>';
continue;
}
// code
if (cap = this.rules.code.exec(src)) {
src = src.substring(cap[0].length);
out += '<code>'
+ escape(cap[2], true)
+ '</code>';
continue;
}
// mention
if (cap = inline.mention.exec(src)) {
src = src.substring(cap[0].length);
out += '<span class="link-span" ng-click="vm.goToProfile(\'' + cap[1] + '\')">'
+ cap[0]
+ '</span>';
continue;
}
// tags
if (cap = inline.tags.exec(src)) {
src = src.substring(cap[0].length);
out += '<span class="link-span"' + ' ng-click="vm.goToTagTimeline(\'' + cap[1] + '\')">' + cap[0] + '</span>';
continue;
}
// br
if (cap = this.rules.br.exec(src)) {
src = src.substring(cap[0].length);
out += '<br>';
continue;
}
// del (gfm)
if (cap = this.rules.del.exec(src)) {
src = src.substring(cap[0].length);
out += '<del>'
+ this.output(cap[1])
+ '</del>';
continue;
}
// text
if (cap = this.rules.text.exec(src)) {
src = src.substring(cap[0].length);
out += escape(cap[0]);
continue;
}
if (src) {
throw new
Error('Infinite loop on byte: ' + src.charCodeAt(0));
}
}
return out;
};
/**
* Compile Link
*/
InlineLexer.prototype.outputLink = function(cap, link) {
if (cap[0][0] !== '!') {
return '<a target="_blank" href="'
+ escape(link.href)
+ '"'
+ (link.title
? ' title="'
+ escape(link.title)
+ '"'
: '')
+ '>'
+ this.output(cap[1])
+ '</a>';
} else {
return '<img src="'
+ escape(link.href)
+ '" alt="'
+ escape(cap[1])
+ '"'
+ (link.title
? ' title="'
+ escape(link.title)
+ '"'
: '')
+ '>';
}
};
/**
* Mangle Links
*/
InlineLexer.prototype.mangle = function(text) {
var out = ''
, l = text.length
, i = 0
, ch;
for (; i < l; i++) {
ch = text.charCodeAt(i);
if (Math.random() > 0.5) {
ch = 'x' + ch.toString(16);
}
out += '&#' + ch + ';';
}
return out;
};
/**
* Parsing & Compiling
*/
function Parser(options) {
this.tokens = [];
this.token = null;
this.options = options || marked.defaults;
}
/**
* Static Parse Method
*/
Parser.parse = function(src, options) {
var parser = new Parser(options);
return parser.parse(src);
};
/**
* Parse Loop
*/
Parser.prototype.parse = function(src) {
this.inline = new InlineLexer(src.links, this.options);
this.tokens = src.reverse();
var out = '';
while (this.next()) {
out += this.tok();
}
return out;
};
/**
* Next Token
*/
Parser.prototype.next = function() {
return this.token = this.tokens.pop();
};
/**
* Preview Next Token
*/
Parser.prototype.peek = function() {
return this.tokens[this.tokens.length-1] || 0;
};
/**
* Parse Text Tokens
*/
Parser.prototype.parseText = function() {
var body = this.token.text;
while (this.peek().type === 'text') {
body += '\n' + this.next().text;
}
return this.inline.output(body);
};
/**
* Parse Current Token
*/
Parser.prototype.tok = function() {
switch (this.token.type) {
case 'space': {
return '';
}
case 'hr': {
return '<hr>\n';
}
case 'heading': {
return '<h'
+ this.token.depth
+ '>'
+ this.inline.output(this.token.text)
+ '</h'
+ this.token.depth
+ '>\n';
}
case 'code': {
if (this.options.highlight) {
var code = this.options.highlight(this.token.text, this.token.lang);
if (code != null && code !== this.token.text) {
this.token.escaped = true;
this.token.text = code;
}
}
if (!this.token.escaped) {
this.token.text = escape(this.token.text, true);
}
return '<pre><code'
+ (this.token.lang
? ' class="'
+ this.options.langPrefix
+ this.token.lang
+ '"'
: '')
+ '>'
+ this.token.text
+ '</code></pre>\n';
}
case 'table': {
var body = ''
, heading
, i
, row
, cell
, j;
// header
body += '<thead>\n<tr>\n';
for (i = 0; i < this.token.header.length; i++) {
heading = this.inline.output(this.token.header[i]);
body += this.token.align[i]
? '<th align="' + this.token.align[i] + '">' + heading + '</th>\n'
: '<th>' + heading + '</th>\n';
}
body += '</tr>\n</thead>\n';
// body
body += '<tbody>\n'
for (i = 0; i < this.token.cells.length; i++) {
row = this.token.cells[i];
body += '<tr>\n';
for (j = 0; j < row.length; j++) {
cell = this.inline.output(row[j]);
body += this.token.align[j]
? '<td align="' + this.token.align[j] + '">' + cell + '</td>\n'
: '<td>' + cell + '</td>\n';
}
body += '</tr>\n';
}
body += '</tbody>\n';
return '<table>\n'
+ body
+ '</table>\n';
}
case 'blockquote_start': {
var body = '';
while (this.next().type !== 'blockquote_end') {
body += this.tok();
}
return '<blockquote>\n'
+ body
+ '</blockquote>\n';
}
case 'list_start': {
var type = this.token.ordered ? 'ol' : 'ul'
, body = '';
while (this.next().type !== 'list_end') {
body += this.tok();
}
return '<'
+ type
+ '>\n'
+ body
+ '</'
+ type
+ '>\n';
}
case 'list_item_start': {
var body = '';
while (this.next().type !== 'list_item_end') {
body += this.token.type === 'text'
? this.parseText()
: this.tok();
}
return '<li>'
+ body
+ '</li>\n';
}
case 'loose_item_start': {
var body = '';
while (this.next().type !== 'list_item_end') {
body += this.tok();
}
return '<li>'
+ body
+ '</li>\n';
}
case 'html': {
return !this.token.pre && !this.options.pedantic
? this.inline.output(this.token.text)
: this.token.text;
}
case 'paragraph': {
return '<p>'
+ this.inline.output(this.token.text)
+ '</p>\n';
}
case 'text': {
return '<p>'
+ this.parseText()
+ '</p>\n';
}
}
};
/**
* Helpers
*/
function escape(html, encode) {
return html
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function shortenUrl(url) {
if (url.length < 67) {
return url;
} else {
return url.substring(0, 64) + "...";
}
}
function replace(regex, opt) {
regex = regex.source;
opt = opt || '';
return function self(name, val) {
if (!name) return new RegExp(regex, opt);
val = val.source || val;
val = val.replace(/(^|[^\[])\^/g, '$1');
regex = regex.replace(name, val);
return self;
};
}
function noop() {}
noop.exec = noop;
function merge(obj) {
var i = 1
, target
, key;
for (; i < arguments.length; i++) {
target = arguments[i];
for (key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
obj[key] = target[key];
}
}
}
return obj;
}
/**
* Marked
*/
function marked(src, opt) {
try {
if (opt) opt = merge({}, marked.defaults, opt);
return Parser.parse(Lexer.lex(src, opt), opt);
} catch (e) {
e.message += '\nPlease report this to https://github.com/chjj/marked.';
if ((opt || marked.defaults).silent) {
return '<p>An error occured:</p><pre>'
+ escape(e.message + '', true)
+ '</pre>';
}
throw e;
}
}
/**
* Options
*/
marked.options =
marked.setOptions = function(opt) {
merge(marked.defaults, opt);
return marked;
};
marked.defaults = {
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
// urls : [function(text, url){ return 'html'; }]
smartLists: false,
silent: false,
highlight: null,
langPrefix: 'lang-'
};
/**
* Expose
*/
marked.Parser = Parser;
marked.parser = Parser.parse;
marked.Lexer = Lexer;
marked.lexer = Lexer.lex;
marked.InlineLexer = InlineLexer;
marked.inlineLexer = InlineLexer.output;
marked.parse = marked;
if (typeof exports === 'object') {
module.exports = marked;
} else if (typeof define === 'function' && define.amd) {
define(function() { return marked; });
} else {
this.marked = marked;
}
}).call(function() {
return this || (typeof window !== 'undefined' ? window : global);
}());
================================================
FILE: mobile/www/app/shared/interceptor/auth.interceptor.js
================================================
(function() {
'use strict';
angular.module('tatami')
.factory('authInterceptor', authInterceptor)
.factory('authExpiredInterceptor', authExpiredInterceptor)
.factory('endpointInterceptor', endpointInterceptor);
authInterceptor.$inject = ['$rootScope', '$q', '$location', '$localStorage'];
function authInterceptor($rootScope, $q, $location, $localStorage) {
var interceptor = {
request: request
};
return interceptor;
request.$inject = ['config'];
function request(config) {
config.headers = config.headers || {};
var token = $localStorage.get('token');
if (token && token.expires && token.expires > new Date().getTime()) {
config.headers['x-auth-token'] = token.token;
}
return config;
}
}
authExpiredInterceptor.$inject = ['$q', '$localStorage', '$injector'];
function authExpiredInterceptor($q, $localStorage, $injector) {
var interceptor = {
responseError: responseError
};
return interceptor;
responseError.$inject = ['response'];
function responseError(response) {
if(response.status === 401 && (response.data.error == 'invalid_token' || response.data.error == 'Unauthorized')) {
$localStorage.signOut();
var $state = $injector.get('$state');
$state.go('login');
}
return $q.reject(response);
}
}
/* endpointInterceptor built to replace PathService.buildPath(resource)
*
* Old implementation was causing issues - for some reason, REST path requests randomly started getting cached
* so an attempt to access /rest/authentication wouldn't reach buildPath but would return the endpoint used initially
* This interceptor never caches, so it's a better implementation.
*
* NOTE: Only make requests to server beginning with "/"; only access documents locally using the first folder and
* NOT "/"; static url requests (i.e. to google.com) should begin with http://, NEVER "/".
*
* ONLY USE "/" AS FIRST CHARACTER OF REQUESTS IF YOU NEED THE ENDPOINT URL TO BE A PREFIX
*/
endpointInterceptor.$inject = ['$localStorage'];
function endpointInterceptor($localStorage) {
var interceptor = {
request: request
};
return interceptor;
request.$inject = ['config'];
function request(config) {
if(config.url.indexOf("/") == 0) {
config.url = $localStorage.get('endpoint').url + config.url;
}
return config;
}
}
})();
================================================
FILE: mobile/www/app/shared/providers/provider.js
================================================
(function() {
'use strict';
angular.module('tatami.providers', []);
})();
================================================
FILE: mobile/www/app/shared/providers/tatami.state.provider.js
================================================
(function() {
'use strict';
// This will dynamically create any tab substates inside the current tab. If in the timeline tab, we will
// create a timeline.status state
angular.module('tatami.providers')
.provider('TatamiState', tatamiState);
tatamiState.$inject = ['$stateProvider'];
function tatamiState($stateProvider) {
this.$get = tatamiStateHelper;
function tatamiStateHelper() {
var profileViewConfig = {
templateUrl: 'app/shared/state/profile/profile.html',
controller: 'ProfileCtrl',
controllerAs: 'vm'
};
var profileViews = [];
profileViews['suggested@follow'] = { 'suggested@follow': profileViewConfig };
profileViews['following@follow'] = { 'following@follow': profileViewConfig };
profileViews['follower@follow'] = { 'follower@follow': profileViewConfig };
profileViews['timeline@home'] = { 'timeline@home': profileViewConfig };
profileViews['mentions@home'] = { 'mentions@home': profileViewConfig };
profileViews['favorites@home'] = { 'favorites@home': profileViewConfig };
profileViews['more@home'] = { 'more@home': profileViewConfig };
profileViews['company@home'] = { 'more@home': profileViewConfig };
profileViews['blockedusers@home'] = { 'more@home': profileViewConfig };
profileViews['allusers@home'] = { 'more@home': profileViewConfig };
var conversationViewConfig = {
templateUrl: 'app/shared/state/conversation/conversation.html',
controller: 'ConversationCtrl',
controllerAs: 'vm'
};
var conversationViews = [];
conversationViews['suggested@follow'] = { 'suggested@follow': conversationViewConfig };
conversationViews['following@follow'] = { 'following@follow': conversationViewConfig };
conversationViews['follower@follow'] = { 'follower@follow': conversationViewConfig };
conversationViews['timeline@home'] = { 'timeline@home': conversationViewConfig };
conversationViews['mentions@home'] = { 'mentions@home': conversationViewConfig };
conversationViews['favorites@home'] = { 'favorites@home': conversationViewConfig };
conversationViews['company@home'] = { 'more@home': conversationViewConfig };
conversationViews['blockedusers@home'] = { 'more@home': profileViewConfig };
conversationViews['allusers@home'] = { 'more@home': profileViewConfig };
var tagViewConfig = {
templateUrl: 'app/shared/state/tag/tag.html',
controller: 'TagCtrl',
controllerAs: 'vm'
};
var tagViews = [];
tagViews['suggested@follow'] = { 'suggested@follow': tagViewConfig };
tagViews['following@follow'] = { 'following@follow': tagViewConfig };
tagViews['follower@follow'] = { 'follower@follow': tagViewConfig };
tagViews['timeline@home'] = { 'timeline@home': tagViewConfig };
tagViews['mentions@home'] = { 'mentions@home': tagViewConfig };
tagViews['favorites@home'] = { 'favorites@home': tagViewConfig };
tagViews['company@home'] = { 'more@home': tagViewConfig };
tagViews['blockedusers@home'] = { 'more@home': profileViewConfig };
tagViews['allusers@home'] = { 'more@home': profileViewConfig };
var service = {
addProfileState: addProfileState,
addConversationState: addConversationState,
addTagState: addTagState
};
addProfileState.$inject = ['prefixName', 'parentName'];
function addProfileState(prefixName, parentName) {
$stateProvider.state(prefixName + '.profile', {
url: '/profile/:username',
views: profileViews[prefixName + '@' + parentName],
resolve: {
user: getUser,
statuses: getStatuses,
currentUser: getCurrentUser
}
});
getUser.$inject = ['UserService', '$stateParams'];
function getUser(UserService, $stateParams) {
return UserService.get({ username : $stateParams.username }).$promise;
}
getStatuses.$inject = ['user', 'StatusService'];
function getStatuses(user, StatusService) {
return StatusService.getUserTimeline({ username: user.username }).$promise;
}
getCurrentUser.$inject = ['currentUser'];
function getCurrentUser(currentUser) {
return currentUser;
}
}
addConversationState.$inject = ['prefixName', 'parentName'];
function addConversationState(prefixName, parentName) {
$stateProvider.state(prefixName + '.conversation', {
url: '/conversation/:statusId',
views: conversationViews[prefixName + '@' + parentName],
resolve: {
originalStatus: getOriginalStatus,
conversation: getConversation
}
});
getOriginalStatus.$inject = ['StatusService', '$stateParams'];
function getOriginalStatus(StatusService, $stateParams) {
return StatusService.get({ statusId : $stateParams.statusId }).$promise;
}
getConversation.$inject = ['StatusService', '$stateParams'];
function getConversation(StatusService, $stateParams) {
return StatusService.getDetails({ statusId : $stateParams.statusId }).$promise;
}
}
addTagState.$inject = ['prefixName', 'parentName'];
function addTagState(prefixName, parentName) {
$stateProvider.state(prefixName + '.tag', {
url: '/tag/:tag',
views: tagViews[prefixName + '@' + parentName],
resolve: {
tag: getTag,
statuses: getStatuses
}
});
getTag.$inject = ['$stateParams'];
function getTag($stateParams) {
return $stateParams.tag;
}
getStatuses.$inject = ['TagService', '$stateParams'];
function getStatuses(TagService, $stateParams) {
return TagService.getTagTimeline({ tag: $stateParams.tag }).$promise;
}
}
return service;
}
}
})();
================================================
FILE: mobile/www/app/shared/services/HomeService.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('HomeService', homeService);
homeService.$inject = ['$resource', 'PathService'];
function homeService($resource, PathService) {
return $resource(null, null,
{
'getMentions': {
method: 'GET', isArray: true, url: '/tatami/rest/mentions',
transformResponse: responseTransform
},
'getFavorites': {
method: 'GET', isArray: true, url: '/tatami/rest/favorites',
transformResponse: responseTransform
},
'getCompanyTimeline': {
method: 'GET', isArray: true, url: '/tatami/rest/company',
transformResponse: responseTransform
}
});
responseTransform.$inject = ['statuses'];
function responseTransform(statuses) {
statuses = angular.fromJson(statuses);
for(var i = 0; i < statuses.length; i++) {
statuses[i]['avatarURL'] = PathService.getAvatar(statuses[i]);
if(statuses[i].geoLocalization) {
var latitude = statuses[i].geoLocalization.split(',')[0].trim();
var longitude = statuses[i].geoLocalization.split(',')[1].trim();
statuses[i]['locationURL'] =
'https://www.openstreetmap.org/?mlon='
+ longitude + '&mlat=' + latitude;
}
}
return statuses;
}
}
})();
================================================
FILE: mobile/www/app/shared/services/ProfileService.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('ProfileService', profileService);
profileService.$inject = ['$resource', 'PathService'];
function profileService($resource, PathService) {
return $resource('/tatami/rest/account/profile', null,
{
'get': {
method: 'GET',
transformResponse: function (profile) {
profile = angular.fromJson(profile);
profile['avatarURL'] = PathService.getAvatar(profile);
return profile;
}
},
'update': {
method: 'PUT',
transformRequest: function (profile) {
delete profile['avatarURL'];
return angular.toJson(profile);
}
}
});
}
})();
================================================
FILE: mobile/www/app/shared/services/StatusService.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('StatusService', statusService);
statusService.$inject = ['$resource', 'PathService'];
function statusService($resource, PathService) {
var responseTransform = function (statuses) {
statuses = angular.fromJson(statuses);
for (var i = 0; i < statuses.length; i++) {
statuses[i]['avatarURL'] = PathService.getAvatar(statuses[i]);
if (statuses[i].geoLocalization) {
var latitude = statuses[i].geoLocalization.split(',')[0].trim();
var longitude = statuses[i].geoLocalization.split(',')[1].trim();
statuses[i]['locationURL'] =
'https://www.openstreetmap.org/?mlon='
+ longitude + '&mlat=' + latitude;
}
}
return statuses;
};
return $resource('/tatami/rest/statuses/:statusId', null,
{
'get': {
method: 'GET',
cache: false,
transformResponse: function (status) {
status = angular.fromJson(status);
status.avatarURL = PathService.getAvatar(status);
if (status.geoLocalization) {
var latitude = status.geoLocalization.split(',')[0].trim();
var longitude = status.geoLocalization.split(',')[1].trim();
status['locationURL'] =
'https://www.openstreetmap.org/?mlon='
+ longitude + '&mlat=' + latitude;
}
return status;
}
},
'getHomeTimeline': {
method: 'GET',
isArray: true,
url: '/tatami/rest/statuses/home_timeline',
cache: false,
transformResponse: responseTransform
},
'getUserTimeline': {
method: 'GET',
isArray: true,
params: {username: '@username'},
url: '/tatami/rest/statuses/:username/timeline',
cache: false,
transformResponse: responseTransform
},
'getDetails': {
method: 'GET',
params: {statusId: '@statusId'},
url: '/tatami/rest/statuses/details/:statusId',
cache: false,
transformResponse: function (details) {
details = angular.fromJson(details);
for (var i = 0; i < details.discussionStatuses.length; i++) {
details.discussionStatuses[i]['avatarURL'] = PathService.getAvatar(details.discussionStatuses[i]);
if (details.discussionStatuses[i].geoLocalization) {
var latitude = details.discussionStatuses[i].geoLocalization.split(',')[0].trim();
var longitude = details.discussionStatuses[i].geoLocalization.split(',')[1].trim();
details.discussionStatuses[i]['locationURL'] =
'https://www.openstreetmap.org/?mlon='
+ longitude + '&mlat=' + latitude;
}
}
for (var i = 0; i < details.sharedByLogins.length; i++) {
details.sharedByLogins[i]['avatarURL'] = PathService.getAvatar(details.sharedByLogins[i]);
}
return details;
}
},
'update': {method: 'PATCH', cache: false, params: {statusId: '@statusId'}},
'announce': {method: 'PATCH', cache: false, params: {params: '@statusId'}},
'hideStatus': {
method: 'POST',
params: {statusId: '@statusId'},
cache: false,
url: '/tatami/rest/statuses/hide/:statusId'
}
});
}
})();
================================================
FILE: mobile/www/app/shared/services/UserService.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('UserService', userService);
userService.$inject = ['$resource', 'PathService'];
function userService($resource, PathService) {
var responseTransform = function (users) {
users = angular.fromJson(users);
for (var i = 0; i < users.length; i++) {
users[i]['avatarURL'] = PathService.getAvatar(users[i]);
}
return users;
};
return $resource('/tatami/rest/users/:username', null,
{
'get': {
method: 'GET', params: {username: '@username'},
cache: false,
transformResponse: function (user) {
user = angular.fromJson(user);
user['avatarURL'] = PathService.getAvatar(user);
return user;
}
},
'query': {
method: 'GET',
isArray: true,
url: '/tatami/rest/users',
transformResponse: responseTransform
},
'getFollowing': {
method: 'GET',
isArray: true,
params: {username: '@username'},
url: '/tatami/rest/users/:username/friends',
transformResponse: responseTransform
},
'getFollowers': {
method: 'GET',
isArray: true,
params: {username: '@username'},
url: '/tatami/rest/users/:username/followers',
transformResponse: responseTransform
},
'getSuggestions': {
method: 'GET',
isArray: true,
url: '/tatami/rest/users/suggestions',
transformResponse: function (suggestions) {
suggestions = angular.fromJson(suggestions);
for (var i = 0; i < suggestions.length; i++) {
suggestions[i]['avatarURL'] = PathService.getAvatar(suggestions[i]);
suggestions[i]['followingUser'] = false;
}
return suggestions;
}
},
'follow': {
method: 'PATCH',
params: {username: '@username'}
},
'searchUsers': {
method: 'GET',
isArray: true,
url: '/tatami/rest/users/:term',
transformResponse: responseTransform
},
'deactivate': {
method: 'PATCH',
params: {username: '@username'}
}
});
}
})();
================================================
FILE: mobile/www/app/shared/services/account.service.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('AccountService', accountService);
accountService.$inject = ['$resource', 'PathService'];
function accountService($resource, PathService) {
return $resource('/tatami/rest/account/admin', null, null);
}
})();
================================================
FILE: mobile/www/app/shared/services/block.service.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('BlockService', blockService);
blockService.$inject = ['$resource', 'PathService'];
function blockService($resource, PathService) {
var responseTransform = function (users) {
users = angular.fromJson(users);
for (var i = 0; i < users.length; i++) {
users[i]['avatarURL'] = PathService.getAvatar(users[i]);
}
return users;
};
return $resource(null, null,
{
'getBlockedUsersForUser': {
method: 'GET',
isArray: true,
params: {username: '@username'},
url: '/tatami/rest/block/blockedusers/:username',
transformResponse: responseTransform
},
'updateBlockedUser': {
method: 'PATCH',
params: { username: '@username'},
url: '/tatami/rest/block/update/:username',
transformResponse: function (blockedUser) {
blockedUser = angular.fromJson(blockedUser);
return blockedUser;
}
}
});
}
})();
================================================
FILE: mobile/www/app/shared/services/localStorage.service.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('$localStorage', localStorage);
localStorage.$inject = ['$window'];
function localStorage($window) {
var service = {
get: getFromLocalStorage,
set: setFromLocalStorage,
signOut: clearToken
};
return service;
getFromLocalStorage.$inject = ['key'];
function getFromLocalStorage(key) {
if(isLocalStorageUndefined(key)) {
return undefined;
}
return JSON.parse($window.localStorage[key] || '{}');
}
setFromLocalStorage.$inject = ['key', 'value'];
function setFromLocalStorage(key, value) {
$window.localStorage[key] = JSON.stringify(value);
}
function clearToken() {
$window.localStorage.removeItem('token');
}
isLocalStorageUndefined.$inject = ['key'];
function isLocalStorageUndefined(key) {
return $window.localStorage.length === 0 || $window.localStorage[key] === 'undefined';
}
}
})();
================================================
FILE: mobile/www/app/shared/services/path.service.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('PathService', avatarService);
avatarService.$inject = ['TatamiEndpoint'];
function avatarService(TatamiEndpoint) {
var service = {
getAvatar: getAvatar
};
return service;
getAvatar.$inject = ['user'];
function getAvatar(user) {
return TatamiEndpoint.getEndpoint().url + (user.avatar && user.avatar !== '' ? '/tatami/avatar/' + user.avatar + '/photo.jpg' : '/assets/img/default_image_profile.png');
}
//buildPath() removed - REST endpoints being accessed were being cached, leading to issues when swapping endpoints
//new implementation intercepts url requests beginning with "/" and tacks on the current endpoint url as a prefix
}
})();
================================================
FILE: mobile/www/app/shared/services/report.service.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('ReportService', reportService);
reportService.$inject = ['$resource', 'PathService'];
function reportService($resource, PathService) {
var responseTransform = function (statuses) {
statuses = angular.fromJson(statuses);
for (var i = 0; i < statuses.length; i++) {
statuses[i]['avatarURL'] = PathService.getAvatar(statuses[i]);
}
return statuses;
};
return $resource('/tatami/rest/statuses/report/:statusId', null,
{
'reportStatus': {
method: 'POST',
params: {statusId: '@statusId'}
},
'getReportedStatuses': {
method: 'GET',
isArray: true,
url: '/tatami/rest/statuses/report/reportedList',
transformResponse: responseTransform
},
'approveStatus': {
method : 'DELETE',
params: {statusId: '@statusId'}
},
'deleteStatus': {
method: 'PUT',
params: {statusId: '@statusId'}
}
});
}
})();
================================================
FILE: mobile/www/app/shared/services/service.js
================================================
(function() {
'use strict';
angular.module('tatami.services', []);
})();
================================================
FILE: mobile/www/app/shared/services/tag.service.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('TagService', tagService);
tagService.$inject = ['$resource', 'PathService'];
function tagService($resource, PathService) {
return $resource('/tatami/rest/tags', null,
{
'get': { method:'GET', params: { tag: '@tag' }, url: '/tatami/rest/tags/:tag' },
'getTagTimeline': {
method:'GET', isArray: true, params: { tag: '@tag' }, url: '/tatami/rest/tags/:tag/tag_timeline',
transformResponse: function(statuses) {
statuses = angular.fromJson(statuses);
for(var i = 0; i < statuses.length; i++) {
statuses[i]['avatarURL'] = PathService.getAvatar(statuses[i]);
if(statuses[i].geoLocalization) {
var latitude = statuses[i].geoLocalization.split(',')[0].trim();
var longitude = statuses[i].geoLocalization.split(',')[1].trim();
statuses[i]['locationURL'] =
'https://www.openstreetmap.org/?mlon='
+ longitude + '&mlat=' + latitude;
}
}
return statuses;
}
},
'follow': { method:'PUT', params: { tag: '@tag' }, url: '/tatami/rest/tags/:tag' },
'getPopular': { method: 'GET', isArray: true, url: '/tatami/rest/tags/popular' }
});
}
})();
================================================
FILE: mobile/www/app/shared/services/toast.service.js
================================================
(function() {
'use strict';
angular.module('tatami.services')
.factory('ToastService', ToastService);
ToastService.$inject = ['$window', '$translate', 'ionicToast'];
function ToastService($window, $translate, ionicToast) {
var service = {
display: displayToast
};
return service;
function displayToast(toastMessage){
$translate(toastMessage).then(function(msg){
if (ionic.Platform.isIOS()){
ionicToast.show(msg, 'top', false, 2000);
}
else{
ionicToast.show(msg, 'bottom', false, 2000);
}
});
}
}
})();
================================================
FILE: mobile/www/app/shared/state/conversation/conversation.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('ConversationCtrl', conversationCtrl);
conversationCtrl.$inject = ['$ionicPopup', '$ionicHistory', '$state', 'originalStatus', 'conversation', 'currentUser'];
function conversationCtrl($ionicPopup, $ionicHistory, $state, originalStatus, conversation, currentUser) {
var vm = this;
vm.conversation = buildStatusList();
vm.currentUser = currentUser;
function buildStatusList() {
try {
return conversation.discussionStatuses.concat(originalStatus).sort(byDate);
} catch (error) {
var deletedPopup = $ionicPopup.alert({
title: 'Status Not Found!',
template: 'The original status has been deleted. <br>Returning to previous state.'
});
deletedPopup.then(goBack);
}
}
function goBack() {
$ionicHistory.goBack();
}
byDate.$inject = ['first', 'second'];
function byDate(first, second) {
return first.statusDate - second.statusDate;
}
}
})();
================================================
FILE: mobile/www/app/shared/state/conversation/conversation.html
================================================
<ion-view view-title="{{ 'conversation.title' | translate }}">
<tatami-status-list statuses="vm.conversation"
current-user="vm.currentUser"></tatami-status-list>
</ion-view>
================================================
FILE: mobile/www/app/shared/state/profile/profile.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('ProfileCtrl', profileCtrl);
profileCtrl.$inject = ['$ionicPopover', '$ionicPopup', '$scope', '$translate', 'user', 'statuses', 'currentUser', 'TatamiStatusRefresherService', 'UserService', 'BlockService'];
function profileCtrl($ionicPopover, $ionicPopup, $scope, $translate, user, statuses, currentUser, TatamiStatusRefresherService, UserService, BlockService) {
var vm = this;
vm.user = user;
vm.statuses = statuses;
vm.currentUser = currentUser;
vm.isCurrentUser = (vm.currentUser.username === vm.user.username);
vm.customHeight = (vm.currentUser.isAdmin) ? {'height': '120px'} : {'height': '70px'}; //Adapts the height of the popover depending on the role because a different number of buttons is displayed
vm.followUser = followUser;
vm.getNewStatuses = getNewStatuses;
vm.toggleActivateUser = toggleActivateUser;
vm.blockUser = blockUser;
function getNewStatuses() {
return TatamiStatusRefresherService.refreshUserTimeline(user).then(setStatuses);
}
setStatuses.$inject = ['statuses'];
function setStatuses(statuses) {
vm.statuses = statuses;
}
function followUser() {
UserService.follow({ username : vm.user.username }, { friend: !vm.user.friend, friendShip: true },
function() {
vm.user.friend = !vm.user.friend;
});
}
function toggleActivateUser() {
var confirmPopup;
if (vm.user.activated) {
confirmPopup = $ionicPopup.confirm({
title: $translate.instant('user.deactivate.title'),
template: '<span translate="user.deactivate.confirmation"></span>'
});
} else {
confirmPopup = $ionicPopup.confirm({
title: $translate.instant('user.reactivate.title'),
template: '<span translate="user.reactivate.confirmation"></span>'
});
}
confirmPopup.then(checkDelete);
checkDelete.$inject = ['decision'];
function checkDelete(decision) {
if(decision) {
UserService.deactivate({ username : vm.user.username }, {activate: true},
function() {
vm.user.activated = !vm.user.activated;
});
}
}
}
function blockUser() {
var confirmPopup = $ionicPopup.confirm({
title: $translate.instant('user.block.title'),
template: '<span translate="user.block.confirmation"></span>'
});
confirmPopup.then(checkDelete);
checkDelete.$inject = ['decision'];
function checkDelete(decision) {
if(decision) {
BlockService.updateBlockedUser( {username: vm.user.username }, function () {
ToastService.display('user.block.success');
}
);
}
}
}
$ionicPopover.fromTemplateUrl('app/shared/state/profile/userOptionsMenu.html', {
scope: $scope
}).then(function(popover) {
$scope.popover = popover;
});
}
})();
================================================
FILE: mobile/www/app/shared/state/profile/profile.html
================================================
<ion-view view-title="@{{ vm.user.username }}">
<ion-nav-buttons side="secondary">
<button class="button ion-gear-a"
ng-if="!vm.isCurrentUser"
style="font-size: 30px;"
ng-click="popover.show($event)"></button>
<button class="button ion-person-add"
ng-if="!vm.isCurrentUser"
ng-class="{ 'button-calm' : vm.user.friend, 'button-stable button-outline' : !vm.user.friend }"
style="font-size: 30px;"
ng-click="vm.followUser()"></button>
</ion-nav-buttons>
<ion-content class="tatami-header tatami-footer" ng-style="{'background-color':'#f5f5f5'}">
<ion-refresher on-refresh="vm.getNewStatuses()"></ion-refresher>
<tatami-user-detail user="vm.user"></tatami-user-detail>
<ion-list>
<ion-item ng-repeat="status in vm.statuses">
<tatami-status status="status" current-user="vm.currentUser"></tatami-status>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
================================================
FILE: mobile/www/app/shared/state/profile/userOptionsMenu.html
================================================
<ion-popover-view ng-style="vm.customHeight" scroll="false">
<ion-content>
<div class="list" ng-click="popover.hide()">
<a class="item assertive" target="_blank" ng-click="vm.blockUser()">
<span class="ion-close-circled padding-right"></span>
<span translate="user.profile.options.block"></span>
</a>
<a class="item assertive" ng-if="vm.currentUser.isAdmin && vm.user.activated" ng-click="vm.toggleActivateUser()" >
<span class="ion-trash-a padding-right"></span>
<span translate="user.profile.options.deactivate"></span>
</a>
<a class="item calm" ng-if="vm.currentUser.isAdmin && !vm.user.activated" ng-click="vm.toggleActivateUser()" >
<span class="ion-trash-a padding-right"></span>
<span translate="user.profile.options.reactivate"></span>
</a>
</div>
</ion-content>
</ion-popover-view>
================================================
FILE: mobile/www/app/shared/state/tag/tag.controller.js
================================================
(function() {
'use strict';
angular.module('tatami')
.controller('TagCtrl', tagCtrl);
tagCtrl.$inject = ['tag', 'statuses', 'currentUser', 'TatamiStatusRefresherService'];
function tagCtrl(tag, statuses, currentUser, TatamiStatusRefresherService) {
var vm = this;
vm.tag = tag;
vm.statuses = statuses;
vm.currentUser = currentUser;
vm.getNewStatuses = getNewStatuses;
vm.getOldStatuses = getOldStatuses;
function getNewStatuses() {
return TatamiStatusRefresherService.refreshTagTimeline(vm.tag);
}
getOldStatuses.$inject = ['finalStatus'];
function getOldStatuses(finalStatus) {
return TatamiStatusRefresherService.getOldTags(finalStatus, vm.tag)
}
}
})();
================================================
FILE: mobile/www/app/shared/state/tag/tag.html
================================================
<ion-view view-title="#{{ vm.tag }}">
<tatami-status-list statuses="vm.statuses"
current-user="vm.currentUser"
tatami-refresher="vm.getNewStatuses()"
tatami-infinite-refresher="vm.getOldStatuses(finalStatus)"></tatami-status-list>
</ion-view>
================================================
FILE: mobile/www/app/shared/status/blockUserMenu.html
================================================
<ion-popover-view ng-style="vm.customHeight">
<ion-content>
<div class="list" ng-click="popover.hide()">
<a class="item" ng-if="vm.currentUser.isAdmin" ng-click="vm.announceStatus()" >
<span class="ion-speakerphone padding-right"></span>
<span class="right" translate="status.announcement.action"></span>
</a>
<a class="item" target="_blank" ng-click="vm.hideStatus()">
<span class="ion-minus-round padding-right"></span>
<span translate="status.hide.action" right></span>
</a>
<a class="item" target="_blank" ng-click="vm.reportStatus()">
<span class="ion-alert padding-right"></span>
<span class="html-editor-align-right" translate="status.block.reportStatus"></span>
</a>
<a class="item" target="_blank" ng-click="vm.blockUser()">
<span class="ion-close-circled padding-right"></span>
<span translate="status.block.blockUser"></span>
</a>
<a class="item assertive" ng-if="vm.currentUser.isAdmin" ng-click="vm.remove()" >
<span class="ion-trash-a padding-right"></span>
<span translate="status.block.delete"></span>
</a>
</div>
</ion-content>
</ion-popover-view>
================================================
FILE: mobile/www/app/shared/status/list/status-list.html
================================================
<ion-content class="tatami-header tatami-footer">
<ion-refresher ng-if="!vm.$state.includes('*.conversation')" on-refresh="vm.getNewStatuses()"></ion-refresher>
<ion-list>
<ion-item ng-repeat="status in vm.statuses">
<tatami-status status="status" current-user="vm.currentUser" on-delete="vm.remove(status)"></tatami-status>
</ion-item>
<div class="text-center" ng-if="!vm.statuses.length" translate="status.noContent" ng-style="{'color':'#ababab','padding':'40px'}"/>
</ion-list>
<ion-infinite-scroll ng-if="!vm.finishedTimeline && !vm.$state.includes('*.conversation')" on-infinite="vm.getNewInfiniteScrollStatuses()"></ion-infinite-scroll>
</ion-content>
================================================
FILE: mobile/www/app/shared/status/list/status.list.directive.js
================================================
(function() {
'use strict';
angular.module('tatami')
.directive('tatamiStatusList', tatamiStatusList);
function tatamiStatusList() {
var directive = {
restrict: 'E',
scope: {
statuses: '=',
currentUser: '=',
tatamiRefresher: '&',
tatamiInfiniteRefresher: '&'
},
controller: controller,
controllerAs: 'vm',
templateUrl: 'app/shared/status/list/status-list.html'
};
return directive;
}
controller.$inject = ['$scope', '$state'];
function controller($scope, $state) {
var vm = this;
vm.statuses = $scope.statuses;
vm.currentUser = $scope.currentUser;
vm.$state = $state;
vm.getNewStatuses = getNewStatuses;
vm.getNewInfiniteScrollStatuses = getNewInfiniteScrollStatuses;
vm.remove = remove;
vm.finishedTimeline = vm.statuses && vm.statuses.length < 20;
function getNewStatuses() {
$scope.tatamiRefresher().then(setStatuses);
}
function getNewInfiniteScrollStatuses() {
if(vm.statuses && vm.statuses.length > 0) {
var lastStatus = vm.statuses[vm.statuses.length - 1].timelineId;
$scope.tatamiInfiniteRefresher({ finalStatus: lastStatus }).then(addNewStatuses);
}
}
remove.$inject = ['status'];
function remove(status) {
vm.statuses.splice(vm.statuses.indexOf(status), 1);
}
setStatuses.$inject = ['statuses'];
function setStatuses(statuses) {
vm.statuses = statuses;
}
addNewStatuses.$inject = ['oldStatuses'];
function addNewStatuses(oldStatuses) {
if(oldStatuses.length === 0) {
vm.finishedTimeline = true;
}
vm.statuses.push.apply(vm.statuses, oldStatuses);
}
}
})();
================================================
FILE: mobile/www/app/shared/status/status.directive.js
================================================
(function() {
'use strict';
angular.module('tatami')
.directive('tatamiStatus', tatamiStatus);
function tatamiStatus() {
var directive = {
restrict: 'E',
scope: {
status: '=',
currentUser: '=',
gitextract_2urwtjut/
├── .gitignore
├── CONTRIBUTING.md
├── README.md
├── etc/
│ └── installation/
│ └── ubuntu/
│ ├── files/
│ │ └── maven/
│ │ └── settings.xml
│ ├── install.sh
│ ├── uninstall.sh
│ └── update.sh
├── jenkinsScripts/
│ ├── insertGoogleAuthKeys.sh
│ ├── restoreDatabase.sh
│ ├── saveDatabase.sh
│ ├── startTatami.sh
│ └── stopTatami.sh
├── mobile/
│ ├── .bowerrc
│ ├── .editorconfig
│ ├── .gitignore
│ ├── README.md
│ ├── bower.json
│ ├── config.xml
│ ├── gulpfile.js
│ ├── hooks/
│ │ ├── README.md
│ │ └── after_prepare/
│ │ └── 010_add_platform_class.js
│ ├── ionic.project
│ ├── karma.ci.conf.js
│ ├── package.json
│ ├── pom.xml
│ ├── resources/
│ │ ├── icon.psd
│ │ └── splash.psd
│ ├── scss/
│ │ └── ionic.app.scss
│ └── www/
│ ├── app/
│ │ ├── components/
│ │ │ ├── follow/
│ │ │ │ ├── follow.html
│ │ │ │ ├── follow.js
│ │ │ │ ├── follower/
│ │ │ │ │ ├── follower.controller.js
│ │ │ │ │ ├── follower.html
│ │ │ │ │ └── follower.js
│ │ │ │ ├── following/
│ │ │ │ │ ├── following.controller.js
│ │ │ │ │ ├── following.html
│ │ │ │ │ └── following.js
│ │ │ │ └── suggested/
│ │ │ │ ├── suggested.controller.js
│ │ │ │ ├── suggested.html
│ │ │ │ └── suggested.js
│ │ │ ├── home/
│ │ │ │ ├── favorites/
│ │ │ │ │ ├── favorites.controller.js
│ │ │ │ │ ├── favorites.html
│ │ │ │ │ └── favorites.js
│ │ │ │ ├── home.html
│ │ │ │ ├── home.js
│ │ │ │ ├── mentions/
│ │ │ │ │ ├── mentions.controller.js
│ │ │ │ │ ├── mentions.html
│ │ │ │ │ └── mentions.js
│ │ │ │ ├── more/
│ │ │ │ │ ├── all_users/
│ │ │ │ │ │ ├── all.users.controller.js
│ │ │ │ │ │ ├── all.users.html
│ │ │ │ │ │ └── all.users.js
│ │ │ │ │ ├── blocked_users/
│ │ │ │ │ │ ├── blocked.users.controller.js
│ │ │ │ │ │ ├── blocked.users.html
│ │ │ │ │ │ └── blocked.users.js
│ │ │ │ │ ├── company/
│ │ │ │ │ │ ├── company-timeline.html
│ │ │ │ │ │ ├── company.timeline.controller.js
│ │ │ │ │ │ └── company.timeline.js
│ │ │ │ │ ├── more.controller.js
│ │ │ │ │ ├── more.html
│ │ │ │ │ ├── more.js
│ │ │ │ │ ├── reportedStatus/
│ │ │ │ │ │ ├── reportedStatus.controller.js
│ │ │ │ │ │ ├── reportedStatus.html
│ │ │ │ │ │ └── reportedStatus.js
│ │ │ │ │ └── settings/
│ │ │ │ │ ├── settings.controller.js
│ │ │ │ │ ├── settings.html
│ │ │ │ │ └── settings.js
│ │ │ │ └── timeline/
│ │ │ │ ├── timeline.controller.js
│ │ │ │ ├── timeline.html
│ │ │ │ └── timeline.js
│ │ │ ├── login/
│ │ │ │ ├── login.controller.js
│ │ │ │ ├── login.html
│ │ │ │ ├── login.js
│ │ │ │ └── server/
│ │ │ │ ├── server.controller.js
│ │ │ │ ├── server.html
│ │ │ │ └── server.js
│ │ │ └── post/
│ │ │ ├── post.controller.js
│ │ │ ├── post.html
│ │ │ ├── post.js
│ │ │ └── postbar.directive.js
│ │ ├── shared/
│ │ │ ├── config/
│ │ │ │ ├── marked.config.js
│ │ │ │ ├── marked.filter.js
│ │ │ │ └── tatami.marked.js
│ │ │ ├── interceptor/
│ │ │ │ └── auth.interceptor.js
│ │ │ ├── providers/
│ │ │ │ ├── provider.js
│ │ │ │ └── tatami.state.provider.js
│ │ │ ├── services/
│ │ │ │ ├── HomeService.js
│ │ │ │ ├── ProfileService.js
│ │ │ │ ├── StatusService.js
│ │ │ │ ├── UserService.js
│ │ │ │ ├── account.service.js
│ │ │ │ ├── block.service.js
│ │ │ │ ├── localStorage.service.js
│ │ │ │ ├── path.service.js
│ │ │ │ ├── report.service.js
│ │ │ │ ├── service.js
│ │ │ │ ├── tag.service.js
│ │ │ │ └── toast.service.js
│ │ │ ├── state/
│ │ │ │ ├── conversation/
│ │ │ │ │ ├── conversation.controller.js
│ │ │ │ │ └── conversation.html
│ │ │ │ ├── profile/
│ │ │ │ │ ├── profile.controller.js
│ │ │ │ │ ├── profile.html
│ │ │ │ │ └── userOptionsMenu.html
│ │ │ │ └── tag/
│ │ │ │ ├── tag.controller.js
│ │ │ │ └── tag.html
│ │ │ ├── status/
│ │ │ │ ├── blockUserMenu.html
│ │ │ │ ├── list/
│ │ │ │ │ ├── status-list.html
│ │ │ │ │ └── status.list.directive.js
│ │ │ │ ├── status.directive.js
│ │ │ │ ├── status.html
│ │ │ │ └── status.refresher.service.js
│ │ │ └── user/
│ │ │ ├── user-detail.html
│ │ │ ├── user.detail.directive.js
│ │ │ ├── user.directive.js
│ │ │ ├── user.html
│ │ │ ├── user.refresher.service.js
│ │ │ ├── users.directive.js
│ │ │ └── users.html
│ │ ├── tatami.controller.js
│ │ ├── tatami.endpoint.js
│ │ ├── tatami.html
│ │ └── tatamiApp.js
│ ├── css/
│ │ ├── ionic.app.css
│ │ └── style.css
│ ├── i18n/
│ │ ├── en/
│ │ │ ├── conversation.json
│ │ │ ├── follow.json
│ │ │ ├── home.json
│ │ │ ├── login.json
│ │ │ ├── more.json
│ │ │ ├── post.json
│ │ │ ├── server.json
│ │ │ ├── status.json
│ │ │ └── user.json
│ │ └── fr/
│ │ ├── conversation.json
│ │ ├── follow.json
│ │ ├── home.json
│ │ ├── login.json
│ │ ├── more.json
│ │ ├── post.json
│ │ ├── server.json
│ │ ├── status.json
│ │ └── user.json
│ ├── index.html
│ └── test/
│ └── javascript/
│ └── components/
│ └── profile/
│ └── profile.controller.spec.js
├── pom.xml
├── scripts/
│ └── insertBuildVersion.sh
├── services/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── fr/
│ │ │ │ └── ippon/
│ │ │ │ └── tatami/
│ │ │ │ ├── config/
│ │ │ │ │ ├── ApplicationConfiguration.java
│ │ │ │ │ ├── AsyncConfiguration.java
│ │ │ │ │ ├── CacheConfiguration.java
│ │ │ │ │ ├── CassandraConfiguration.java
│ │ │ │ │ ├── ColumnFamilyKeys.java
│ │ │ │ │ ├── Constants.java
│ │ │ │ │ ├── DispatcherServletConfig.java
│ │ │ │ │ ├── GroupRoles.java
│ │ │ │ │ ├── MailConfiguration.java
│ │ │ │ │ ├── MetricsConfiguration.java
│ │ │ │ │ ├── SearchConfiguration.java
│ │ │ │ │ └── metrics/
│ │ │ │ │ ├── CassandraHealthCheck.java
│ │ │ │ │ └── JavaMailHealthCheck.java
│ │ │ │ ├── domain/
│ │ │ │ │ ├── Attachment.java
│ │ │ │ │ ├── Avatar.java
│ │ │ │ │ ├── DigestType.java
│ │ │ │ │ ├── Domain.java
│ │ │ │ │ ├── DomainConfiguration.java
│ │ │ │ │ ├── Group.java
│ │ │ │ │ ├── User.java
│ │ │ │ │ ├── UserStatusStat.java
│ │ │ │ │ ├── status/
│ │ │ │ │ │ ├── AbstractStatus.java
│ │ │ │ │ │ ├── Announcement.java
│ │ │ │ │ │ ├── MentionFriend.java
│ │ │ │ │ │ ├── MentionShare.java
│ │ │ │ │ │ ├── Share.java
│ │ │ │ │ │ ├── Status.java
│ │ │ │ │ │ ├── StatusDetails.java
│ │ │ │ │ │ └── StatusType.java
│ │ │ │ │ └── validation/
│ │ │ │ │ ├── ContraintsAttachmentCreation.java
│ │ │ │ │ └── ContraintsUserCreation.java
│ │ │ │ ├── repository/
│ │ │ │ │ ├── AppleDeviceRepository.java
│ │ │ │ │ ├── AppleDeviceUserRepository.java
│ │ │ │ │ ├── AttachmentRepository.java
│ │ │ │ │ ├── AvatarRepository.java
│ │ │ │ │ ├── BlockRepository.java
│ │ │ │ │ ├── CounterRepository.java
│ │ │ │ │ ├── DaylineRepository.java
│ │ │ │ │ ├── DiscussionRepository.java
│ │ │ │ │ ├── DomainConfigurationRepository.java
│ │ │ │ │ ├── DomainRepository.java
│ │ │ │ │ ├── DomainlineRepository.java
│ │ │ │ │ ├── FavoritelineRepository.java
│ │ │ │ │ ├── FollowerRepository.java
│ │ │ │ │ ├── FriendRepository.java
│ │ │ │ │ ├── GroupCounterRepository.java
│ │ │ │ │ ├── GroupDetailsRepository.java
│ │ │ │ │ ├── GroupMembersRepository.java
│ │ │ │ │ ├── GroupRepository.java
│ │ │ │ │ ├── GrouplineRepository.java
│ │ │ │ │ ├── IdempotentRepository.java
│ │ │ │ │ ├── MailDigestRepository.java
│ │ │ │ │ ├── MentionlineRepository.java
│ │ │ │ │ ├── RegistrationRepository.java
│ │ │ │ │ ├── ResolvedReportRepository.java
│ │ │ │ │ ├── RssUidRepository.java
│ │ │ │ │ ├── SharesRepository.java
│ │ │ │ │ ├── StatusAttachmentRepository.java
│ │ │ │ │ ├── StatusReportRepository.java
│ │ │ │ │ ├── StatusRepository.java
│ │ │ │ │ ├── TagCounterRepository.java
│ │ │ │ │ ├── TagFollowerRepository.java
│ │ │ │ │ ├── TaglineRepository.java
│ │ │ │ │ ├── TimelineRepository.java
│ │ │ │ │ ├── TrendRepository.java
│ │ │ │ │ ├── UserAttachmentRepository.java
│ │ │ │ │ ├── UserGroupRepository.java
│ │ │ │ │ ├── UserRepository.java
│ │ │ │ │ ├── UserTagRepository.java
│ │ │ │ │ ├── UserTrendRepository.java
│ │ │ │ │ ├── UserlineRepository.java
│ │ │ │ │ └── cassandra/
│ │ │ │ │ ├── AbstractCassandraFollowerRepository.java
│ │ │ │ │ ├── AbstractCassandraFriendRepository.java
│ │ │ │ │ ├── AbstractCassandraLineRepository.java
│ │ │ │ │ ├── CassandraAppleDeviceRepository.java
│ │ │ │ │ ├── CassandraAppleDeviceUserRepository.java
│ │ │ │ │ ├── CassandraAttachmentRepository.java
│ │ │ │ │ ├── CassandraAvatarRepository.java
│ │ │ │ │ ├── CassandraBlockRepository.java
│ │ │ │ │ ├── CassandraCounterRepository.java
│ │ │ │ │ ├── CassandraDaylineRepository.java
│ │ │ │ │ ├── CassandraDiscussionRepository.java
│ │ │ │ │ ├── CassandraDomainConfigurationRepository.java
│ │ │ │ │ ├── CassandraDomainRepository.java
│ │ │ │ │ ├── CassandraDomainlineRepository.java
│ │ │ │ │ ├── CassandraFavoritelineRepository.java
│ │ │ │ │ ├── CassandraFollowerRepository.java
│ │ │ │ │ ├── CassandraFriendRepository.java
│ │ │ │ │ ├── CassandraGroupCounterRepository.java
│ │ │ │ │ ├── CassandraGroupDetailsRepository.java
│ │ │ │ │ ├── CassandraGroupMembersRepository.java
│ │ │ │ │ ├── CassandraGroupRepository.java
│ │ │ │ │ ├── CassandraGrouplineRepository.java
│ │ │ │ │ ├── CassandraIdempotentRepository.java
│ │ │ │ │ ├── CassandraMailDigestRepository.java
│ │ │ │ │ ├── CassandraMentionlineRepository.java
│ │ │ │ │ ├── CassandraRegistrationRepository.java
│ │ │ │ │ ├── CassandraRssUidRepository.java
│ │ │ │ │ ├── CassandraSharesRepository.java
│ │ │ │ │ ├── CassandraStatusAttachmentRepository.java
│ │ │ │ │ ├── CassandraStatusReportRepository.java
│ │ │ │ │ ├── CassandraStatusRepository.java
│ │ │ │ │ ├── CassandraTagCounterRepository.java
│ │ │ │ │ ├── CassandraTagFollowerRepository.java
│ │ │ │ │ ├── CassandraTaglineRepository.java
│ │ │ │ │ ├── CassandraTimelineRepository.java
│ │ │ │ │ ├── CassandraTrendRepository.java
│ │ │ │ │ ├── CassandraUserAttachmentRepository.java
│ │ │ │ │ ├── CassandraUserGroupRepository.java
│ │ │ │ │ ├── CassandraUserRepository.java
│ │ │ │ │ ├── CassandraUserTagRepository.java
│ │ │ │ │ ├── CassandraUserTrendRepository.java
│ │ │ │ │ └── CassandraUserlineRepository.java
│ │ │ │ ├── security/
│ │ │ │ │ ├── AjaxAuthenticationFailureHandler.java
│ │ │ │ │ ├── AjaxAuthenticationSuccessHandler.java
│ │ │ │ │ ├── AjaxLogoutSuccessHandler.java
│ │ │ │ │ ├── AuthenticationService.java
│ │ │ │ │ ├── DomainViolationException.java
│ │ │ │ │ ├── GoogleApiAuthenticationProvider.java
│ │ │ │ │ ├── GoogleAuthenticationProvider.java
│ │ │ │ │ ├── GoogleAuthenticationToken.java
│ │ │ │ │ ├── GoogleAutoRegisteringUserDetailsService.java
│ │ │ │ │ ├── Http401UnauthorizedEntryPoint.java
│ │ │ │ │ ├── OpenIdAutoRegisteringUserDetailsService.java
│ │ │ │ │ ├── TatamiAuthenticationSuccessHandler.java
│ │ │ │ │ ├── TatamiLdapAuthenticationProvider.java
│ │ │ │ │ ├── TatamiUserDetailsService.java
│ │ │ │ │ └── xauth/
│ │ │ │ │ ├── Token.java
│ │ │ │ │ ├── TokenProvider.java
│ │ │ │ │ └── XAuthTokenFilter.java
│ │ │ │ ├── service/
│ │ │ │ │ ├── AdminService.java
│ │ │ │ │ ├── ApplePushService.java
│ │ │ │ │ ├── AtmosphereService.java
│ │ │ │ │ ├── AttachmentService.java
│ │ │ │ │ ├── AvatarService.java
│ │ │ │ │ ├── BlockService.java
│ │ │ │ │ ├── CounterService.java
│ │ │ │ │ ├── FriendshipService.java
│ │ │ │ │ ├── GroupService.java
│ │ │ │ │ ├── MailDigestService.java
│ │ │ │ │ ├── MailService.java
│ │ │ │ │ ├── MentionService.java
│ │ │ │ │ ├── SearchService.java
│ │ │ │ │ ├── StatsService.java
│ │ │ │ │ ├── StatusUpdateService.java
│ │ │ │ │ ├── SuggestionService.java
│ │ │ │ │ ├── TagMembershipService.java
│ │ │ │ │ ├── TimelineService.java
│ │ │ │ │ ├── TrendService.java
│ │ │ │ │ ├── UserService.java
│ │ │ │ │ ├── dto/
│ │ │ │ │ │ ├── StatusDTO.java
│ │ │ │ │ │ ├── UserDTO.java
│ │ │ │ │ │ └── UserGroupDTO.java
│ │ │ │ │ ├── elasticsearch/
│ │ │ │ │ │ ├── ElasticsearchEngine.java
│ │ │ │ │ │ ├── ElasticsearchSearchService.java
│ │ │ │ │ │ ├── EmbeddedElasticsearchEngine.java
│ │ │ │ │ │ └── RemoteElasticsearchEngine.java
│ │ │ │ │ ├── exception/
│ │ │ │ │ │ ├── ArchivedGroupException.java
│ │ │ │ │ │ ├── ReplyStatusException.java
│ │ │ │ │ │ └── StorageSizeException.java
│ │ │ │ │ └── util/
│ │ │ │ │ ├── AnalysisUtil.java
│ │ │ │ │ ├── DomainUtil.java
│ │ │ │ │ ├── RandomUtil.java
│ │ │ │ │ └── ValueComparator.java
│ │ │ │ └── web/
│ │ │ │ ├── atmosphere/
│ │ │ │ │ └── TatamiNotification.java
│ │ │ │ ├── rest/
│ │ │ │ │ └── dto/
│ │ │ │ │ ├── ActionStatus.java
│ │ │ │ │ ├── EmailAndUsername.java
│ │ │ │ │ ├── Preferences.java
│ │ │ │ │ ├── Reply.java
│ │ │ │ │ ├── SearchResults.java
│ │ │ │ │ ├── Tag.java
│ │ │ │ │ ├── Trend.java
│ │ │ │ │ ├── UserActionStatus.java
│ │ │ │ │ └── UserPassword.java
│ │ │ │ └── syndic/
│ │ │ │ ├── SyndicTimelineController.java
│ │ │ │ ├── SyndicView.java
│ │ │ │ └── UnknownRssChannelException.java
│ │ │ └── me/
│ │ │ └── prettyprint/
│ │ │ └── hom/
│ │ │ └── CassandraPersistenceProvider.java
│ │ ├── resources/
│ │ │ ├── META-INF/
│ │ │ │ ├── elasticsearch/
│ │ │ │ │ ├── elasticsearch-embedded.yml
│ │ │ │ │ ├── index/
│ │ │ │ │ │ ├── group.json
│ │ │ │ │ │ ├── status.json
│ │ │ │ │ │ └── user.json
│ │ │ │ │ └── logging.yml
│ │ │ │ ├── spring/
│ │ │ │ │ ├── applicationContext-metrics.xml
│ │ │ │ │ └── applicationContext-security.xml
│ │ │ │ └── tatami/
│ │ │ │ ├── customization.properties
│ │ │ │ ├── mails/
│ │ │ │ │ ├── common
│ │ │ │ │ ├── dailyDigestEmail
│ │ │ │ │ ├── deactivatedUserEmail
│ │ │ │ │ ├── invitationMessageEmail
│ │ │ │ │ ├── lostPasswordEmail
│ │ │ │ │ ├── messages/
│ │ │ │ │ │ ├── messages_en.properties
│ │ │ │ │ │ └── messages_fr.properties
│ │ │ │ │ ├── passwordReinitializedEmail
│ │ │ │ │ ├── registrationEmail
│ │ │ │ │ ├── reportedStatusEmail
│ │ │ │ │ ├── userMentionEmail
│ │ │ │ │ ├── userPrivateMessageEmail
│ │ │ │ │ ├── validationEmail
│ │ │ │ │ └── weeklyDigestEmail
│ │ │ │ └── tatami.properties
│ │ │ ├── ehcache.xml
│ │ │ └── logback.xml
│ │ └── webapp/
│ │ └── app/
│ │ └── shared/
│ │ └── services/
│ │ ├── AuthenticationService.js
│ │ ├── GeolocService.js
│ │ ├── GroupService.js
│ │ ├── HomeService.js
│ │ ├── ProfileService.js
│ │ ├── SearchService.js
│ │ ├── StatusService.js
│ │ ├── TagService.js
│ │ ├── TopPostersService.js
│ │ ├── UserService.js
│ │ └── UserSession.js
│ └── test/
│ ├── java/
│ │ └── fr/
│ │ └── ippon/
│ │ └── tatami/
│ │ ├── AbstractCassandraTatamiTest.java
│ │ ├── repository/
│ │ │ ├── MailDigestRepositoryTest.java
│ │ │ ├── StatusReportRepositoryTest.java
│ │ │ ├── StatusRepositoryTest.java
│ │ │ ├── TagFollowerRepositoryTest.java
│ │ │ └── UserRepositoryTest.java
│ │ ├── service/
│ │ │ ├── FriendshipServiceTest.java
│ │ │ ├── GroupServiceTest.java
│ │ │ ├── MailDigestServiceTest.java
│ │ │ ├── StatsServiceTest.java
│ │ │ ├── StatusDeletionTest.java
│ │ │ ├── StatusUpdateServiceTest.java
│ │ │ ├── TagMembershipServiceTest.java
│ │ │ ├── TimelineServiceTest.java
│ │ │ ├── TrendServiceTest.java
│ │ │ ├── UserServiceTest.java
│ │ │ └── elasticsearch/
│ │ │ └── ElasticsearchSearchServiceTest.java
│ │ ├── test/
│ │ │ ├── MockUtils.java
│ │ │ └── application/
│ │ │ ├── ApplicationTestConfiguration.java
│ │ │ └── WebApplicationTestConfiguration.java
│ │ └── web/
│ │ └── syndic/
│ │ └── SyndicTimelineControllerTest.java
│ ├── jmeter/
│ │ ├── tatami-create-users.jmx
│ │ └── tatami-stress-test.jmx
│ └── resources/
│ ├── dataset/
│ │ └── dataset.json
│ ├── logback.xml
│ └── tatami/
│ └── tatami-test.properties
├── src/
│ ├── integration/
│ │ ├── java/
│ │ │ ├── fr/
│ │ │ │ └── ippon/
│ │ │ │ └── tatami/
│ │ │ │ ├── test/
│ │ │ │ │ └── support/
│ │ │ │ │ ├── LdapTestServer.java
│ │ │ │ │ └── LdapTestServerJunitLauncher.java
│ │ │ │ └── uitest/
│ │ │ │ ├── AuthenticationSpec.groovy
│ │ │ │ ├── NewRegistrationSpec.groovy
│ │ │ │ └── support/
│ │ │ │ ├── AccountUtils.groovy
│ │ │ │ ├── CassandraAccessUtils.groovy
│ │ │ │ ├── RegistrationUtils.groovy
│ │ │ │ └── TatamiBaseGebSpec.groovy
│ │ │ └── pages/
│ │ │ ├── EmailVerifiedPage.groovy
│ │ │ ├── HomePage.groovy
│ │ │ ├── LoginPage.groovy
│ │ │ ├── TatamiBasePage.groovy
│ │ │ └── google/
│ │ │ ├── GoogleAuthenticationPage.groovy
│ │ │ └── GoogleOpenIdPage.groovy
│ │ └── resources/
│ │ ├── GebConfig.groovy
│ │ └── fr/
│ │ └── ippon/
│ │ └── tatami/
│ │ └── test/
│ │ └── support/
│ │ └── ipponTestLdapExport.ldif
│ └── main/
│ └── cql/
│ ├── install.cql
│ └── upgrade/
│ ├── upgrade_from_1.0.27_to_2.0.0.cql
│ ├── upgrade_from_2.0.0_to_2.1.0.cql
│ ├── upgrade_from_2.1.3_to_2.2.0.cql
│ └── upgrade_from_3.0.26_to_3.0.27.cql
├── tatamibot/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── fr/
│ │ │ └── ippon/
│ │ │ └── tatami/
│ │ │ ├── bot/
│ │ │ │ ├── Tatamibot.java
│ │ │ │ ├── config/
│ │ │ │ │ └── TatamibotConfiguration.java
│ │ │ │ ├── processor/
│ │ │ │ │ ├── LastUpdateDateTatamibotConfigurationUpdater.java
│ │ │ │ │ └── TatamiStatusProcessor.java
│ │ │ │ └── route/
│ │ │ │ ├── CommonRouteBuilder.java
│ │ │ │ ├── GitHubRouteBuilder.java
│ │ │ │ ├── RssRouteBuilder.java
│ │ │ │ ├── SourceRouteBuilderBase.java
│ │ │ │ └── TwitterRouteBuilder.java
│ │ │ ├── repository/
│ │ │ │ ├── TatamibotConfigurationRepository.java
│ │ │ │ └── cassandra/
│ │ │ │ └── CassandraTatamibotConfigurationRepository.java
│ │ │ └── web/
│ │ │ └── bot/
│ │ │ └── TatamibotController.java
│ │ └── resources/
│ │ └── META-INF/
│ │ └── spring/
│ │ └── applicationContext-tatamibot.xml
│ └── test/
│ ├── java/
│ │ └── fr/
│ │ └── ippon/
│ │ └── tatami/
│ │ ├── bot/
│ │ │ ├── TatamibotTest.java
│ │ │ └── route/
│ │ │ ├── CommonRouteBuilderTest.java
│ │ │ ├── RssRouteBuilderCamelTest.java
│ │ │ ├── RssRouteBuilderUnitTest.java
│ │ │ ├── SourceRouteBuilderBaseCamelTest.java
│ │ │ └── TwitterRouteBuilderCamelTest.java
│ │ └── test/
│ │ └── MockUtils.java
│ └── resources/
│ └── fr/
│ └── ippon/
│ └── tatami/
│ └── bot/
│ └── route/
│ └── rss.xml
└── web/
├── gruntfile.js
├── karma.ci.conf.js
├── karma.conf.js
├── package.json
├── pom.xml
└── src/
├── main/
│ ├── java/
│ │ └── fr/
│ │ └── ippon/
│ │ └── tatami/
│ │ └── web/
│ │ ├── atmosphere/
│ │ │ └── RealtimeService.java
│ │ ├── controller/
│ │ │ ├── ErrorController.java
│ │ │ ├── HomeController.java
│ │ │ └── Pac4JSecurityCheckController.java
│ │ ├── fileupload/
│ │ │ ├── FileController.java
│ │ │ ├── Message.java
│ │ │ ├── StatusResponse.java
│ │ │ └── UploadedFile.java
│ │ ├── filter/
│ │ │ ├── IeRefreshWrapper.java
│ │ │ └── TatamiGzipFilter.java
│ │ ├── init/
│ │ │ └── WebConfigurer.java
│ │ └── rest/
│ │ ├── AccountController.java
│ │ ├── AttachmentController.java
│ │ ├── BlockController.java
│ │ ├── CompanyWallController.java
│ │ ├── FavoritesController.java
│ │ ├── FriendshipController.java
│ │ ├── GroupController.java
│ │ ├── MentionsController.java
│ │ ├── SearchController.java
│ │ ├── StatsController.java
│ │ ├── TagController.java
│ │ ├── TimelineController.java
│ │ ├── TrendController.java
│ │ ├── UserController.java
│ │ └── UserXAuthController.java
│ └── webapp/
│ ├── .bowerrc
│ ├── WEB-INF/
│ │ ├── messages/
│ │ │ ├── messages_en.properties
│ │ │ └── messages_fr.properties
│ │ ├── pages/
│ │ │ ├── errors/
│ │ │ │ ├── 404.jsp
│ │ │ │ ├── 500.jsp
│ │ │ │ └── file_not_found.jsp
│ │ │ ├── home.jsp
│ │ │ ├── includes/
│ │ │ │ ├── footer.jsp
│ │ │ │ ├── header.jsp
│ │ │ │ ├── help-home.jsp
│ │ │ │ ├── navigation-admin.jsp
│ │ │ │ ├── template-search-engine.jsp
│ │ │ │ ├── templates-admin.jsp
│ │ │ │ ├── templates.jsp
│ │ │ │ ├── topavatar.jsp
│ │ │ │ └── topmenu.jsp
│ │ │ └── login.jsp
│ │ └── web.xml
│ ├── app/
│ │ ├── TatamiApp.js
│ │ ├── components/
│ │ │ ├── about/
│ │ │ │ ├── AboutModule.js
│ │ │ │ ├── AboutView.html
│ │ │ │ ├── license/
│ │ │ │ │ ├── LicenseController.js
│ │ │ │ │ └── LicenseView.html
│ │ │ │ ├── presentation/
│ │ │ │ │ └── PresentationView.html
│ │ │ │ └── tos/
│ │ │ │ └── ToSView.html
│ │ │ ├── account/
│ │ │ │ ├── AccountController.js
│ │ │ │ ├── AccountModule.js
│ │ │ │ ├── AccountView.html
│ │ │ │ ├── FormController.js
│ │ │ │ ├── FormView.html
│ │ │ │ ├── files/
│ │ │ │ │ ├── FilesController.js
│ │ │ │ │ ├── FilesModule.js
│ │ │ │ │ ├── FilesService.js
│ │ │ │ │ └── FilesView.html
│ │ │ │ ├── groups/
│ │ │ │ │ ├── GroupsController.js
│ │ │ │ │ ├── GroupsModule.js
│ │ │ │ │ ├── GroupsView.html
│ │ │ │ │ ├── creation/
│ │ │ │ │ │ ├── GroupsCreateController.js
│ │ │ │ │ │ └── GroupsCreateView.html
│ │ │ │ │ ├── list/
│ │ │ │ │ │ ├── GroupListController.js
│ │ │ │ │ │ └── GroupsListView.html
│ │ │ │ │ └── manage/
│ │ │ │ │ ├── GroupsManageController.js
│ │ │ │ │ └── GroupsManageView.html
│ │ │ │ ├── password/
│ │ │ │ │ ├── PasswordController.js
│ │ │ │ │ ├── PasswordModule.js
│ │ │ │ │ ├── PasswordService.js
│ │ │ │ │ └── PasswordView.html
│ │ │ │ ├── preferences/
│ │ │ │ │ ├── PreferencesController.js
│ │ │ │ │ ├── PreferencesModule.js
│ │ │ │ │ ├── PreferencesService.js
│ │ │ │ │ └── PreferencesView.html
│ │ │ │ ├── profile/
│ │ │ │ │ ├── ProfileController.js
│ │ │ │ │ ├── ProfileModule.js
│ │ │ │ │ └── ProfileView.html
│ │ │ │ ├── tags/
│ │ │ │ │ ├── TagsController.js
│ │ │ │ │ ├── TagsModule.js
│ │ │ │ │ └── TagsView.html
│ │ │ │ ├── topPosters/
│ │ │ │ │ ├── TopPostersController.js
│ │ │ │ │ ├── TopPostersModule.js
│ │ │ │ │ └── TopPostersView.html
│ │ │ │ └── users/
│ │ │ │ ├── UsersController.js
│ │ │ │ ├── UsersModule.js
│ │ │ │ ├── UsersView.html
│ │ │ │ └── directives/
│ │ │ │ ├── UserAccountController.js
│ │ │ │ ├── UserAccountDirective.js
│ │ │ │ └── UserAccountView.html
│ │ │ ├── admin/
│ │ │ │ ├── AdminController.js
│ │ │ │ ├── AdminModule.js
│ │ │ │ ├── AdminService.js
│ │ │ │ └── AdminView.html
│ │ │ ├── home/
│ │ │ │ ├── HomeModule.js
│ │ │ │ ├── HomeView.html
│ │ │ │ ├── group/
│ │ │ │ │ ├── GroupHeaderController.js
│ │ │ │ │ └── GroupHeaderView.html
│ │ │ │ ├── profile/
│ │ │ │ │ ├── ProfileHeaderController.js
│ │ │ │ │ └── ProfileHeaderView.html
│ │ │ │ ├── search/
│ │ │ │ │ ├── SearchHeaderController.js
│ │ │ │ │ └── SearchHeaderView.html
│ │ │ │ ├── status/
│ │ │ │ │ ├── StatusController.js
│ │ │ │ │ └── StatusView.html
│ │ │ │ ├── tag/
│ │ │ │ │ ├── TagHeaderController.js
│ │ │ │ │ └── TagHeaderView.html
│ │ │ │ ├── timeline/
│ │ │ │ │ └── TimelineHeaderView.html
│ │ │ │ └── welcome/
│ │ │ │ ├── WelcomeController.js
│ │ │ │ └── WelcomeView.html
│ │ │ └── login/
│ │ │ ├── LoginController.js
│ │ │ ├── LoginModule.js
│ │ │ ├── LoginView.html
│ │ │ ├── RegistrationService.js
│ │ │ ├── email/
│ │ │ │ ├── EmailRegistration.html
│ │ │ │ └── EmailRegistrationController.js
│ │ │ ├── google/
│ │ │ │ ├── GoogleLoginController.js
│ │ │ │ └── GoogleLoginView.html
│ │ │ ├── manual/
│ │ │ │ ├── ManualLoginController.js
│ │ │ │ └── ManualLoginView.html
│ │ │ ├── recoverPassword/
│ │ │ │ ├── RecoverPasswordController.js
│ │ │ │ └── RecoverPasswordView.html
│ │ │ └── register/
│ │ │ ├── RegisterController.js
│ │ │ └── RegisterView.html
│ │ └── shared/
│ │ ├── configs/
│ │ │ ├── MarkedConfig.js
│ │ │ ├── MomentConfig.js
│ │ │ └── TranslateConfig.js
│ │ ├── error/
│ │ │ ├── 404View.html
│ │ │ └── 500View.html
│ │ ├── filters/
│ │ │ ├── EmoticonFilter.js
│ │ │ ├── MarkdownFilter.js
│ │ │ └── PlaceholderFilter.js
│ │ ├── footer/
│ │ │ ├── FooterController.js
│ │ │ ├── FooterModule.js
│ │ │ └── FooterView.html
│ │ ├── lists/
│ │ │ ├── status/
│ │ │ │ ├── withContext/
│ │ │ │ │ ├── StatusListContextController.js
│ │ │ │ │ └── StatusListContextView.html
│ │ │ │ └── withoutContext/
│ │ │ │ ├── StatusListController.js
│ │ │ │ └── StatusListView.html
│ │ │ └── user/
│ │ │ ├── UserListController.js
│ │ │ └── UserListView.html
│ │ ├── services/
│ │ │ ├── AuthenticationService.js
│ │ │ ├── GeolocService.js
│ │ │ ├── GroupService.js
│ │ │ ├── HomeService.js
│ │ │ ├── ProfileService.js
│ │ │ ├── SearchService.js
│ │ │ ├── StatusService.js
│ │ │ ├── TagService.js
│ │ │ ├── TopPostersService.js
│ │ │ ├── UserService.js
│ │ │ └── UserSession.js
│ │ ├── sidebars/
│ │ │ ├── home/
│ │ │ │ ├── HomeSidebarController.js
│ │ │ │ ├── HomeSidebarModule.js
│ │ │ │ └── HomeSidebarView.html
│ │ │ └── profile/
│ │ │ ├── ProfileSidebarController.js
│ │ │ ├── ProfileSidebarModule.js
│ │ │ └── ProfileSidebarView.html
│ │ └── topMenu/
│ │ ├── SearchView.html
│ │ ├── TopMenuController.js
│ │ ├── TopMenuModule.js
│ │ ├── TopMenuView.html
│ │ └── post/
│ │ ├── DropdownTagTemplate.html
│ │ ├── DropdownUserTemplate.html
│ │ ├── PostController.js
│ │ ├── PostModule.js
│ │ └── PostView.html
│ ├── assets/
│ │ ├── bower_components/
│ │ │ ├── angular/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-csp.css
│ │ │ │ ├── angular.min.js.gzip
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-animate/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-bootstrap/
│ │ │ │ ├── .bower.json
│ │ │ │ └── bower.json
│ │ │ ├── angular-bootstrap-tour/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── app/
│ │ │ │ │ ├── angular-bootstrap-tour.js
│ │ │ │ │ ├── tour_config_provider.js
│ │ │ │ │ ├── tour_controller.js
│ │ │ │ │ ├── tour_directive.js
│ │ │ │ │ ├── tour_helpers.js
│ │ │ │ │ └── tour_step_directive.js
│ │ │ │ ├── bower.json
│ │ │ │ ├── demo/
│ │ │ │ │ └── angular-bootstrap-tour.js
│ │ │ │ ├── dist/
│ │ │ │ │ └── angular-bootstrap-tour.js
│ │ │ │ ├── gruntfile.js
│ │ │ │ ├── karma.conf.js
│ │ │ │ └── test/
│ │ │ │ └── spec/
│ │ │ │ └── angular-bootstrap-tour.spec.js
│ │ │ ├── angular-cookies/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-mocks/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-mocks.js
│ │ │ │ ├── bower.json
│ │ │ │ ├── ngAnimateMock.js
│ │ │ │ ├── ngMock.js
│ │ │ │ ├── ngMockE2E.js
│ │ │ │ └── package.json
│ │ │ ├── angular-moment/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── .editorconfig
│ │ │ │ ├── .gitignore
│ │ │ │ ├── .jshintrc
│ │ │ │ ├── .npmignore
│ │ │ │ ├── .travis.yml
│ │ │ │ ├── CHANGELOG.md
│ │ │ │ ├── CONTRIBUTING.md
│ │ │ │ ├── Gruntfile.js
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-moment.nuspec
│ │ │ │ ├── bower.json
│ │ │ │ ├── karma.conf.js
│ │ │ │ ├── package.json
│ │ │ │ └── tests.js
│ │ │ ├── angular-resource/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-route/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-route.js
│ │ │ │ └── bower.json
│ │ │ ├── angular-sanitize/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-touch/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── angular-translate/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ └── bower.json
│ │ │ ├── angular-translate-storage-cookie/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ └── bower.json
│ │ │ ├── angular-ui-router/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── CHANGELOG.md
│ │ │ │ ├── CONTRIBUTING.md
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── api/
│ │ │ │ │ └── angular-ui-router.d.ts
│ │ │ │ ├── bower.json
│ │ │ │ ├── release/
│ │ │ │ │ └── angular-ui-router.js
│ │ │ │ └── src/
│ │ │ │ ├── common.js
│ │ │ │ ├── resolve.js
│ │ │ │ ├── state.js
│ │ │ │ ├── stateDirectives.js
│ │ │ │ ├── stateFilters.js
│ │ │ │ ├── templateFactory.js
│ │ │ │ ├── urlMatcherFactory.js
│ │ │ │ ├── urlRouter.js
│ │ │ │ ├── view.js
│ │ │ │ ├── viewDirective.js
│ │ │ │ └── viewScroll.js
│ │ │ ├── bootstrap/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── DOCS-LICENSE
│ │ │ │ ├── LICENSE
│ │ │ │ ├── LICENSE-MIT
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── dist/
│ │ │ │ │ ├── css/
│ │ │ │ │ │ ├── bootstrap-theme.css
│ │ │ │ │ │ └── bootstrap.css
│ │ │ │ │ └── js/
│ │ │ │ │ └── bootstrap.js
│ │ │ │ ├── js/
│ │ │ │ │ ├── affix.js
│ │ │ │ │ ├── alert.js
│ │ │ │ │ ├── button.js
│ │ │ │ │ ├── carousel.js
│ │ │ │ │ ├── collapse.js
│ │ │ │ │ ├── dropdown.js
│ │ │ │ │ ├── modal.js
│ │ │ │ │ ├── popover.js
│ │ │ │ │ ├── scrollspy.js
│ │ │ │ │ ├── tab.js
│ │ │ │ │ ├── tooltip.js
│ │ │ │ │ └── transition.js
│ │ │ │ └── less/
│ │ │ │ ├── alerts.less
│ │ │ │ ├── badges.less
│ │ │ │ ├── bootstrap.less
│ │ │ │ ├── breadcrumbs.less
│ │ │ │ ├── button-groups.less
│ │ │ │ ├── buttons.less
│ │ │ │ ├── carousel.less
│ │ │ │ ├── close.less
│ │ │ │ ├── code.less
│ │ │ │ ├── component-animations.less
│ │ │ │ ├── dropdowns.less
│ │ │ │ ├── forms.less
│ │ │ │ ├── glyphicons.less
│ │ │ │ ├── grid.less
│ │ │ │ ├── input-groups.less
│ │ │ │ ├── jumbotron.less
│ │ │ │ ├── labels.less
│ │ │ │ ├── list-group.less
│ │ │ │ ├── media.less
│ │ │ │ ├── mixins.less
│ │ │ │ ├── modals.less
│ │ │ │ ├── navbar.less
│ │ │ │ ├── navs.less
│ │ │ │ ├── normalize.less
│ │ │ │ ├── pager.less
│ │ │ │ ├── pagination.less
│ │ │ │ ├── panels.less
│ │ │ │ ├── popovers.less
│ │ │ │ ├── print.less
│ │ │ │ ├── progress-bars.less
│ │ │ │ ├── responsive-utilities.less
│ │ │ │ ├── scaffolding.less
│ │ │ │ ├── tables.less
│ │ │ │ ├── theme.less
│ │ │ │ ├── thumbnails.less
│ │ │ │ ├── tooltip.less
│ │ │ │ ├── type.less
│ │ │ │ ├── utilities.less
│ │ │ │ ├── variables.less
│ │ │ │ └── wells.less
│ │ │ ├── jquery/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── MIT-LICENSE.txt
│ │ │ │ ├── bower.json
│ │ │ │ ├── dist/
│ │ │ │ │ └── jquery.js
│ │ │ │ └── src/
│ │ │ │ ├── ajax/
│ │ │ │ │ ├── jsonp.js
│ │ │ │ │ ├── load.js
│ │ │ │ │ ├── parseJSON.js
│ │ │ │ │ ├── parseXML.js
│ │ │ │ │ ├── script.js
│ │ │ │ │ ├── var/
│ │ │ │ │ │ ├── nonce.js
│ │ │ │ │ │ └── rquery.js
│ │ │ │ │ └── xhr.js
│ │ │ │ ├── ajax.js
│ │ │ │ ├── attributes/
│ │ │ │ │ ├── attr.js
│ │ │ │ │ ├── classes.js
│ │ │ │ │ ├── prop.js
│ │ │ │ │ ├── support.js
│ │ │ │ │ └── val.js
│ │ │ │ ├── attributes.js
│ │ │ │ ├── callbacks.js
│ │ │ │ ├── core/
│ │ │ │ │ ├── access.js
│ │ │ │ │ ├── init.js
│ │ │ │ │ ├── parseHTML.js
│ │ │ │ │ ├── ready.js
│ │ │ │ │ └── var/
│ │ │ │ │ └── rsingleTag.js
│ │ │ │ ├── core.js
│ │ │ │ ├── css/
│ │ │ │ │ ├── addGetHookIf.js
│ │ │ │ │ ├── curCSS.js
│ │ │ │ │ ├── defaultDisplay.js
│ │ │ │ │ ├── hiddenVisibleSelectors.js
│ │ │ │ │ ├── support.js
│ │ │ │ │ ├── swap.js
│ │ │ │ │ └── var/
│ │ │ │ │ ├── cssExpand.js
│ │ │ │ │ ├── isHidden.js
│ │ │ │ │ ├── rmargin.js
│ │ │ │ │ └── rnumnonpx.js
│ │ │ │ ├── css.js
│ │ │ │ ├── data.js
│ │ │ │ ├── deferred.js
│ │ │ │ ├── deprecated.js
│ │ │ │ ├── dimensions.js
│ │ │ │ ├── effects/
│ │ │ │ │ ├── Tween.js
│ │ │ │ │ ├── animatedSelector.js
│ │ │ │ │ └── support.js
│ │ │ │ ├── effects.js
│ │ │ │ ├── event/
│ │ │ │ │ ├── alias.js
│ │ │ │ │ └── support.js
│ │ │ │ ├── event.js
│ │ │ │ ├── exports/
│ │ │ │ │ ├── amd.js
│ │ │ │ │ └── global.js
│ │ │ │ ├── intro.js
│ │ │ │ ├── jquery.js
│ │ │ │ ├── manipulation/
│ │ │ │ │ ├── _evalUrl.js
│ │ │ │ │ ├── support.js
│ │ │ │ │ └── var/
│ │ │ │ │ └── rcheckableType.js
│ │ │ │ ├── manipulation.js
│ │ │ │ ├── offset.js
│ │ │ │ ├── outro.js
│ │ │ │ ├── queue/
│ │ │ │ │ └── delay.js
│ │ │ │ ├── queue.js
│ │ │ │ ├── selector-sizzle.js
│ │ │ │ ├── selector.js
│ │ │ │ ├── serialize.js
│ │ │ │ ├── sizzle/
│ │ │ │ │ └── dist/
│ │ │ │ │ └── sizzle.js
│ │ │ │ ├── support.js
│ │ │ │ ├── traversing/
│ │ │ │ │ ├── findFilter.js
│ │ │ │ │ └── var/
│ │ │ │ │ └── rneedsContext.js
│ │ │ │ ├── traversing.js
│ │ │ │ ├── var/
│ │ │ │ │ ├── class2type.js
│ │ │ │ │ ├── concat.js
│ │ │ │ │ ├── deletedIds.js
│ │ │ │ │ ├── hasOwn.js
│ │ │ │ │ ├── indexOf.js
│ │ │ │ │ ├── pnum.js
│ │ │ │ │ ├── push.js
│ │ │ │ │ ├── rnotwhite.js
│ │ │ │ │ ├── slice.js
│ │ │ │ │ ├── strundefined.js
│ │ │ │ │ ├── support.js
│ │ │ │ │ └── toString.js
│ │ │ │ └── wrap.js
│ │ │ ├── ment.io/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── LICENSE-MIT
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── dist/
│ │ │ │ │ ├── mentio.js
│ │ │ │ │ └── templates.js
│ │ │ │ ├── gulpfile.js
│ │ │ │ ├── karma.conf.js
│ │ │ │ ├── ment.io/
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── peopledata.json
│ │ │ │ │ ├── productdata.json
│ │ │ │ │ ├── scripts.js
│ │ │ │ │ ├── simplepeopledata.json
│ │ │ │ │ └── styles.css
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ ├── mentio-menu.tpl.html
│ │ │ │ ├── mentio.directive.js
│ │ │ │ └── mentio.service.js
│ │ │ ├── moment/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── CHANGELOG.md
│ │ │ │ ├── LICENSE
│ │ │ │ ├── Moment.js.nuspec
│ │ │ │ ├── README.md
│ │ │ │ ├── benchmarks/
│ │ │ │ │ └── clone.js
│ │ │ │ ├── bower.json
│ │ │ │ ├── locale/
│ │ │ │ │ ├── af.js
│ │ │ │ │ ├── ar-ma.js
│ │ │ │ │ ├── ar-sa.js
│ │ │ │ │ ├── ar-tn.js
│ │ │ │ │ ├── ar.js
│ │ │ │ │ ├── az.js
│ │ │ │ │ ├── be.js
│ │ │ │ │ ├── bg.js
│ │ │ │ │ ├── bn.js
│ │ │ │ │ ├── bo.js
│ │ │ │ │ ├── br.js
│ │ │ │ │ ├── bs.js
│ │ │ │ │ ├── ca.js
│ │ │ │ │ ├── cs.js
│ │ │ │ │ ├── cv.js
│ │ │ │ │ ├── cy.js
│ │ │ │ │ ├── da.js
│ │ │ │ │ ├── de-at.js
│ │ │ │ │ ├── de.js
│ │ │ │ │ ├── el.js
│ │ │ │ │ ├── en-au.js
│ │ │ │ │ ├── en-ca.js
│ │ │ │ │ ├── en-gb.js
│ │ │ │ │ ├── eo.js
│ │ │ │ │ ├── es.js
│ │ │ │ │ ├── et.js
│ │ │ │ │ ├── eu.js
│ │ │ │ │ ├── fa.js
│ │ │ │ │ ├── fi.js
│ │ │ │ │ ├── fo.js
│ │ │ │ │ ├── fr-ca.js
│ │ │ │ │ ├── fr.js
│ │ │ │ │ ├── fy.js
│ │ │ │ │ ├── gl.js
│ │ │ │ │ ├── he.js
│ │ │ │ │ ├── hi.js
│ │ │ │ │ ├── hr.js
│ │ │ │ │ ├── hu.js
│ │ │ │ │ ├── hy-am.js
│ │ │ │ │ ├── id.js
│ │ │ │ │ ├── is.js
│ │ │ │ │ ├── it.js
│ │ │ │ │ ├── ja.js
│ │ │ │ │ ├── ka.js
│ │ │ │ │ ├── km.js
│ │ │ │ │ ├── ko.js
│ │ │ │ │ ├── lb.js
│ │ │ │ │ ├── lt.js
│ │ │ │ │ ├── lv.js
│ │ │ │ │ ├── mk.js
│ │ │ │ │ ├── ml.js
│ │ │ │ │ ├── mr.js
│ │ │ │ │ ├── ms-my.js
│ │ │ │ │ ├── my.js
│ │ │ │ │ ├── nb.js
│ │ │ │ │ ├── ne.js
│ │ │ │ │ ├── nl.js
│ │ │ │ │ ├── nn.js
│ │ │ │ │ ├── pl.js
│ │ │ │ │ ├── pt-br.js
│ │ │ │ │ ├── pt.js
│ │ │ │ │ ├── ro.js
│ │ │ │ │ ├── ru.js
│ │ │ │ │ ├── sk.js
│ │ │ │ │ ├── sl.js
│ │ │ │ │ ├── sq.js
│ │ │ │ │ ├── sr-cyrl.js
│ │ │ │ │ ├── sr.js
│ │ │ │ │ ├── sv.js
│ │ │ │ │ ├── ta.js
│ │ │ │ │ ├── th.js
│ │ │ │ │ ├── tl-ph.js
│ │ │ │ │ ├── tr.js
│ │ │ │ │ ├── tzm-latn.js
│ │ │ │ │ ├── tzm.js
│ │ │ │ │ ├── uk.js
│ │ │ │ │ ├── uz.js
│ │ │ │ │ ├── vi.js
│ │ │ │ │ ├── zh-cn.js
│ │ │ │ │ └── zh-tw.js
│ │ │ │ ├── meteor/
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── export.js
│ │ │ │ │ └── test.js
│ │ │ │ ├── min/
│ │ │ │ │ ├── locales.js
│ │ │ │ │ ├── moment-with-locales.js
│ │ │ │ │ └── tests.js
│ │ │ │ ├── moment.js
│ │ │ │ ├── scripts/
│ │ │ │ │ └── npm_prepublish.sh
│ │ │ │ ├── src/
│ │ │ │ │ ├── lib/
│ │ │ │ │ │ ├── create/
│ │ │ │ │ │ │ ├── check-overflow.js
│ │ │ │ │ │ │ ├── date-from-array.js
│ │ │ │ │ │ │ ├── default-parsing-flags.js
│ │ │ │ │ │ │ ├── from-anything.js
│ │ │ │ │ │ │ ├── from-array.js
│ │ │ │ │ │ │ ├── from-object.js
│ │ │ │ │ │ │ ├── from-string-and-array.js
│ │ │ │ │ │ │ ├── from-string-and-format.js
│ │ │ │ │ │ │ ├── from-string.js
│ │ │ │ │ │ │ ├── local.js
│ │ │ │ │ │ │ ├── utc.js
│ │ │ │ │ │ │ └── valid.js
│ │ │ │ │ │ ├── duration/
│ │ │ │ │ │ │ ├── abs.js
│ │ │ │ │ │ │ ├── add-subtract.js
│ │ │ │ │ │ │ ├── as.js
│ │ │ │ │ │ │ ├── bubble.js
│ │ │ │ │ │ │ ├── constructor.js
│ │ │ │ │ │ │ ├── create.js
│ │ │ │ │ │ │ ├── duration.js
│ │ │ │ │ │ │ ├── get.js
│ │ │ │ │ │ │ ├── humanize.js
│ │ │ │ │ │ │ ├── iso-string.js
│ │ │ │ │ │ │ └── prototype.js
│ │ │ │ │ │ ├── format/
│ │ │ │ │ │ │ └── format.js
│ │ │ │ │ │ ├── locale/
│ │ │ │ │ │ │ ├── calendar.js
│ │ │ │ │ │ │ ├── constructor.js
│ │ │ │ │ │ │ ├── en.js
│ │ │ │ │ │ │ ├── formats.js
│ │ │ │ │ │ │ ├── invalid.js
│ │ │ │ │ │ │ ├── lists.js
│ │ │ │ │ │ │ ├── locale.js
│ │ │ │ │ │ │ ├── locales.js
│ │ │ │ │ │ │ ├── ordinal.js
│ │ │ │ │ │ │ ├── pre-post-format.js
│ │ │ │ │ │ │ ├── prototype.js
│ │ │ │ │ │ │ ├── relative.js
│ │ │ │ │ │ │ └── set.js
│ │ │ │ │ │ ├── moment/
│ │ │ │ │ │ │ ├── add-subtract.js
│ │ │ │ │ │ │ ├── calendar.js
│ │ │ │ │ │ │ ├── clone.js
│ │ │ │ │ │ │ ├── compare.js
│ │ │ │ │ │ │ ├── constructor.js
│ │ │ │ │ │ │ ├── diff.js
│ │ │ │ │ │ │ ├── format.js
│ │ │ │ │ │ │ ├── from.js
│ │ │ │ │ │ │ ├── get-set.js
│ │ │ │ │ │ │ ├── locale.js
│ │ │ │ │ │ │ ├── min-max.js
│ │ │ │ │ │ │ ├── moment.js
│ │ │ │ │ │ │ ├── prototype.js
│ │ │ │ │ │ │ ├── start-end-of.js
│ │ │ │ │ │ │ ├── to-type.js
│ │ │ │ │ │ │ └── valid.js
│ │ │ │ │ │ ├── parse/
│ │ │ │ │ │ │ ├── regex.js
│ │ │ │ │ │ │ └── token.js
│ │ │ │ │ │ ├── units/
│ │ │ │ │ │ │ ├── aliases.js
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── day-of-month.js
│ │ │ │ │ │ │ ├── day-of-week.js
│ │ │ │ │ │ │ ├── day-of-year.js
│ │ │ │ │ │ │ ├── hour.js
│ │ │ │ │ │ │ ├── millisecond.js
│ │ │ │ │ │ │ ├── minute.js
│ │ │ │ │ │ │ ├── month.js
│ │ │ │ │ │ │ ├── offset.js
│ │ │ │ │ │ │ ├── quarter.js
│ │ │ │ │ │ │ ├── second.js
│ │ │ │ │ │ │ ├── timestamp.js
│ │ │ │ │ │ │ ├── timezone.js
│ │ │ │ │ │ │ ├── units.js
│ │ │ │ │ │ │ ├── week-year.js
│ │ │ │ │ │ │ ├── week.js
│ │ │ │ │ │ │ └── year.js
│ │ │ │ │ │ └── utils/
│ │ │ │ │ │ ├── abs-floor.js
│ │ │ │ │ │ ├── compare-arrays.js
│ │ │ │ │ │ ├── defaults.js
│ │ │ │ │ │ ├── deprecate.js
│ │ │ │ │ │ ├── extend.js
│ │ │ │ │ │ ├── has-own-prop.js
│ │ │ │ │ │ ├── hooks.js
│ │ │ │ │ │ ├── is-array.js
│ │ │ │ │ │ ├── is-date.js
│ │ │ │ │ │ ├── map.js
│ │ │ │ │ │ ├── to-int.js
│ │ │ │ │ │ └── zero-fill.js
│ │ │ │ │ ├── locale/
│ │ │ │ │ │ ├── af.js
│ │ │ │ │ │ ├── ar-ma.js
│ │ │ │ │ │ ├── ar-sa.js
│ │ │ │ │ │ ├── ar-tn.js
│ │ │ │ │ │ ├── ar.js
│ │ │ │ │ │ ├── az.js
│ │ │ │ │ │ ├── be.js
│ │ │ │ │ │ ├── bg.js
│ │ │ │ │ │ ├── bn.js
│ │ │ │ │ │ ├── bo.js
│ │ │ │ │ │ ├── br.js
│ │ │ │ │ │ ├── bs.js
│ │ │ │ │ │ ├── ca.js
│ │ │ │ │ │ ├── cs.js
│ │ │ │ │ │ ├── cv.js
│ │ │ │ │ │ ├── cy.js
│ │ │ │ │ │ ├── da.js
│ │ │ │ │ │ ├── de-at.js
│ │ │ │ │ │ ├── de.js
│ │ │ │ │ │ ├── el.js
│ │ │ │ │ │ ├── en-au.js
│ │ │ │ │ │ ├── en-ca.js
│ │ │ │ │ │ ├── en-gb.js
│ │ │ │ │ │ ├── eo.js
│ │ │ │ │ │ ├── es.js
│ │ │ │ │ │ ├── et.js
│ │ │ │ │ │ ├── eu.js
│ │ │ │ │ │ ├── fa.js
│ │ │ │ │ │ ├── fi.js
│ │ │ │ │ │ ├── fo.js
│ │ │ │ │ │ ├── fr-ca.js
│ │ │ │ │ │ ├── fr.js
│ │ │ │ │ │ ├── fy.js
│ │ │ │ │ │ ├── gl.js
│ │ │ │ │ │ ├── he.js
│ │ │ │ │ │ ├── hi.js
│ │ │ │ │ │ ├── hr.js
│ │ │ │ │ │ ├── hu.js
│ │ │ │ │ │ ├── hy-am.js
│ │ │ │ │ │ ├── id.js
│ │ │ │ │ │ ├── is.js
│ │ │ │ │ │ ├── it.js
│ │ │ │ │ │ ├── ja.js
│ │ │ │ │ │ ├── ka.js
│ │ │ │ │ │ ├── km.js
│ │ │ │ │ │ ├── ko.js
│ │ │ │ │ │ ├── lb.js
│ │ │ │ │ │ ├── lt.js
│ │ │ │ │ │ ├── lv.js
│ │ │ │ │ │ ├── mk.js
│ │ │ │ │ │ ├── ml.js
│ │ │ │ │ │ ├── mr.js
│ │ │ │ │ │ ├── ms-my.js
│ │ │ │ │ │ ├── my.js
│ │ │ │ │ │ ├── nb.js
│ │ │ │ │ │ ├── ne.js
│ │ │ │ │ │ ├── nl.js
│ │ │ │ │ │ ├── nn.js
│ │ │ │ │ │ ├── pl.js
│ │ │ │ │ │ ├── pt-br.js
│ │ │ │ │ │ ├── pt.js
│ │ │ │ │ │ ├── ro.js
│ │ │ │ │ │ ├── ru.js
│ │ │ │ │ │ ├── sk.js
│ │ │ │ │ │ ├── sl.js
│ │ │ │ │ │ ├── sq.js
│ │ │ │ │ │ ├── sr-cyrl.js
│ │ │ │ │ │ ├── sr.js
│ │ │ │ │ │ ├── sv.js
│ │ │ │ │ │ ├── ta.js
│ │ │ │ │ │ ├── th.js
│ │ │ │ │ │ ├── tl-ph.js
│ │ │ │ │ │ ├── tr.js
│ │ │ │ │ │ ├── tzm-latn.js
│ │ │ │ │ │ ├── tzm.js
│ │ │ │ │ │ ├── uk.js
│ │ │ │ │ │ ├── uz.js
│ │ │ │ │ │ ├── vi.js
│ │ │ │ │ │ ├── zh-cn.js
│ │ │ │ │ │ └── zh-tw.js
│ │ │ │ │ └── moment.js
│ │ │ │ └── templates/
│ │ │ │ ├── amd-named.js
│ │ │ │ ├── amd.js
│ │ │ │ ├── globals.js
│ │ │ │ ├── locale-header.js
│ │ │ │ └── test-header.js
│ │ │ ├── ng-file-upload/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── FileAPI.flash.swf
│ │ │ │ ├── FileAPI.js
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── angular-file-upload-all.js
│ │ │ │ ├── angular-file-upload-shim.js
│ │ │ │ ├── angular-file-upload.js
│ │ │ │ ├── bower.json
│ │ │ │ └── ng-file-upload-all.js
│ │ │ ├── ngInfiniteScroll/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── build/
│ │ │ │ │ └── ng-infinite-scroll.js
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ └── infinite-scroll.coffee
│ │ │ ├── ngtoast/
│ │ │ │ ├── .bower.json
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ └── dist/
│ │ │ │ ├── ngToast-animations.css
│ │ │ │ ├── ngToast.css
│ │ │ │ └── ngToast.js
│ │ │ └── openlayers/
│ │ │ ├── .bower.json
│ │ │ ├── .gitignore
│ │ │ ├── apidoc_config/
│ │ │ │ ├── Languages.txt
│ │ │ │ ├── Menu.txt
│ │ │ │ ├── OL.css
│ │ │ │ └── Topics.txt
│ │ │ ├── authors.txt
│ │ │ ├── build/
│ │ │ │ ├── README.txt
│ │ │ │ ├── build.py
│ │ │ │ ├── buildUncompressed.py
│ │ │ │ ├── closure-compiler/
│ │ │ │ │ └── Externs.js
│ │ │ │ ├── full.cfg
│ │ │ │ ├── license.txt
│ │ │ │ ├── light.cfg
│ │ │ │ ├── lite.cfg
│ │ │ │ ├── mobile.cfg
│ │ │ │ └── tests.cfg
│ │ │ ├── doc_config/
│ │ │ │ ├── Languages.txt
│ │ │ │ ├── Menu.txt
│ │ │ │ ├── OL.css
│ │ │ │ └── Topics.txt
│ │ │ ├── lib/
│ │ │ │ ├── Firebug/
│ │ │ │ │ ├── firebug.css
│ │ │ │ │ ├── firebug.html
│ │ │ │ │ ├── firebug.js
│ │ │ │ │ ├── firebugx.js
│ │ │ │ │ ├── license.txt
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── OpenLayers/
│ │ │ │ │ ├── Animation.js
│ │ │ │ │ ├── BaseTypes/
│ │ │ │ │ │ ├── Bounds.js
│ │ │ │ │ │ ├── Class.js
│ │ │ │ │ │ ├── Date.js
│ │ │ │ │ │ ├── Element.js
│ │ │ │ │ │ ├── LonLat.js
│ │ │ │ │ │ ├── Pixel.js
│ │ │ │ │ │ └── Size.js
│ │ │ │ │ ├── BaseTypes.js
│ │ │ │ │ ├── Console.js
│ │ │ │ │ ├── Control/
│ │ │ │ │ │ ├── ArgParser.js
│ │ │ │ │ │ ├── Attribution.js
│ │ │ │ │ │ ├── Button.js
│ │ │ │ │ │ ├── CacheRead.js
│ │ │ │ │ │ ├── CacheWrite.js
│ │ │ │ │ │ ├── DragFeature.js
│ │ │ │ │ │ ├── DragPan.js
│ │ │ │ │ │ ├── DrawFeature.js
│ │ │ │ │ │ ├── EditingToolbar.js
│ │ │ │ │ │ ├── Geolocate.js
│ │ │ │ │ │ ├── GetFeature.js
│ │ │ │ │ │ ├── Graticule.js
│ │ │ │ │ │ ├── KeyboardDefaults.js
│ │ │ │ │ │ ├── LayerSwitcher.js
│ │ │ │ │ │ ├── Measure.js
│ │ │ │ │ │ ├── ModifyFeature/
│ │ │ │ │ │ │ └── BySegment.js
│ │ │ │ │ │ ├── ModifyFeature.js
│ │ │ │ │ │ ├── MousePosition.js
│ │ │ │ │ │ ├── NavToolbar.js
│ │ │ │ │ │ ├── Navigation.js
│ │ │ │ │ │ ├── NavigationHistory.js
│ │ │ │ │ │ ├── OverviewMap.js
│ │ │ │ │ │ ├── Pan.js
│ │ │ │ │ │ ├── PanPanel.js
│ │ │ │ │ │ ├── PanZoom.js
│ │ │ │ │ │ ├── PanZoomBar.js
│ │ │ │ │ │ ├── Panel.js
│ │ │ │ │ │ ├── Permalink.js
│ │ │ │ │ │ ├── PinchZoom.js
│ │ │ │ │ │ ├── SLDSelect.js
│ │ │ │ │ │ ├── Scale.js
│ │ │ │ │ │ ├── ScaleLine.js
│ │ │ │ │ │ ├── SelectFeature.js
│ │ │ │ │ │ ├── Snapping.js
│ │ │ │ │ │ ├── Split.js
│ │ │ │ │ │ ├── TextButtonPanel.js
│ │ │ │ │ │ ├── TouchNavigation.js
│ │ │ │ │ │ ├── TransformFeature.js
│ │ │ │ │ │ ├── UTFGrid.js
│ │ │ │ │ │ ├── WMSGetFeatureInfo.js
│ │ │ │ │ │ ├── WMTSGetFeatureInfo.js
│ │ │ │ │ │ ├── Zoom.js
│ │ │ │ │ │ ├── ZoomBox.js
│ │ │ │ │ │ ├── ZoomIn.js
│ │ │ │ │ │ ├── ZoomOut.js
│ │ │ │ │ │ ├── ZoomPanel.js
│ │ │ │ │ │ └── ZoomToMaxExtent.js
│ │ │ │ │ ├── Control.js
│ │ │ │ │ ├── Events/
│ │ │ │ │ │ ├── buttonclick.js
│ │ │ │ │ │ └── featureclick.js
│ │ │ │ │ ├── Events.js
│ │ │ │ │ ├── Feature/
│ │ │ │ │ │ └── Vector.js
│ │ │ │ │ ├── Feature.js
│ │ │ │ │ ├── Filter/
│ │ │ │ │ │ ├── Comparison.js
│ │ │ │ │ │ ├── FeatureId.js
│ │ │ │ │ │ ├── Function.js
│ │ │ │ │ │ ├── Logical.js
│ │ │ │ │ │ └── Spatial.js
│ │ │ │ │ ├── Filter.js
│ │ │ │ │ ├── Format/
│ │ │ │ │ │ ├── ArcXML/
│ │ │ │ │ │ │ └── Features.js
│ │ │ │ │ │ ├── ArcXML.js
│ │ │ │ │ │ ├── Atom.js
│ │ │ │ │ │ ├── CQL.js
│ │ │ │ │ │ ├── CSWGetDomain/
│ │ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ │ ├── CSWGetDomain.js
│ │ │ │ │ │ ├── CSWGetRecords/
│ │ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ │ ├── CSWGetRecords.js
│ │ │ │ │ │ ├── Context.js
│ │ │ │ │ │ ├── EncodedPolyline.js
│ │ │ │ │ │ ├── Filter/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ ├── v2.js
│ │ │ │ │ │ │ └── v2_0_0.js
│ │ │ │ │ │ ├── Filter.js
│ │ │ │ │ │ ├── GML/
│ │ │ │ │ │ │ ├── Base.js
│ │ │ │ │ │ │ ├── v2.js
│ │ │ │ │ │ │ └── v3.js
│ │ │ │ │ │ ├── GML.js
│ │ │ │ │ │ ├── GPX.js
│ │ │ │ │ │ ├── GeoJSON.js
│ │ │ │ │ │ ├── GeoRSS.js
│ │ │ │ │ │ ├── JSON.js
│ │ │ │ │ │ ├── KML.js
│ │ │ │ │ │ ├── OGCExceptionReport.js
│ │ │ │ │ │ ├── OSM.js
│ │ │ │ │ │ ├── OWSCommon/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── OWSCommon.js
│ │ │ │ │ │ ├── OWSContext/
│ │ │ │ │ │ │ └── v0_3_1.js
│ │ │ │ │ │ ├── OWSContext.js
│ │ │ │ │ │ ├── QueryStringFilter.js
│ │ │ │ │ │ ├── SLD/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_0_0_GeoServer.js
│ │ │ │ │ │ ├── SLD.js
│ │ │ │ │ │ ├── SOSCapabilities/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── SOSCapabilities.js
│ │ │ │ │ │ ├── SOSGetFeatureOfInterest.js
│ │ │ │ │ │ ├── SOSGetObservation.js
│ │ │ │ │ │ ├── TMSCapabilities.js
│ │ │ │ │ │ ├── Text.js
│ │ │ │ │ │ ├── WCSCapabilities/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── WCSCapabilities.js
│ │ │ │ │ │ ├── WCSDescribeCoverage/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── WCSDescribeCoverage.js
│ │ │ │ │ │ ├── WCSGetCoverage.js
│ │ │ │ │ │ ├── WFS.js
│ │ │ │ │ │ ├── WFSCapabilities/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ └── v2_0_0.js
│ │ │ │ │ │ ├── WFSCapabilities.js
│ │ │ │ │ │ ├── WFSDescribeFeatureType.js
│ │ │ │ │ │ ├── WFST/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ └── v2_0_0.js
│ │ │ │ │ │ ├── WFST.js
│ │ │ │ │ │ ├── WKT.js
│ │ │ │ │ │ ├── WMC/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── WMC.js
│ │ │ │ │ │ ├── WMSCapabilities/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_1.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ ├── v1_1_1.js
│ │ │ │ │ │ │ ├── v1_1_1_WMSC.js
│ │ │ │ │ │ │ ├── v1_3.js
│ │ │ │ │ │ │ └── v1_3_0.js
│ │ │ │ │ │ ├── WMSCapabilities.js
│ │ │ │ │ │ ├── WMSDescribeLayer/
│ │ │ │ │ │ │ └── v1_1.js
│ │ │ │ │ │ ├── WMSDescribeLayer.js
│ │ │ │ │ │ ├── WMSGetFeatureInfo.js
│ │ │ │ │ │ ├── WMTSCapabilities/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── WMTSCapabilities.js
│ │ │ │ │ │ ├── WPSCapabilities/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── WPSCapabilities.js
│ │ │ │ │ │ ├── WPSDescribeProcess/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── WPSDescribeProcess.js
│ │ │ │ │ │ ├── WPSExecute.js
│ │ │ │ │ │ ├── XLS/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ └── v1_1_0.js
│ │ │ │ │ │ ├── XLS.js
│ │ │ │ │ │ ├── XML/
│ │ │ │ │ │ │ └── VersionedOGC.js
│ │ │ │ │ │ └── XML.js
│ │ │ │ │ ├── Format.js
│ │ │ │ │ ├── Geometry/
│ │ │ │ │ │ ├── Collection.js
│ │ │ │ │ │ ├── Curve.js
│ │ │ │ │ │ ├── LineString.js
│ │ │ │ │ │ ├── LinearRing.js
│ │ │ │ │ │ ├── MultiLineString.js
│ │ │ │ │ │ ├── MultiPoint.js
│ │ │ │ │ │ ├── MultiPolygon.js
│ │ │ │ │ │ ├── Point.js
│ │ │ │ │ │ └── Polygon.js
│ │ │ │ │ ├── Geometry.js
│ │ │ │ │ ├── Handler/
│ │ │ │ │ │ ├── Box.js
│ │ │ │ │ │ ├── Click.js
│ │ │ │ │ │ ├── Drag.js
│ │ │ │ │ │ ├── Feature.js
│ │ │ │ │ │ ├── Hover.js
│ │ │ │ │ │ ├── Keyboard.js
│ │ │ │ │ │ ├── MouseWheel.js
│ │ │ │ │ │ ├── Path.js
│ │ │ │ │ │ ├── Pinch.js
│ │ │ │ │ │ ├── Point.js
│ │ │ │ │ │ ├── Polygon.js
│ │ │ │ │ │ └── RegularPolygon.js
│ │ │ │ │ ├── Handler.js
│ │ │ │ │ ├── Icon.js
│ │ │ │ │ ├── Kinetic.js
│ │ │ │ │ ├── Lang/
│ │ │ │ │ │ ├── ar.js
│ │ │ │ │ │ ├── be-tarask.js
│ │ │ │ │ │ ├── bg.js
│ │ │ │ │ │ ├── br.js
│ │ │ │ │ │ ├── ca.js
│ │ │ │ │ │ ├── cs-CZ.js
│ │ │ │ │ │ ├── da-DK.js
│ │ │ │ │ │ ├── de.js
│ │ │ │ │ │ ├── el.js
│ │ │ │ │ │ ├── en-CA.js
│ │ │ │ │ │ ├── en.js
│ │ │ │ │ │ ├── es.js
│ │ │ │ │ │ ├── fi.js
│ │ │ │ │ │ ├── fr.js
│ │ │ │ │ │ ├── fur.js
│ │ │ │ │ │ ├── gl.js
│ │ │ │ │ │ ├── gsw.js
│ │ │ │ │ │ ├── hr.js
│ │ │ │ │ │ ├── hsb.js
│ │ │ │ │ │ ├── hu.js
│ │ │ │ │ │ ├── ia.js
│ │ │ │ │ │ ├── id.js
│ │ │ │ │ │ ├── io.js
│ │ │ │ │ │ ├── is.js
│ │ │ │ │ │ ├── it.js
│ │ │ │ │ │ ├── ja.js
│ │ │ │ │ │ ├── km.js
│ │ │ │ │ │ ├── ksh.js
│ │ │ │ │ │ ├── lt.js
│ │ │ │ │ │ ├── nb.js
│ │ │ │ │ │ ├── nds.js
│ │ │ │ │ │ ├── nl.js
│ │ │ │ │ │ ├── nn.js
│ │ │ │ │ │ ├── oc.js
│ │ │ │ │ │ ├── pl.js
│ │ │ │ │ │ ├── pt-BR.js
│ │ │ │ │ │ ├── pt.js
│ │ │ │ │ │ ├── ro.js
│ │ │ │ │ │ ├── ru.js
│ │ │ │ │ │ ├── sk.js
│ │ │ │ │ │ ├── sv-SE.js
│ │ │ │ │ │ ├── te.js
│ │ │ │ │ │ ├── vi.js
│ │ │ │ │ │ ├── zh-CN.js
│ │ │ │ │ │ └── zh-TW.js
│ │ │ │ │ ├── Lang.js
│ │ │ │ │ ├── Layer/
│ │ │ │ │ │ ├── ArcGIS93Rest.js
│ │ │ │ │ │ ├── ArcGISCache.js
│ │ │ │ │ │ ├── ArcIMS.js
│ │ │ │ │ │ ├── Bing.js
│ │ │ │ │ │ ├── Boxes.js
│ │ │ │ │ │ ├── EventPane.js
│ │ │ │ │ │ ├── FixedZoomLevels.js
│ │ │ │ │ │ ├── GeoRSS.js
│ │ │ │ │ │ ├── Google/
│ │ │ │ │ │ │ └── v3.js
│ │ │ │ │ │ ├── Google.js
│ │ │ │ │ │ ├── Grid.js
│ │ │ │ │ │ ├── HTTPRequest.js
│ │ │ │ │ │ ├── Image.js
│ │ │ │ │ │ ├── KaMap.js
│ │ │ │ │ │ ├── KaMapCache.js
│ │ │ │ │ │ ├── MapGuide.js
│ │ │ │ │ │ ├── MapServer.js
│ │ │ │ │ │ ├── Markers.js
│ │ │ │ │ │ ├── OSM.js
│ │ │ │ │ │ ├── PointGrid.js
│ │ │ │ │ │ ├── PointTrack.js
│ │ │ │ │ │ ├── SphericalMercator.js
│ │ │ │ │ │ ├── TMS.js
│ │ │ │ │ │ ├── Text.js
│ │ │ │ │ │ ├── TileCache.js
│ │ │ │ │ │ ├── UTFGrid.js
│ │ │ │ │ │ ├── Vector/
│ │ │ │ │ │ │ └── RootContainer.js
│ │ │ │ │ │ ├── Vector.js
│ │ │ │ │ │ ├── WMS.js
│ │ │ │ │ │ ├── WMTS.js
│ │ │ │ │ │ ├── WorldWind.js
│ │ │ │ │ │ ├── XYZ.js
│ │ │ │ │ │ └── Zoomify.js
│ │ │ │ │ ├── Layer.js
│ │ │ │ │ ├── Map.js
│ │ │ │ │ ├── Marker/
│ │ │ │ │ │ └── Box.js
│ │ │ │ │ ├── Marker.js
│ │ │ │ │ ├── Popup/
│ │ │ │ │ │ ├── Anchored.js
│ │ │ │ │ │ ├── Framed.js
│ │ │ │ │ │ └── FramedCloud.js
│ │ │ │ │ ├── Popup.js
│ │ │ │ │ ├── Projection.js
│ │ │ │ │ ├── Protocol/
│ │ │ │ │ │ ├── CSW/
│ │ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ │ ├── CSW.js
│ │ │ │ │ │ ├── HTTP.js
│ │ │ │ │ │ ├── SOS/
│ │ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ │ ├── SOS.js
│ │ │ │ │ │ ├── Script.js
│ │ │ │ │ │ ├── WFS/
│ │ │ │ │ │ │ ├── v1.js
│ │ │ │ │ │ │ ├── v1_0_0.js
│ │ │ │ │ │ │ ├── v1_1_0.js
│ │ │ │ │ │ │ └── v2_0_0.js
│ │ │ │ │ │ └── WFS.js
│ │ │ │ │ ├── Protocol.js
│ │ │ │ │ ├── Renderer/
│ │ │ │ │ │ ├── Canvas.js
│ │ │ │ │ │ ├── Elements.js
│ │ │ │ │ │ ├── SVG.js
│ │ │ │ │ │ └── VML.js
│ │ │ │ │ ├── Renderer.js
│ │ │ │ │ ├── Request/
│ │ │ │ │ │ └── XMLHttpRequest.js
│ │ │ │ │ ├── Request.js
│ │ │ │ │ ├── Rule.js
│ │ │ │ │ ├── SingleFile.js
│ │ │ │ │ ├── Spherical.js
│ │ │ │ │ ├── Strategy/
│ │ │ │ │ │ ├── BBOX.js
│ │ │ │ │ │ ├── Cluster.js
│ │ │ │ │ │ ├── Filter.js
│ │ │ │ │ │ ├── Fixed.js
│ │ │ │ │ │ ├── Paging.js
│ │ │ │ │ │ ├── Refresh.js
│ │ │ │ │ │ └── Save.js
│ │ │ │ │ ├── Strategy.js
│ │ │ │ │ ├── Style.js
│ │ │ │ │ ├── Style2.js
│ │ │ │ │ ├── StyleMap.js
│ │ │ │ │ ├── Symbolizer/
│ │ │ │ │ │ ├── Line.js
│ │ │ │ │ │ ├── Point.js
│ │ │ │ │ │ ├── Polygon.js
│ │ │ │ │ │ ├── Raster.js
│ │ │ │ │ │ └── Text.js
│ │ │ │ │ ├── Symbolizer.js
│ │ │ │ │ ├── Tile/
│ │ │ │ │ │ ├── Image/
│ │ │ │ │ │ │ └── IFrame.js
│ │ │ │ │ │ ├── Image.js
│ │ │ │ │ │ └── UTFGrid.js
│ │ │ │ │ ├── Tile.js
│ │ │ │ │ ├── TileManager.js
│ │ │ │ │ ├── Tween.js
│ │ │ │ │ ├── Util/
│ │ │ │ │ │ └── vendorPrefix.js
│ │ │ │ │ ├── Util.js
│ │ │ │ │ ├── WPSClient.js
│ │ │ │ │ └── WPSProcess.js
│ │ │ │ ├── OpenLayers.js
│ │ │ │ ├── Rico/
│ │ │ │ │ ├── Color.js
│ │ │ │ │ ├── Corner.js
│ │ │ │ │ └── license.js
│ │ │ │ └── deprecated.js
│ │ │ ├── license.txt
│ │ │ ├── licenses/
│ │ │ │ ├── APACHE-2.0.txt
│ │ │ │ ├── BSD-LICENSE.txt
│ │ │ │ └── MIT-LICENSE.txt
│ │ │ ├── notes/
│ │ │ │ ├── 2.12.md
│ │ │ │ ├── 2.13.md
│ │ │ │ └── 2.14.md
│ │ │ ├── readme.md
│ │ │ ├── tests/
│ │ │ │ ├── Animation.html
│ │ │ │ ├── BaseTypes/
│ │ │ │ │ ├── Bounds.html
│ │ │ │ │ ├── Class.html
│ │ │ │ │ ├── Date.html
│ │ │ │ │ ├── Element.html
│ │ │ │ │ ├── LonLat.html
│ │ │ │ │ ├── Pixel.html
│ │ │ │ │ └── Size.html
│ │ │ │ ├── BaseTypes.html
│ │ │ │ ├── Console.html
│ │ │ │ ├── Control/
│ │ │ │ │ ├── ArgParser.html
│ │ │ │ │ ├── Attribution.html
│ │ │ │ │ ├── Button.html
│ │ │ │ │ ├── CacheRead.html
│ │ │ │ │ ├── CacheWrite.html
│ │ │ │ │ ├── DragFeature.html
│ │ │ │ │ ├── DragPan.html
│ │ │ │ │ ├── DrawFeature.html
│ │ │ │ │ ├── EditingToolbar.html
│ │ │ │ │ ├── Geolocate.html
│ │ │ │ │ ├── GetFeature.html
│ │ │ │ │ ├── Graticule.html
│ │ │ │ │ ├── KeyboardDefaults.html
│ │ │ │ │ ├── LayerSwitcher.html
│ │ │ │ │ ├── Measure.html
│ │ │ │ │ ├── ModifyFeature/
│ │ │ │ │ │ └── BySegment.html
│ │ │ │ │ ├── ModifyFeature.html
│ │ │ │ │ ├── MousePosition.html
│ │ │ │ │ ├── NavToolbar.html
│ │ │ │ │ ├── Navigation.html
│ │ │ │ │ ├── NavigationHistory.html
│ │ │ │ │ ├── OverviewMap.html
│ │ │ │ │ ├── Pan.html
│ │ │ │ │ ├── PanPanel.html
│ │ │ │ │ ├── PanZoom.html
│ │ │ │ │ ├── PanZoomBar.html
│ │ │ │ │ ├── Panel.html
│ │ │ │ │ ├── Permalink.html
│ │ │ │ │ ├── PinchZoom.html
│ │ │ │ │ ├── SLDSelect.html
│ │ │ │ │ ├── Scale.html
│ │ │ │ │ ├── ScaleLine.html
│ │ │ │ │ ├── SelectFeature.html
│ │ │ │ │ ├── Snapping.html
│ │ │ │ │ ├── Split.html
│ │ │ │ │ ├── TextButtonPanel.html
│ │ │ │ │ ├── TouchNavigation.html
│ │ │ │ │ ├── TransformFeature.html
│ │ │ │ │ ├── UTFGrid.html
│ │ │ │ │ ├── WMSGetFeatureInfo.html
│ │ │ │ │ ├── WMTSGetFeatureInfo.html
│ │ │ │ │ ├── Zoom.html
│ │ │ │ │ ├── ZoomBox.html
│ │ │ │ │ ├── ZoomIn.html
│ │ │ │ │ ├── ZoomOut.html
│ │ │ │ │ └── ZoomToMaxExtent.html
│ │ │ │ ├── Control.html
│ │ │ │ ├── Events/
│ │ │ │ │ ├── buttonclick.html
│ │ │ │ │ └── featureclick.html
│ │ │ │ ├── Events.html
│ │ │ │ ├── Extras.html
│ │ │ │ ├── Feature/
│ │ │ │ │ └── Vector.html
│ │ │ │ ├── Feature.html
│ │ │ │ ├── Filter/
│ │ │ │ │ ├── Comparison.html
│ │ │ │ │ ├── FeatureId.html
│ │ │ │ │ ├── Logical.html
│ │ │ │ │ └── Spatial.html
│ │ │ │ ├── Filter.html
│ │ │ │ ├── Format/
│ │ │ │ │ ├── ArcXML/
│ │ │ │ │ │ └── Features.html
│ │ │ │ │ ├── ArcXML.html
│ │ │ │ │ ├── Atom.html
│ │ │ │ │ ├── CQL.html
│ │ │ │ │ ├── CSWGetDomain/
│ │ │ │ │ │ ├── v2_0_2.html
│ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ ├── CSWGetDomain.html
│ │ │ │ │ ├── CSWGetRecords/
│ │ │ │ │ │ ├── v2_0_2.html
│ │ │ │ │ │ └── v2_0_2.js
│ │ │ │ │ ├── CSWGetRecords.html
│ │ │ │ │ ├── EncodedPolyline.html
│ │ │ │ │ ├── Filter/
│ │ │ │ │ │ ├── v1.html
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ ├── v1_1_0.html
│ │ │ │ │ │ └── v2_0_0.html
│ │ │ │ │ ├── Filter.html
│ │ │ │ │ ├── GML/
│ │ │ │ │ │ ├── cases.js
│ │ │ │ │ │ ├── v2.html
│ │ │ │ │ │ └── v3.html
│ │ │ │ │ ├── GML.html
│ │ │ │ │ ├── GPX.html
│ │ │ │ │ ├── GeoJSON.html
│ │ │ │ │ ├── GeoRSS.html
│ │ │ │ │ ├── JSON.html
│ │ │ │ │ ├── KML.html
│ │ │ │ │ ├── OGCExceptionReport.html
│ │ │ │ │ ├── OSM.html
│ │ │ │ │ ├── OWSCommon/
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ └── v1_1_0.html
│ │ │ │ │ ├── OWSContext/
│ │ │ │ │ │ └── v0_3_1.html
│ │ │ │ │ ├── QueryStringFilter.html
│ │ │ │ │ ├── SLD/
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ └── v1_0_0_GeoServer.html
│ │ │ │ │ ├── SLD.html
│ │ │ │ │ ├── SOSCapabilities/
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ ├── SOSGetFeatureOfInterest.html
│ │ │ │ │ ├── SOSGetObservation.html
│ │ │ │ │ ├── TMSCapabilities.html
│ │ │ │ │ ├── Text.html
│ │ │ │ │ ├── WCSCapabilities/
│ │ │ │ │ │ └── v1.html
│ │ │ │ │ ├── WCSCapabilities.html
│ │ │ │ │ ├── WCSDescribeCoverage/
│ │ │ │ │ │ └── v1.html
│ │ │ │ │ ├── WCSDescribeCoverage.html
│ │ │ │ │ ├── WCSGetCoverage.html
│ │ │ │ │ ├── WFS.html
│ │ │ │ │ ├── WFSCapabilities/
│ │ │ │ │ │ ├── v1.html
│ │ │ │ │ │ └── v2.html
│ │ │ │ │ ├── WFSCapabilities.html
│ │ │ │ │ ├── WFSDescribeFeatureType.html
│ │ │ │ │ ├── WFST/
│ │ │ │ │ │ ├── v1.html
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ ├── v1_1_0.html
│ │ │ │ │ │ └── v2_0_0.html
│ │ │ │ │ ├── WFST.html
│ │ │ │ │ ├── WKT.html
│ │ │ │ │ ├── WMC/
│ │ │ │ │ │ ├── v1.html
│ │ │ │ │ │ └── v1_1_0.html
│ │ │ │ │ ├── WMC.html
│ │ │ │ │ ├── WMSCapabilities/
│ │ │ │ │ │ ├── v1_1_1.html
│ │ │ │ │ │ ├── v1_1_1_WMSC.html
│ │ │ │ │ │ └── v1_3_0.html
│ │ │ │ │ ├── WMSCapabilities.html
│ │ │ │ │ ├── WMSDescribeLayer.html
│ │ │ │ │ ├── WMSGetFeatureInfo.html
│ │ │ │ │ ├── WMTSCapabilities/
│ │ │ │ │ │ └── v1_0_0.html
│ │ │ │ │ ├── WMTSCapabilities.html
│ │ │ │ │ ├── WPSCapabilities/
│ │ │ │ │ │ ├── v1_0_0.html
│ │ │ │ │ │ └── v1_0_0.js
│ │ │ │ │ ├── WPSDescribeProcess.html
│ │ │ │ │ ├── WPSExecute.html
│ │ │ │ │ ├── XLS/
│ │ │ │ │ │ └── v1_1_0.html
│ │ │ │ │ ├── XML/
│ │ │ │ │ │ └── VersionedOGC.html
│ │ │ │ │ └── XML.html
│ │ │ │ ├── Format.html
│ │ │ │ ├── Geometry/
│ │ │ │ │ ├── Collection.html
│ │ │ │ │ ├── Curve.html
│ │ │ │ │ ├── LineString.html
│ │ │ │ │ ├── LinearRing.html
│ │ │ │ │ ├── MultiLineString.html
│ │ │ │ │ ├── MultiPoint.html
│ │ │ │ │ ├── MultiPolygon.html
│ │ │ │ │ ├── Point.html
│ │ │ │ │ └── Polygon.html
│ │ │ │ ├── Geometry.html
│ │ │ │ ├── Handler/
│ │ │ │ │ ├── Box.html
│ │ │ │ │ ├── Click.html
│ │ │ │ │ ├── Drag.html
│ │ │ │ │ ├── Feature.html
│ │ │ │ │ ├── Hover.html
│ │ │ │ │ ├── Keyboard.html
│ │ │ │ │ ├── MouseWheel.html
│ │ │ │ │ ├── Path.html
│ │ │ │ │ ├── Pinch.html
│ │ │ │ │ ├── Point.html
│ │ │ │ │ ├── Polygon.html
│ │ │ │ │ └── RegularPolygon.html
│ │ │ │ ├── Handler.html
│ │ │ │ ├── Icon.html
│ │ │ │ ├── Kinetic.html
│ │ │ │ ├── Lang.html
│ │ │ │ ├── Layer/
│ │ │ │ │ ├── ArcGIS93Rest.html
│ │ │ │ │ ├── ArcGISCache.html
│ │ │ │ │ ├── ArcGISCache.json
│ │ │ │ │ ├── ArcIMS.html
│ │ │ │ │ ├── Bing.html
│ │ │ │ │ ├── EventPane.html
│ │ │ │ │ ├── FixedZoomLevels.html
│ │ │ │ │ ├── GeoRSS.html
│ │ │ │ │ ├── Google/
│ │ │ │ │ │ └── v3.html
│ │ │ │ │ ├── Grid.html
│ │ │ │ │ ├── HTTPRequest.html
│ │ │ │ │ ├── Image.html
│ │ │ │ │ ├── KaMap.html
│ │ │ │ │ ├── MapGuide.html
│ │ │ │ │ ├── MapServer.html
│ │ │ │ │ ├── Markers.html
│ │ │ │ │ ├── OSM.html
│ │ │ │ │ ├── PointGrid.html
│ │ │ │ │ ├── PointTrack.html
│ │ │ │ │ ├── SphericalMercator.html
│ │ │ │ │ ├── TMS.html
│ │ │ │ │ ├── Text.html
│ │ │ │ │ ├── TileCache.html
│ │ │ │ │ ├── UTFGrid.html
│ │ │ │ │ ├── Vector/
│ │ │ │ │ │ └── RootContainer.html
│ │ │ │ │ ├── Vector.html
│ │ │ │ │ ├── WMS.html
│ │ │ │ │ ├── WMTS.html
│ │ │ │ │ ├── WrapDateLine.html
│ │ │ │ │ ├── XYZ.html
│ │ │ │ │ ├── atom-1.0.xml
│ │ │ │ │ ├── data_Layer_Text_textfile.txt
│ │ │ │ │ ├── data_Layer_Text_textfile_2.txt
│ │ │ │ │ ├── data_Layer_Text_textfile_overflow.txt
│ │ │ │ │ └── georss.txt
│ │ │ │ ├── Layer.html
│ │ │ │ ├── Map.html
│ │ │ │ ├── Marker/
│ │ │ │ │ └── Box.html
│ │ │ │ ├── Marker.html
│ │ │ │ ├── OLLoader.js
│ │ │ │ ├── OpenLayers1.html
│ │ │ │ ├── OpenLayers2.html
│ │ │ │ ├── OpenLayers3.html
│ │ │ │ ├── OpenLayers4.html
│ │ │ │ ├── OpenLayersJsFiles.html
│ │ │ │ ├── Popup/
│ │ │ │ │ ├── Anchored.html
│ │ │ │ │ └── FramedCloud.html
│ │ │ │ ├── Popup.html
│ │ │ │ ├── Projection.html
│ │ │ │ ├── Protocol/
│ │ │ │ │ ├── CSW.html
│ │ │ │ │ ├── HTTP.html
│ │ │ │ │ ├── SOS.html
│ │ │ │ │ ├── Script.html
│ │ │ │ │ └── WFS.html
│ │ │ │ ├── Protocol.html
│ │ │ │ ├── README.txt
│ │ │ │ ├── Renderer/
│ │ │ │ │ ├── Canvas.html
│ │ │ │ │ ├── Elements.html
│ │ │ │ │ ├── SVG.html
│ │ │ │ │ └── VML.html
│ │ │ │ ├── Renderer.html
│ │ │ │ ├── Request/
│ │ │ │ │ └── XMLHttpRequest.html
│ │ │ │ ├── Request.html
│ │ │ │ ├── Rule.html
│ │ │ │ ├── SingleFile1.html
│ │ │ │ ├── SingleFile2.html
│ │ │ │ ├── SingleFile3.html
│ │ │ │ ├── Strategy/
│ │ │ │ │ ├── BBOX.html
│ │ │ │ │ ├── Cluster.html
│ │ │ │ │ ├── Filter.html
│ │ │ │ │ ├── Fixed.html
│ │ │ │ │ ├── Paging.html
│ │ │ │ │ ├── Refresh.html
│ │ │ │ │ └── Save.html
│ │ │ │ ├── Strategy.html
│ │ │ │ ├── Style.html
│ │ │ │ ├── Style2.html
│ │ │ │ ├── StyleMap.html
│ │ │ │ ├── Symbolizer/
│ │ │ │ │ ├── Line.html
│ │ │ │ │ ├── Point.html
│ │ │ │ │ ├── Polygon.html
│ │ │ │ │ ├── Raster.html
│ │ │ │ │ └── Text.html
│ │ │ │ ├── Symbolizer.html
│ │ │ │ ├── Test.AnotherWay.baseadditions.js
│ │ │ │ ├── Test.AnotherWay.css
│ │ │ │ ├── Test.AnotherWay.geom_eq.js
│ │ │ │ ├── Test.AnotherWay.js
│ │ │ │ ├── Test.AnotherWay.xml_eq.js
│ │ │ │ ├── Tile/
│ │ │ │ │ ├── Image/
│ │ │ │ │ │ └── IFrame.html
│ │ │ │ │ ├── Image.html
│ │ │ │ │ └── UTFGrid.html
│ │ │ │ ├── Tile.html
│ │ │ │ ├── TileManager.html
│ │ │ │ ├── Tween.html
│ │ │ │ ├── Util/
│ │ │ │ │ └── vendorPrefix.html
│ │ │ │ ├── Util.html
│ │ │ │ ├── Util_common.js
│ │ │ │ ├── Util_w3c.html
│ │ │ │ ├── WPSClient.html
│ │ │ │ ├── WPSProcess.html
│ │ │ │ ├── atom-1.0.xml
│ │ │ │ ├── auto-tests.html
│ │ │ │ ├── data_Layer_Text_textfile.txt
│ │ │ │ ├── data_Layer_Text_textfile_2.txt
│ │ │ │ ├── data_Layer_Text_textfile_overflow.txt
│ │ │ │ ├── deprecated/
│ │ │ │ │ ├── Ajax.html
│ │ │ │ │ ├── BaseTypes/
│ │ │ │ │ │ ├── Class.html
│ │ │ │ │ │ └── Element.html
│ │ │ │ │ ├── Control/
│ │ │ │ │ │ └── MouseToolbar.html
│ │ │ │ │ ├── Geometry/
│ │ │ │ │ │ └── Rectangle.html
│ │ │ │ │ ├── Layer/
│ │ │ │ │ │ ├── GML.html
│ │ │ │ │ │ ├── MapServer/
│ │ │ │ │ │ │ └── Untiled.html
│ │ │ │ │ │ ├── MapServer.html
│ │ │ │ │ │ ├── WFS.html
│ │ │ │ │ │ ├── WMS/
│ │ │ │ │ │ │ └── Post.html
│ │ │ │ │ │ ├── WMS.html
│ │ │ │ │ │ ├── Yahoo.html
│ │ │ │ │ │ ├── mice.xml
│ │ │ │ │ │ └── owls.xml
│ │ │ │ │ ├── Popup/
│ │ │ │ │ │ └── AnchoredBubble.html
│ │ │ │ │ ├── Protocol/
│ │ │ │ │ │ ├── SQL/
│ │ │ │ │ │ │ └── Gears.html
│ │ │ │ │ │ └── SQL.html
│ │ │ │ │ ├── Renderer/
│ │ │ │ │ │ └── SVG2.html
│ │ │ │ │ ├── Tile/
│ │ │ │ │ │ └── WFS.html
│ │ │ │ │ └── Util.html
│ │ │ │ ├── georss.txt
│ │ │ │ ├── grid_inittiles.html
│ │ │ │ ├── index.html
│ │ │ │ ├── list-tests.html
│ │ │ │ ├── manual/
│ │ │ │ │ ├── ajax.html
│ │ │ │ │ ├── ajax.txt
│ │ │ │ │ ├── alloverlays-mixed.html
│ │ │ │ │ ├── arcims-2117.html
│ │ │ │ │ ├── arkansas.rss
│ │ │ │ │ ├── big-georss.html
│ │ │ │ │ ├── box-quirks.html
│ │ │ │ │ ├── box-strict.html
│ │ │ │ │ ├── clip-features-svg.html
│ │ │ │ │ ├── dateline-sketch.html
│ │ │ │ │ ├── dateline-smallextent.html
│ │ │ │ │ ├── draw-feature.html
│ │ │ │ │ ├── feature-handler.html
│ │ │ │ │ ├── geodesic.html
│ │ │ │ │ ├── geojson-geomcoll-reprojection.html
│ │ │ │ │ ├── google-fullscreen-overlay.html
│ │ │ │ │ ├── google-panning.html
│ │ │ │ │ ├── google-resize.html
│ │ │ │ │ ├── google-tilt.html
│ │ │ │ │ ├── google-v3-resize.html
│ │ │ │ │ ├── loadend.html
│ │ │ │ │ ├── map-events.html
│ │ │ │ │ ├── memory/
│ │ │ │ │ │ ├── Marker-2258.html
│ │ │ │ │ │ ├── PanZoom-2323.html
│ │ │ │ │ │ ├── RemoveChild-2170.html
│ │ │ │ │ │ └── VML-2170.html
│ │ │ │ │ ├── multiple-google-layers.html
│ │ │ │ │ ├── overviewmap-projection.html
│ │ │ │ │ ├── page-position.html
│ │ │ │ │ ├── pan-redraw-svg.html
│ │ │ │ │ ├── popup-keepInMap.html
│ │ │ │ │ ├── reflow.html
│ │ │ │ │ ├── renderedDimensions.html
│ │ │ │ │ ├── select-feature-right-click.html
│ │ │ │ │ ├── select-feature.html
│ │ │ │ │ ├── tiles-loading.html
│ │ │ │ │ ├── tween.html
│ │ │ │ │ ├── vector-features-performance.html
│ │ │ │ │ └── vector-layer-zindex.html
│ │ │ │ ├── mice.xml
│ │ │ │ ├── node.js/
│ │ │ │ │ ├── mockdom.js
│ │ │ │ │ ├── node-tests.cfg
│ │ │ │ │ ├── node.js
│ │ │ │ │ ├── run-test.js
│ │ │ │ │ └── run.sh
│ │ │ │ ├── owls.xml
│ │ │ │ ├── run-tests.html
│ │ │ │ ├── selenium/
│ │ │ │ │ └── remotecontrol/
│ │ │ │ │ ├── config.cfg
│ │ │ │ │ ├── selenium.py
│ │ │ │ │ ├── setup.txt
│ │ │ │ │ └── test_ol.py
│ │ │ │ ├── speed/
│ │ │ │ │ ├── geometry.html
│ │ │ │ │ ├── string_format.html
│ │ │ │ │ ├── vector-renderers.html
│ │ │ │ │ ├── vector-renderers.js
│ │ │ │ │ ├── wmc_speed.html
│ │ │ │ │ ├── wmscaps.html
│ │ │ │ │ ├── wmscaps.js
│ │ │ │ │ └── wmscaps.xml
│ │ │ │ └── throws.js
│ │ │ ├── theme/
│ │ │ │ └── default/
│ │ │ │ ├── google.css
│ │ │ │ ├── ie6-style.css
│ │ │ │ ├── style.css
│ │ │ │ └── style.mobile.css
│ │ │ └── tools/
│ │ │ ├── BeautifulSoup.py
│ │ │ ├── README.txt
│ │ │ ├── closure_library_jscompiler.py
│ │ │ ├── closure_ws.py
│ │ │ ├── exampleparser.py
│ │ │ ├── jsmin.c
│ │ │ ├── jsmin.py
│ │ │ ├── mergejs.py
│ │ │ ├── minimize.py
│ │ │ ├── oldot.py
│ │ │ ├── release.sh
│ │ │ ├── shrinksafe.py
│ │ │ ├── toposort.py
│ │ │ ├── uglify_js.py
│ │ │ └── update_dev_dir.sh
│ │ ├── css/
│ │ │ ├── ie-only.css
│ │ │ └── tatami.css
│ │ └── vendor/
│ │ ├── backgroundsize.min.htc
│ │ ├── css/
│ │ │ └── bootstrap/
│ │ │ ├── css/
│ │ │ │ └── bootstrap.css
│ │ │ ├── fonts/
│ │ │ │ └── glyphiconshalflings-regular.otf
│ │ │ └── js/
│ │ │ └── bootstrap.js
│ │ └── js/
│ │ ├── marked/
│ │ │ └── marked.js
│ │ └── respond/
│ │ └── respond.js
│ ├── css/
│ │ ├── ie-only.css
│ │ ├── tatami.css
│ │ └── vendor/
│ │ ├── backgroundsize.min.htc
│ │ ├── css/
│ │ │ ├── bootstrap.css
│ │ │ └── jQueryjGrowl.css
│ │ └── fonts/
│ │ └── glyphiconshalflings-regular.otf
│ ├── index.html
│ ├── index.html.tpl
│ ├── index.jsp
│ ├── robots.txt
│ └── sitemap.xml
└── test/
├── java/
│ └── fr/
│ └── ippon/
│ └── tatami/
│ └── web/
│ └── rest/
│ ├── GroupControllerTest.java
│ ├── TagControllerTest.java
│ ├── TimelineControllerTest.java
│ └── UserControllerTest.java
└── javascript/
└── webapp/
└── app/
└── components/
├── about/
│ └── license/
│ └── LicenseController_spec.js
├── account/
│ ├── PasswordModule_spec.js
│ └── preferences/
│ └── Preferences_spec.js
└── home/
└── status/
└── StatusController_spec.js
Copy disabled (too large)
Download .json
Condensed preview — 1921 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (14,377K chars).
[
{
"path": ".gitignore",
"chars": 492,
"preview": "data\n.idea\n*.iml\ntatami.iml\ntatami.ipr\ntatami.iws\n.classpath\n.project\n.settings\ntarget\nnode_modules/\nweb/node_modules/\ns"
},
{
"path": "CONTRIBUTING.md",
"chars": 1482,
"preview": "Contributing to Tatami\n=========================\n\nOpen Source\n------------------\n\nTatami is an Open Source project, whic"
},
{
"path": "README.md",
"chars": 7622,
"preview": "Tatami\n================\n\nPresentation\n------------------\n\nTatami is an Open Source enterprise social network.\n\nA public "
},
{
"path": "etc/installation/ubuntu/files/maven/settings.xml",
"chars": 756,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<settings xmlns=\"http://maven.apache.org/SETTINGS/1.0.0\"\n xmlns:xsi=\"ht"
},
{
"path": "etc/installation/ubuntu/install.sh",
"chars": 5351,
"preview": "#!/bin/sh\n#\n# description: Installs Tatami on Ubuntu\n# This script must be run by the \"root\" user.\n# Run this script dir"
},
{
"path": "etc/installation/ubuntu/uninstall.sh",
"chars": 475,
"preview": "#!/bin/sh\n#\n# description: Uninstalls Tatami on Ubuntu\n# This script must be run by the \"root\" user.\n#\n# Run this script"
},
{
"path": "etc/installation/ubuntu/update.sh",
"chars": 663,
"preview": "#!/bin/sh\n#\n# description: Updates Tatami from Git\n# This script must be run by the \"tatami\" user, who must be a sudoer."
},
{
"path": "jenkinsScripts/insertGoogleAuthKeys.sh",
"chars": 612,
"preview": "#!/bin/bash\n\n#Insert google auth variables into the build. \ngoogleKey=$1\ngoogleSecret=$2\nnewServer=$3\n\n\nusage='startTata"
},
{
"path": "jenkinsScripts/restoreDatabase.sh",
"chars": 183,
"preview": "#!/bin/bash\n\nrm -rf ../target/cassandra || true\nrm -rf ./target/elasticsearch || true\n\ntar -zxvf save.tar.gz -C ../targe"
},
{
"path": "jenkinsScripts/saveDatabase.sh",
"chars": 122,
"preview": "#!/bin/bash\n\ntar -zcvf save.tar.gz ../target/cassandra ../target/elasticsearch\ntar -zcvf db.tar.gz ./target/elasticsearc"
},
{
"path": "jenkinsScripts/startTatami.sh",
"chars": 322,
"preview": "#!/bin/bash\n\n#Insert google Authentication keys.\n./insertGoogleAuthKeys.sh $1 $2 $3\n\nif [ $? -ne 0 ]; then\n exit 1\nfi"
},
{
"path": "jenkinsScripts/stopTatami.sh",
"chars": 68,
"preview": "#!/bin/bash\ncat tatamiPID | xargs kill || true\nrm tatamiPID || true\n"
},
{
"path": "mobile/.bowerrc",
"chars": 29,
"preview": "{\n \"directory\": \"www/lib\"\n}\n"
},
{
"path": "mobile/.editorconfig",
"chars": 242,
"preview": "# http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 4\nend_of_line = lf\ninsert_"
},
{
"path": "mobile/.gitignore",
"chars": 147,
"preview": "# Specifies intentionally untracked files to ignore when using Git\n# http://git-scm.com/docs/gitignore\n\nwww/lib/\nnode_mo"
},
{
"path": "mobile/README.md",
"chars": 702,
"preview": "Tatami Mobile Beta\n==================\n\nIf interested in the mobile beta, follow these steps:\n\nPrepare Project\n----------"
},
{
"path": "mobile/bower.json",
"chars": 645,
"preview": "{\n \"name\": \"tatami\",\n \"private\": \"true\",\n \"devDependencies\": {\n \"ionic\": \"~1.2.4\",\n \"angular-mocks\": \"1.4.3\",\n "
},
{
"path": "mobile/config.xml",
"chars": 4903,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<widget id=\"com.ippon.tatami.mobile\" version=\"1.0.1\" xmlns=\"http"
},
{
"path": "mobile/gulpfile.js",
"chars": 2574,
"preview": "var gulp = require('gulp');\nvar gutil = require('gulp-util');\nvar bower = require('bower');\nvar concat = require('gulp-c"
},
{
"path": "mobile/hooks/README.md",
"chars": 3018,
"preview": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements. See the N"
},
{
"path": "mobile/hooks/after_prepare/010_add_platform_class.js",
"chars": 2735,
"preview": "#!/usr/bin/env node\n\n// Add Platform Class\n// v1.0\n// Automatically adds the platform class to the body tag\n// after the"
},
{
"path": "mobile/ionic.project",
"chars": 393,
"preview": "{\n \"name\": \"mobile\",\n \"app_id\": \"\",\n \"proxies\": [\n {\n \"path\": \"/tatami\",\n \"proxyUr"
},
{
"path": "mobile/karma.ci.conf.js",
"chars": 2287,
"preview": "// Karma configuration\n// Generated on Wed May 06 2015 15:23:11 GMT-0400 (EDT)\n\nmodule.exports = function (config) {\n "
},
{
"path": "mobile/package.json",
"chars": 1319,
"preview": "{\n \"name\": \"mobile\",\n \"version\": \"1.1.1\",\n \"description\": \"mobile: An Ionic project\",\n \"dependencies\": {\n \"gulp\":"
},
{
"path": "mobile/pom.xml",
"chars": 7491,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n xmlns:xsi=\"http://www"
},
{
"path": "mobile/scss/ionic.app.scss",
"chars": 1552,
"preview": "/*\nTo customize the look and feel of Ionic, you can override the variables\nin ionic's _variables.scss file.\n\nFor example"
},
{
"path": "mobile/www/app/components/follow/follow.html",
"chars": 767,
"preview": "<ion-view>\n <ion-tabs class=\"tabs-icon-top tabs-color-active-positive\">\n\n <ion-tab title=\"{{ 'tab.suggested.ti"
},
{
"path": "mobile/www/app/components/follow/follow.js",
"chars": 1036,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(followConfig);\n\n followConfig.$inject ="
},
{
"path": "mobile/www/app/components/follow/follower/follower.controller.js",
"chars": 659,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('FollowerCtrl', followerCtrl);\n\n fo"
},
{
"path": "mobile/www/app/components/follow/follower/follower.html",
"chars": 423,
"preview": "<ion-view view-title=\"{{ 'tab.follower' | translate }}\">\n <ion-content class=\"tatami-header tatami-footer\" ng-style=\""
},
{
"path": "mobile/www/app/components/follow/follower/follower.js",
"chars": 1186,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/follow/following/following.controller.js",
"chars": 666,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('FollowingCtrl', FollowingCtrl);\n\n "
},
{
"path": "mobile/www/app/components/follow/following/following.html",
"chars": 424,
"preview": "<ion-view view-title=\"{{ 'tab.following' | translate }}\">\n <ion-content class=\"tatami-header tatami-footer\" ng-style="
},
{
"path": "mobile/www/app/components/follow/following/following.js",
"chars": 1204,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/follow/suggested/suggested.controller.js",
"chars": 645,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('SuggestedCtrl', suggestedCtrl);\n\n "
},
{
"path": "mobile/www/app/components/follow/suggested/suggested.html",
"chars": 428,
"preview": "<ion-view view-title=\"{{ 'tab.suggested.who' | translate }}\">\n <ion-content class=\"tatami-header tatami-footer\" ng-st"
},
{
"path": "mobile/www/app/components/follow/suggested/suggested.js",
"chars": 1144,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/home/favorites/favorites.controller.js",
"chars": 803,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('FavoritesCtrl', favoritesCtrl);\n\n "
},
{
"path": "mobile/www/app/components/home/favorites/favorites.html",
"chars": 376,
"preview": "<ion-view view-title=\"{{ 'tab.favorites' | translate }}\" ng-style=\"{'background-color':'#f5f5f5'}\">\n <tatami-status-l"
},
{
"path": "mobile/www/app/components/home/favorites/favorites.js",
"chars": 1139,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/home/home.html",
"chars": 1112,
"preview": "<ion-tabs class=\"tabs-icon-top tabs-color-active-positive\">\n <!-- Dashboard Tab -->\n <ion-tab title=\"{{ 'tab.timel"
},
{
"path": "mobile/www/app/components/home/home.js",
"chars": 1092,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(homeConfig);\n\n homeConfig.$inject = ['$"
},
{
"path": "mobile/www/app/components/home/mentions/mentions.controller.js",
"chars": 959,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('MentionsCtrl', mentionsCtrl);\n\n me"
},
{
"path": "mobile/www/app/components/home/mentions/mentions.html",
"chars": 381,
"preview": "<ion-view view-title=\"{{ 'tab.mentions' | translate }}\" ng-style=\"{'background-color':'#f5f5f5'}\">\n <tatami-status-li"
},
{
"path": "mobile/www/app/components/home/mentions/mentions.js",
"chars": 1115,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/home/more/all_users/all.users.controller.js",
"chars": 948,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('AllUsersController', allUsersControll"
},
{
"path": "mobile/www/app/components/home/more/all_users/all.users.html",
"chars": 510,
"preview": "<ion-view view-title=\"{{ 'more.allUsers' | translate }}\">\n <ion-content class=\"tatami-header tatami-footer\" ng-style="
},
{
"path": "mobile/www/app/components/home/more/all_users/all.users.js",
"chars": 905,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/home/more/blocked_users/blocked.users.controller.js",
"chars": 1109,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('BlockedUsersController', blockedUsers"
},
{
"path": "mobile/www/app/components/home/more/blocked_users/blocked.users.html",
"chars": 639,
"preview": "<ion-view view-title=\"{{ 'more.blockedUsers.title' | translate }}\">\n <ion-content ng-style=\"{'background-color':'#f5f"
},
{
"path": "mobile/www/app/components/home/more/blocked_users/blocked.users.js",
"chars": 937,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/home/more/company/company-timeline.html",
"chars": 380,
"preview": "<ion-view view-title=\"{{ 'more.company' | translate }}\" ng-style=\"{'background-color':'#f5f5f5'}\">\n <tatami-status-li"
},
{
"path": "mobile/www/app/components/home/more/company/company.timeline.controller.js",
"chars": 822,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('CompanyTimelineCtrl', companyTimeline"
},
{
"path": "mobile/www/app/components/home/more/company/company.timeline.js",
"chars": 1167,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/home/more/more.controller.js",
"chars": 1154,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('MoreController', moreController);\n\n "
},
{
"path": "mobile/www/app/components/home/more/more.html",
"chars": 1959,
"preview": "<ion-view view-title=\"{{ 'tab.more' | translate }}\">\n <ion-content class=\"tatami-header tatami-footer\" ng-style=\"{'ba"
},
{
"path": "mobile/www/app/components/home/more/more.js",
"chars": 1154,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(moreConfig);\n\n moreConfig.$inject = ['$"
},
{
"path": "mobile/www/app/components/home/more/reportedStatus/reportedStatus.controller.js",
"chars": 3199,
"preview": "/**\n * Created by emilyklein on 7/11/16.\n */\n(function() {\n 'use strict';\n\n angular.module('tatami')\n .cont"
},
{
"path": "mobile/www/app/components/home/more/reportedStatus/reportedStatus.html",
"chars": 1028,
"preview": "<ion-view view-title=\"{{ 'more.reportedStatus.title' | translate }}\">\n <ion-content class=\"tatami-header tatami-foote"
},
{
"path": "mobile/www/app/components/home/more/reportedStatus/reportedStatus.js",
"chars": 1026,
"preview": "/**\n * Created by emilyklein on 7/11/16.\n */\n(function() {\n 'use strict';\n\n angular.module('tatami')\n .conf"
},
{
"path": "mobile/www/app/components/home/more/settings/settings.controller.js",
"chars": 879,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('SettingsController', settingsControll"
},
{
"path": "mobile/www/app/components/home/more/settings/settings.html",
"chars": 515,
"preview": "<ion-view view-title=\"{{ 'more.settings' | translate }}\">\n <ion-content ng-style=\"{'background-color':'#f5f5f5'}\">\n "
},
{
"path": "mobile/www/app/components/home/more/settings/settings.js",
"chars": 903,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/home/timeline/timeline.controller.js",
"chars": 788,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('TimelineCtrl', timelineCtrl);\n\n ti"
},
{
"path": "mobile/www/app/components/home/timeline/timeline.html",
"chars": 380,
"preview": "<ion-view view-title=\"{{ 'tab.timeline' | translate }}\" ng-style=\"{'background-color':'#f5f5f5'}\">\n <tatami-status-li"
},
{
"path": "mobile/www/app/components/home/timeline/timeline.js",
"chars": 1146,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/login/login.controller.js",
"chars": 4601,
"preview": "(function () {\n 'use strict';\n\n angular.module('tatami')\n .controller('LoginCtrl', loginCtrl);\n\n loginCt"
},
{
"path": "mobile/www/app/components/login/login.html",
"chars": 2467,
"preview": "<ion-view name=\"login-view\" view-title=\"{{ 'login.title' | translate }}\" hide-back-button=\"true\">\n <ion-content class"
},
{
"path": "mobile/www/app/components/login/login.js",
"chars": 844,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/login/server/server.controller.js",
"chars": 1984,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('ServerController', serverController);"
},
{
"path": "mobile/www/app/components/login/server/server.html",
"chars": 1568,
"preview": "<ion-view view-title=\"\">\n <ion-content ng-style=\"{'background-color':'#f5f5f5'}\">\n <ion-list>\n <ion"
},
{
"path": "mobile/www/app/components/login/server/server.js",
"chars": 976,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(config);\n\n config.$inject = ['$statePro"
},
{
"path": "mobile/www/app/components/post/post.controller.js",
"chars": 6994,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('PostCtrl', postCtrl);\n\n postCtrl.$"
},
{
"path": "mobile/www/app/components/post/post.html",
"chars": 2570,
"preview": "<ion-view view-title=\"{{ 'post.title' | translate }}\" hide-back-button=\"true\">\n <ion-nav-buttons side=\"secondary\">\n "
},
{
"path": "mobile/www/app/components/post/post.js",
"chars": 1167,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(postConfig);\n\n postConfig.$inject = ['$"
},
{
"path": "mobile/www/app/components/post/postbar.directive.js",
"chars": 2062,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .directive('tatamiPostBarAttach', tatamiPostBar);\n"
},
{
"path": "mobile/www/app/shared/config/marked.config.js",
"chars": 2997,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .config(markedConfig);\n\n markedConfig.$inject ="
},
{
"path": "mobile/www/app/shared/config/marked.filter.js",
"chars": 274,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .filter('markdown', markdown);\n\n markdown.$inje"
},
{
"path": "mobile/www/app/shared/config/tatami.marked.js",
"chars": 32688,
"preview": "/**\n * marked - a markdown parser\n * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)\n * https://github.com/"
},
{
"path": "mobile/www/app/shared/interceptor/auth.interceptor.js",
"chars": 2735,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .factory('authInterceptor', authInterceptor)\n "
},
{
"path": "mobile/www/app/shared/providers/provider.js",
"chars": 84,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.providers', []);\n\n})();\n"
},
{
"path": "mobile/www/app/shared/providers/tatami.state.provider.js",
"chars": 6921,
"preview": "(function() {\n 'use strict';\n\n // This will dynamically create any tab substates inside the current tab. If in the"
},
{
"path": "mobile/www/app/shared/services/HomeService.js",
"chars": 1627,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('HomeService', homeService);\n\n "
},
{
"path": "mobile/www/app/shared/services/ProfileService.js",
"chars": 955,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('ProfileService', profileService"
},
{
"path": "mobile/www/app/shared/services/StatusService.js",
"chars": 4368,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('StatusService', statusService);"
},
{
"path": "mobile/www/app/shared/services/UserService.js",
"chars": 2968,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('UserService', userService);\n\n "
},
{
"path": "mobile/www/app/shared/services/account.service.js",
"chars": 319,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('AccountService', accountService"
},
{
"path": "mobile/www/app/shared/services/block.service.js",
"chars": 1310,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('BlockService', blockService);\n\n"
},
{
"path": "mobile/www/app/shared/services/localStorage.service.js",
"chars": 1128,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('$localStorage', localStorage);\n"
},
{
"path": "mobile/www/app/shared/services/path.service.js",
"chars": 830,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('PathService', avatarService);\n\n"
},
{
"path": "mobile/www/app/shared/services/report.service.js",
"chars": 1329,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('ReportService', reportService);"
},
{
"path": "mobile/www/app/shared/services/service.js",
"chars": 83,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services', []);\n\n})();\n"
},
{
"path": "mobile/www/app/shared/services/tag.service.js",
"chars": 1649,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('TagService', tagService);\n\n "
},
{
"path": "mobile/www/app/shared/services/toast.service.js",
"chars": 716,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('ToastService', ToastService);\n\n"
},
{
"path": "mobile/www/app/shared/state/conversation/conversation.controller.js",
"chars": 1177,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('ConversationCtrl', conversationCtrl);"
},
{
"path": "mobile/www/app/shared/state/conversation/conversation.html",
"chars": 210,
"preview": "<ion-view view-title=\"{{ 'conversation.title' | translate }}\">\n <tatami-status-list statuses=\"vm.conversation\"\n "
},
{
"path": "mobile/www/app/shared/state/profile/profile.controller.js",
"chars": 3479,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('ProfileCtrl', profileCtrl);\n\n prof"
},
{
"path": "mobile/www/app/shared/state/profile/profile.html",
"chars": 1066,
"preview": "<ion-view view-title=\"@{{ vm.user.username }}\">\n <ion-nav-buttons side=\"secondary\">\n <button class=\"button ion"
},
{
"path": "mobile/www/app/shared/state/profile/userOptionsMenu.html",
"chars": 983,
"preview": "<ion-popover-view ng-style=\"vm.customHeight\" scroll=\"false\">\n <ion-content>\n <div class=\"list\" ng-click=\"popov"
},
{
"path": "mobile/www/app/shared/state/tag/tag.controller.js",
"chars": 801,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('TagCtrl', tagCtrl);\n\n tagCtrl.$inj"
},
{
"path": "mobile/www/app/shared/state/tag/tag.html",
"chars": 319,
"preview": "<ion-view view-title=\"#{{ vm.tag }}\">\n <tatami-status-list statuses=\"vm.statuses\"\n current-use"
},
{
"path": "mobile/www/app/shared/status/blockUserMenu.html",
"chars": 1370,
"preview": "<ion-popover-view ng-style=\"vm.customHeight\">\n <ion-content>\n <div class=\"list\" ng-click=\"popover.hide()\">\n "
},
{
"path": "mobile/www/app/shared/status/list/status-list.html",
"chars": 710,
"preview": "<ion-content class=\"tatami-header tatami-footer\">\n <ion-refresher ng-if=\"!vm.$state.includes('*.conversation')\" on-re"
},
{
"path": "mobile/www/app/shared/status/list/status.list.directive.js",
"chars": 1985,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .directive('tatamiStatusList', tatamiStatusList);\n"
},
{
"path": "mobile/www/app/shared/status/status.directive.js",
"chars": 6592,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .directive('tatamiStatus', tatamiStatus);\n\n fun"
},
{
"path": "mobile/www/app/shared/status/status.html",
"chars": 3913,
"preview": "<span>\n <div class=\"item-avatar item-text-wrap tatami-avatar\">\n <img ng-src=\"{{ vm.status.avatarURL }}\"/>\n "
},
{
"path": "mobile/www/app/shared/status/status.refresher.service.js",
"chars": 3197,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .factory('TatamiStatusRefresherService', tatamiSta"
},
{
"path": "mobile/www/app/shared/user/user-detail.html",
"chars": 383,
"preview": "<ion-item>\n <div class=\"row\">\n <div class=\"col\">\n <img ng-src=\"{{ vm.user.avatarURL }}\" class=\"cent"
},
{
"path": "mobile/www/app/shared/user/user.detail.directive.js",
"chars": 580,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .directive('tatamiUserDetail', tatamiUserDetail);\n"
},
{
"path": "mobile/www/app/shared/user/user.directive.js",
"chars": 3285,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .directive('tatamiUser', tatamiUser);\n\n tatamiU"
},
{
"path": "mobile/www/app/shared/user/user.html",
"chars": 1656,
"preview": "<ion-item class=\"item-remove-animate item-avatar item-icon-right\" ng-click=\"vm.goToProfile(vm.user.username)\">\n <img "
},
{
"path": "mobile/www/app/shared/user/user.refresher.service.js",
"chars": 1744,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami.services')\n .factory('TatamiUserRefresherService', ta"
},
{
"path": "mobile/www/app/shared/user/users.directive.js",
"chars": 922,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .directive('tatamiUser', tatamiUser);\n\n tatamiU"
},
{
"path": "mobile/www/app/shared/user/users.html",
"chars": 716,
"preview": "<ion-item class=\"item-remove-animate item-avatar item-icon-right\" ui-sref=\"profile({ username: vm.user.username })\">\n "
},
{
"path": "mobile/www/app/tatami.controller.js",
"chars": 244,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami')\n .controller('TatamiCtrl', tatamiCtrl);\n\n tatami"
},
{
"path": "mobile/www/app/tatami.endpoint.js",
"chars": 1172,
"preview": "(function() {\n 'use strict';\n var defaultEndpoint = {url: 'http://tatami.ippon.fr'};\n var endpoint;\n\n angula"
},
{
"path": "mobile/www/app/tatami.html",
"chars": 1017,
"preview": "<ion-header-bar align-title=\"center\" class=\"bar-header bar-dark\">\n <div class=\"buttons\" ng-if=\"!vm.$state.includes('l"
},
{
"path": "mobile/www/app/tatamiApp.js",
"chars": 6116,
"preview": "(function() {\n 'use strict';\n\n angular.module('tatami', [\n 'ionic',\n 'tatami.services',\n 'tat"
},
{
"path": "mobile/www/css/ionic.app.css",
"chars": 243731,
"preview": "@charset \"UTF-8\";\n/*\nTo customize the look and feel of Ionic, you can override the variables\nin ionic's _variables.scss "
},
{
"path": "mobile/www/css/style.css",
"chars": 1081,
"preview": "/* General classes */\n.pull-right {\n float:right;\n}\n.clearfix {\n clear:both;\n}\n.subheading, .date {\n font-size:"
},
{
"path": "mobile/www/i18n/en/conversation.json",
"chars": 64,
"preview": "{\n \"conversation\": {\n \"title\": \"Conversation\"\n }\n}\n"
},
{
"path": "mobile/www/i18n/en/follow.json",
"chars": 192,
"preview": "{\n \"tab\": {\n \"follower\": \"Followers\",\n \"following\": \"Following\",\n \"suggested\": {\n \"ti"
},
{
"path": "mobile/www/i18n/en/home.json",
"chars": 183,
"preview": "{\n \"tab\": {\n \"timeline\": \"Timeline\",\n \"mentions\": \"Mentions\",\n \"favorites\": \"Favorites\",\n "
},
{
"path": "mobile/www/i18n/en/login.json",
"chars": 499,
"preview": "{\n \"login\": {\n \"title\": \"Login\",\n \"email\": \"E-mail\",\n \"password\": \"Password\",\n \"google\": "
},
{
"path": "mobile/www/i18n/en/more.json",
"chars": 586,
"preview": "{\n \"more\": {\n \"title\": \"More Options\",\n \"company\": \"Company Timeline\",\n \"settings\": \"Settings\",\n"
},
{
"path": "mobile/www/i18n/en/post.json",
"chars": 680,
"preview": "{\n \"post\": {\n \"title\": \"Post\",\n \"message\": \"Post Here...\",\n \"progress\": \"Post in progress...\",\n "
},
{
"path": "mobile/www/i18n/en/server.json",
"chars": 646,
"preview": "{\n \"server\": {\n \"success\": \"Logged In!\",\n \"failed\": \"Failed to log in!\",\n \"progress\": \"Login in "
},
{
"path": "mobile/www/i18n/en/status.json",
"chars": 1726,
"preview": "{\n \"status\": {\n \"share\": {\n \"title\": \"shared\",\n \"mention\": \"Your status has been shared\""
},
{
"path": "mobile/www/i18n/en/user.json",
"chars": 1005,
"preview": "{\n \"user\": {\n \"profile\": {\n \"title\": \"Profile\",\n \"options\": {\n \"block\": \""
},
{
"path": "mobile/www/i18n/fr/conversation.json",
"chars": 64,
"preview": "{\n \"conversation\": {\n \"title\": \"Conversation\"\n }\n}\n"
},
{
"path": "mobile/www/i18n/fr/follow.json",
"chars": 189,
"preview": "{\n \"tab\": {\n \"follower\": \"Abonnés\",\n \"following\": \"Abonnement\",\n \"suggested\": {\n \"tit"
},
{
"path": "mobile/www/i18n/fr/home.json",
"chars": 199,
"preview": "{\n \"tab\": {\n \"timeline\": \"Timeline\",\n \"mentions\": \"Mentions\",\n \"favorites\": \"Favoris\",\n \""
},
{
"path": "mobile/www/i18n/fr/login.json",
"chars": 536,
"preview": "{\n \"login\": {\n \"title\": \"Login\",\n \"email\": \"E-mail\",\n \"password\": \"Mot de passe\",\n \"googl"
},
{
"path": "mobile/www/i18n/fr/more.json",
"chars": 628,
"preview": "{\n \"more\": {\n \"title\": \"Plus d'options\",\n \"company\": \"Timeline de l'entreprise\",\n \"settings\": \"P"
},
{
"path": "mobile/www/i18n/fr/post.json",
"chars": 724,
"preview": "{\n \"post\": {\n \"title\": \"Post\",\n \"message\": \"Ecrivez votre message ici...\",\n \"progress\": \"Publica"
},
{
"path": "mobile/www/i18n/fr/server.json",
"chars": 691,
"preview": "{\n \"server\": {\n \"success\": \"Connexion effectuée !\",\n \"failed\": \"Echec de connexion\",\n \"progress\""
},
{
"path": "mobile/www/i18n/fr/status.json",
"chars": 1725,
"preview": "{\n \"status\": {\n \"share\": {\n \"title\": \"a partagé\",\n \"mention\": \"Votre statut a été partag"
},
{
"path": "mobile/www/i18n/fr/user.json",
"chars": 1077,
"preview": "{\n \"user\": {\n \"profile\": {\n \"title\": \"Profil\",\n \"options\": {\n \"block\": \"B"
},
{
"path": "mobile/www/index.html",
"chars": 6398,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"initial-scale=1,"
},
{
"path": "mobile/www/test/javascript/components/profile/profile.controller.spec.js",
"chars": 220,
"preview": "describe(\"License controller test\", function() {\n\n beforeEach(inject(function(_$controller_) {\n $controller = "
},
{
"path": "pom.xml",
"chars": 51279,
"preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xsi:schemaL"
},
{
"path": "scripts/insertBuildVersion.sh",
"chars": 573,
"preview": "#!/bin/bash\n\ndarwin=false;\n\ncase \"`uname`\" in\n Darwin*) darwin=true ;;\nesac\n\nif $darwin; then\n sedi=\"sed -i .sed.d"
},
{
"path": "services/pom.xml",
"chars": 1837,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n xmlns:xsi=\"http://www"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/ApplicationConfiguration.java",
"chars": 2303,
"preview": "package fr.ippon.tatami.config;\n\nimport org.apache.thrift.transport.TTransportException;\nimport org.slf4j.Logger;\nimport"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/AsyncConfiguration.java",
"chars": 1346,
"preview": "package fr.ippon.tatami.config;\n\nimport fr.ippon.tatami.service.SearchService;\nimport fr.ippon.tatami.service.elasticsea"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/CacheConfiguration.java",
"chars": 3195,
"preview": "package fr.ippon.tatami.config;\n\nimport com.yammer.metrics.ehcache.InstrumentedEhcache;\nimport net.sf.ehcache.Cache;\nimp"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/CassandraConfiguration.java",
"chars": 9296,
"preview": "package fr.ippon.tatami.config;\n\nimport me.prettyprint.cassandra.connection.HOpTimer;\nimport me.prettyprint.cassandra.co"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/ColumnFamilyKeys.java",
"chars": 2854,
"preview": "package fr.ippon.tatami.config;\n\n/**\n * @author Julien Dubois\n */\npublic class ColumnFamilyKeys {\n\n private ColumnFam"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/Constants.java",
"chars": 851,
"preview": "package fr.ippon.tatami.config;\n\n/**\n * Application constants.\n */\npublic class Constants {\n\n private Constants() {\n "
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/DispatcherServletConfig.java",
"chars": 6875,
"preview": "package fr.ippon.tatami.config;\r\n\r\nimport fr.ippon.tatami.web.syndic.SyndicView;\r\nimport org.apache.commons.lang.CharEnc"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/GroupRoles.java",
"chars": 234,
"preview": "package fr.ippon.tatami.config;\n\n/**\n * Constants for groupe roles.\n */\npublic class GroupRoles {\n\n private GroupRole"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/MailConfiguration.java",
"chars": 2333,
"preview": "package fr.ippon.tatami.config;\n\nimport org.apache.commons.lang.CharEncoding;\nimport org.apache.velocity.app.VelocityEng"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/MetricsConfiguration.java",
"chars": 1832,
"preview": "package fr.ippon.tatami.config;\n\nimport com.yammer.metrics.HealthChecks;\nimport com.yammer.metrics.reporting.GraphiteRep"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/SearchConfiguration.java",
"chars": 1577,
"preview": "package fr.ippon.tatami.config;\n\nimport fr.ippon.tatami.service.elasticsearch.ElasticsearchEngine;\nimport fr.ippon.tatam"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/metrics/CassandraHealthCheck.java",
"chars": 1281,
"preview": "package fr.ippon.tatami.config.metrics;\n\nimport com.yammer.metrics.core.HealthCheck;\nimport me.prettyprint.cassandra.ser"
},
{
"path": "services/src/main/java/fr/ippon/tatami/config/metrics/JavaMailHealthCheck.java",
"chars": 655,
"preview": "package fr.ippon.tatami.config.metrics;\n\nimport com.yammer.metrics.core.HealthCheck;\nimport fr.ippon.tatami.service.Mail"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/Attachment.java",
"chars": 3118,
"preview": "package fr.ippon.tatami.domain;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport org.joda.time.DateTime;\nimpo"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/Avatar.java",
"chars": 1499,
"preview": "package fr.ippon.tatami.domain;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\n\nimport java.io.Serializable;\nimpor"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/DigestType.java",
"chars": 398,
"preview": "package fr.ippon.tatami.domain;\n\n/**\n * @author Pierre Rust\n */\npublic enum DigestType {\n\n WEEKLY_DIGEST(\"WEEKLY\"),\n "
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/Domain.java",
"chars": 1251,
"preview": "package fr.ippon.tatami.domain;\n\nimport java.io.Serializable;\n\n/**\n * A domain is a domain name (e.g. \"ippon.fr\"), and r"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/DomainConfiguration.java",
"chars": 4220,
"preview": "package fr.ippon.tatami.domain;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Serializable;\nim"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/Group.java",
"chars": 3393,
"preview": "package fr.ippon.tatami.domain;\n\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\n\nimport java.io.Serializable;\n\n/**"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/User.java",
"chars": 7241,
"preview": "package fr.ippon.tatami.domain;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport fr.ippon.tatami.domain.valid"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/UserStatusStat.java",
"chars": 1370,
"preview": "package fr.ippon.tatami.domain;\n\nimport java.io.Serializable;\n\npublic class UserStatusStat implements Comparable<UserSta"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/status/AbstractStatus.java",
"chars": 2704,
"preview": "package fr.ippon.tatami.domain.status;\n\nimport javax.validation.constraints.NotNull;\nimport java.io.Serializable;\nimport"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/status/Announcement.java",
"chars": 113,
"preview": "package fr.ippon.tatami.domain.status;\n\n/**\n * An announcement.\n */\npublic class Announcement extends Share {\n\n}\n"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/status/MentionFriend.java",
"chars": 561,
"preview": "package fr.ippon.tatami.domain.status;\n\n/**\n * Mention a user that someone started following him.\n */\npublic class Menti"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/status/MentionShare.java",
"chars": 148,
"preview": "package fr.ippon.tatami.domain.status;\n\n/**\n * Mention a user that one of his statuses was shared.\n */\npublic class Ment"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/status/Share.java",
"chars": 546,
"preview": "package fr.ippon.tatami.domain.status;\n\n/**\n * A status that is shared.\n */\npublic class Share extends AbstractStatus {\n"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/status/Status.java",
"chars": 3469,
"preview": "package fr.ippon.tatami.domain.status;\n\nimport fr.ippon.tatami.domain.Attachment;\nimport org.hibernate.validator.constra"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/status/StatusDetails.java",
"chars": 1389,
"preview": "package fr.ippon.tatami.domain.status;\n\nimport fr.ippon.tatami.domain.User;\nimport fr.ippon.tatami.service.dto.StatusDTO"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/status/StatusType.java",
"chars": 146,
"preview": "package fr.ippon.tatami.domain.status;\n\npublic enum StatusType {\n STATUS,\n SHARE,\n ANNOUNCEMENT,\n MENTION_FR"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/validation/ContraintsAttachmentCreation.java",
"chars": 94,
"preview": "package fr.ippon.tatami.domain.validation;\n\npublic interface ContraintsAttachmentCreation {\n\n}"
},
{
"path": "services/src/main/java/fr/ippon/tatami/domain/validation/ContraintsUserCreation.java",
"chars": 190,
"preview": "package fr.ippon.tatami.domain.validation;\n\n/**\n * Bean Validation group used to validate the creation of a user.\n *\n * "
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/AppleDeviceRepository.java",
"chars": 287,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Collection;\n\npublic interface AppleDeviceRepository {\n\n void cr"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/AppleDeviceUserRepository.java",
"chars": 256,
"preview": "package fr.ippon.tatami.repository;\n\npublic interface AppleDeviceUserRepository {\n\n void createAppleDeviceForUser(Str"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/AttachmentRepository.java",
"chars": 643,
"preview": "package fr.ippon.tatami.repository;\n\nimport fr.ippon.tatami.domain.Attachment;\n\npublic interface AttachmentRepository {\n"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/AvatarRepository.java",
"chars": 240,
"preview": "package fr.ippon.tatami.repository;\n\nimport fr.ippon.tatami.domain.Avatar;\n\npublic interface AvatarRepository {\n\n voi"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/BlockRepository.java",
"chars": 541,
"preview": "package fr.ippon.tatami.repository;\n\nimport fr.ippon.tatami.domain.User;\n\nimport java.util.Collection;\n\n/**\n *This repos"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/CounterRepository.java",
"chars": 744,
"preview": "package fr.ippon.tatami.repository;\n\n/**\n * The Counter Repository.\n *\n * @author Julien Dubois\n */\npublic interface Cou"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/DaylineRepository.java",
"chars": 588,
"preview": "package fr.ippon.tatami.repository;\n\nimport fr.ippon.tatami.domain.UserStatusStat;\nimport fr.ippon.tatami.domain.status."
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/DiscussionRepository.java",
"chars": 373,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Collection;\n\n/**\n * The StatusDetails Repository.\n *\n * @author Ju"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/DomainConfigurationRepository.java",
"chars": 366,
"preview": "package fr.ippon.tatami.repository;\n\nimport fr.ippon.tatami.domain.DomainConfiguration;\n\n/**\n * The DomainConfiguraiton "
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/DomainRepository.java",
"chars": 550,
"preview": "package fr.ippon.tatami.repository;\n\nimport fr.ippon.tatami.domain.Domain;\n\nimport java.util.List;\nimport java.util.Set;"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/DomainlineRepository.java",
"chars": 726,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * The Domainline Reposito"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/FavoritelineRepository.java",
"chars": 564,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.List;\n\n/**\n * The Favoriteline Repository.\n *\n * @author Julien Du"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/FollowerRepository.java",
"chars": 353,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Collection;\n\n/**\n * The Follower Repository.\n *\n * @author Julien "
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/FriendRepository.java",
"chars": 326,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.List;\n\n/**\n * The Friend Repository.\n *\n * @author Julien Dubois\n "
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/GroupCounterRepository.java",
"chars": 397,
"preview": "package fr.ippon.tatami.repository;\n\n/**\n * The Group Counter Repository.\n *\n * @author Julien Dubois\n */\npublic interfa"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/GroupDetailsRepository.java",
"chars": 432,
"preview": "package fr.ippon.tatami.repository;\n\nimport fr.ippon.tatami.domain.Group;\n\n/**\n * The Group Details Repository.\n *\n * @a"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/GroupMembersRepository.java",
"chars": 382,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Map;\n\n/**\n * The Group members Repository.\n *\n * @author Julien Du"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/GroupRepository.java",
"chars": 269,
"preview": "package fr.ippon.tatami.repository;\n\nimport fr.ippon.tatami.domain.Group;\n\n/**\n * The Group Repository.\n *\n * @author Ju"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/GrouplineRepository.java",
"chars": 723,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * The Groupline Repositor"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/IdempotentRepository.java",
"chars": 325,
"preview": "package fr.ippon.tatami.repository;\n\n/**\n * Used to de-deplucate Camel messages.\n */\npublic interface IdempotentReposito"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/MailDigestRepository.java",
"chars": 862,
"preview": "package fr.ippon.tatami.repository;\n\nimport fr.ippon.tatami.domain.DigestType;\n\nimport java.util.List;\n\n/**\n * Provide a"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/MentionlineRepository.java",
"chars": 751,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * The Mentionline Reposit"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/RegistrationRepository.java",
"chars": 398,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Map;\n\n/**\n * The Registration Repository.\n *\n * @author Julien Dub"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/ResolvedReportRepository.java",
"chars": 407,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Collection;\n\n/**\n * Created by emilyklein on 7/13/16.\n */\npublic i"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/RssUidRepository.java",
"chars": 388,
"preview": "package fr.ippon.tatami.repository;\r\n\r\n/**\r\n * The Rss Uid Repository.\r\n * </p>\r\n * The RSS uid is used to build an anon"
},
{
"path": "services/src/main/java/fr/ippon/tatami/repository/SharesRepository.java",
"chars": 354,
"preview": "package fr.ippon.tatami.repository;\n\nimport java.util.Collection;\n\n/**\n * The StatusDetails Repository.\n *\n * @author Ju"
}
]
// ... and 1721 more files (download for full content)
About this extraction
This page contains the full source code of the ippontech/tatami GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1921 files (12.9 MB), approximately 3.5M tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.