New upstream version 21.0~r2296+dfsg
Andreas Moog
5 years ago
0 | # Configuration file for integration with http://lgtm.com | |
1 | ||
2 | path_classifiers: | |
3 | library: | |
4 | # exclude these directories from default alerts report: | |
5 | - lib | |
6 | - webui/lib | |
7 | ||
8 | extraction: | |
9 | cpp: | |
10 | configure: | |
11 | command: | |
12 | # compile with tests to activate scanning of C++ sources for tests | |
13 | - ./configure --enable-tests | |
14 | ||
15 | queries: | |
16 | - exclude: js/incomplete-sanitization # this one gives false positives only and nothing useful |
0 | 0 | # |
1 | 1 | # This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | # |
3 | # Copyright (C) 2008-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | # Copyright (C) 2008-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | # |
5 | 5 | # This program is free software; you can redistribute it and/or modify |
6 | 6 | # it under the terms of the GNU General Public License as published by |
67 | 67 | daemon/main/nzbget.h \ |
68 | 68 | daemon/main/Options.cpp \ |
69 | 69 | daemon/main/Options.h \ |
70 | daemon/main/WorkState.cpp \ | |
71 | daemon/main/WorkState.h \ | |
70 | 72 | daemon/main/Scheduler.cpp \ |
71 | 73 | daemon/main/Scheduler.h \ |
72 | 74 | daemon/main/StackTrace.cpp \ |
16 | 16 | # |
17 | 17 | # This file is part of nzbget. See <http://nzbget.net>. |
18 | 18 | # |
19 | # Copyright (C) 2008-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
19 | # Copyright (C) 2008-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
20 | 20 | # |
21 | 21 | # This program is free software; you can redistribute it and/or modify |
22 | 22 | # it under the terms of the GNU General Public License as published by |
231 | 231 | daemon/main/DiskService.h daemon/main/Maintenance.cpp \ |
232 | 232 | daemon/main/Maintenance.h daemon/main/nzbget.cpp \ |
233 | 233 | daemon/main/nzbget.h daemon/main/Options.cpp \ |
234 | daemon/main/Options.h daemon/main/Scheduler.cpp \ | |
234 | daemon/main/Options.h daemon/main/WorkState.cpp \ | |
235 | daemon/main/WorkState.h daemon/main/Scheduler.cpp \ | |
235 | 236 | daemon/main/Scheduler.h daemon/main/StackTrace.cpp \ |
236 | 237 | daemon/main/StackTrace.h daemon/nntp/ArticleDownloader.cpp \ |
237 | 238 | daemon/nntp/ArticleDownloader.h daemon/nntp/ArticleWriter.cpp \ |
386 | 387 | daemon/main/CommandLineParser.$(OBJEXT) \ |
387 | 388 | daemon/main/DiskService.$(OBJEXT) \ |
388 | 389 | daemon/main/Maintenance.$(OBJEXT) daemon/main/nzbget.$(OBJEXT) \ |
389 | daemon/main/Options.$(OBJEXT) daemon/main/Scheduler.$(OBJEXT) \ | |
390 | daemon/main/Options.$(OBJEXT) daemon/main/WorkState.$(OBJEXT) \ | |
391 | daemon/main/Scheduler.$(OBJEXT) \ | |
390 | 392 | daemon/main/StackTrace.$(OBJEXT) \ |
391 | 393 | daemon/nntp/ArticleDownloader.$(OBJEXT) \ |
392 | 394 | daemon/nntp/ArticleWriter.$(OBJEXT) \ |
719 | 721 | daemon/main/DiskService.h daemon/main/Maintenance.cpp \ |
720 | 722 | daemon/main/Maintenance.h daemon/main/nzbget.cpp \ |
721 | 723 | daemon/main/nzbget.h daemon/main/Options.cpp \ |
722 | daemon/main/Options.h daemon/main/Scheduler.cpp \ | |
724 | daemon/main/Options.h daemon/main/WorkState.cpp \ | |
725 | daemon/main/WorkState.h daemon/main/Scheduler.cpp \ | |
723 | 726 | daemon/main/Scheduler.h daemon/main/StackTrace.cpp \ |
724 | 727 | daemon/main/StackTrace.h daemon/nntp/ArticleDownloader.cpp \ |
725 | 728 | daemon/nntp/ArticleDownloader.h daemon/nntp/ArticleWriter.cpp \ |
1156 | 1159 | daemon/main/nzbget.$(OBJEXT): daemon/main/$(am__dirstamp) \ |
1157 | 1160 | daemon/main/$(DEPDIR)/$(am__dirstamp) |
1158 | 1161 | daemon/main/Options.$(OBJEXT): daemon/main/$(am__dirstamp) \ |
1162 | daemon/main/$(DEPDIR)/$(am__dirstamp) | |
1163 | daemon/main/WorkState.$(OBJEXT): daemon/main/$(am__dirstamp) \ | |
1159 | 1164 | daemon/main/$(DEPDIR)/$(am__dirstamp) |
1160 | 1165 | daemon/main/Scheduler.$(OBJEXT): daemon/main/$(am__dirstamp) \ |
1161 | 1166 | daemon/main/$(DEPDIR)/$(am__dirstamp) |
1552 | 1557 | @AMDEP_TRUE@@am__include@ @am__quote@daemon/main/$(DEPDIR)/Options.Po@am__quote@ |
1553 | 1558 | @AMDEP_TRUE@@am__include@ @am__quote@daemon/main/$(DEPDIR)/Scheduler.Po@am__quote@ |
1554 | 1559 | @AMDEP_TRUE@@am__include@ @am__quote@daemon/main/$(DEPDIR)/StackTrace.Po@am__quote@ |
1560 | @AMDEP_TRUE@@am__include@ @am__quote@daemon/main/$(DEPDIR)/WorkState.Po@am__quote@ | |
1555 | 1561 | @AMDEP_TRUE@@am__include@ @am__quote@daemon/main/$(DEPDIR)/nzbget.Po@am__quote@ |
1556 | 1562 | @AMDEP_TRUE@@am__include@ @am__quote@daemon/nntp/$(DEPDIR)/ArticleDownloader.Po@am__quote@ |
1557 | 1563 | @AMDEP_TRUE@@am__include@ @am__quote@daemon/nntp/$(DEPDIR)/ArticleWriter.Po@am__quote@ |
0 | 0 | # NZBGet # |
1 | 1 | [![License](https://img.shields.io/badge/license-GPL-blue.svg)](http://www.gnu.org/licenses/) |
2 | 2 | [![Build Status](https://img.shields.io/travis/nzbget/nzbget/develop.svg)](https://travis-ci.org/nzbget/nzbget) |
3 | [![Code Quality: Cpp](https://img.shields.io/lgtm/grade/cpp/g/nzbget/nzbget.svg?label=code%20quality:%20c%2b%2b)](https://lgtm.com/projects/g/nzbget/nzbget/context:cpp) | |
4 | [![Code Quality: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/nzbget/nzbget.svg?label=code%20quality:%20js)](https://lgtm.com/projects/g/nzbget/nzbget/context:javascript) | |
5 | [![Total Alerts](https://img.shields.io/lgtm/alerts/g/nzbget/nzbget.svg)](https://lgtm.com/projects/g/nzbget/nzbget/alerts) | |
6 | ||
7 | [![Total downloads](https://img.shields.io/github/downloads/nzbget/nzbget/total.svg)](https://github.com/nzbget/nzbget/releases) | |
8 | [![Downloads (latest release)](https://img.shields.io/github/downloads/nzbget/nzbget/latest/total.svg?label=latest%20release)](https://github.com/nzbget/nzbget/releases/latest) | |
3 | 9 | |
4 | 10 | NZBGet is a binary downloader, which downloads files from Usenet |
5 | 11 | based on information given in nzb-files. |
6 | 12 | |
7 | 13 | NZBGet is written in C++ and is known for its extraordinary performance and efficiency. |
8 | 14 | |
9 | NZBGet can be run at almost every platform - classic PCs, NAS, media players, SAT-receivers, WLAN-routers, etc. | |
15 | NZBGet can be run on almost every device - classic PCs, NAS, media players, SAT-receivers, WLAN-routers, etc. | |
10 | 16 | The download area provides precompiled binaries |
11 | for Windows, Mac OS X and Linux (compatible with many CPUs and platform variants). For other platforms | |
17 | for Windows, macOS, Linux (compatible with many CPUs and platform variants), FreeBSD and Android. For other platforms | |
12 | 18 | the program can be compiled from sources. |
13 | 19 | |
14 | - [Home page (nzbget.net)](http://nzbget.net) - for first time visitors, learn more about NZBGet; | |
15 | - [Downloads](http://nzbget.net/download) - get the binaries and sources; | |
20 | - [Home page (nzbget.net)](http://nzbget.net) - learn more about NZBGet; | |
21 | - [Downloads](http://nzbget.net/download) - get compiled binaries and sources; | |
16 | 22 | - [Documentation](http://nzbget.net/documentation) - installation manuals, HOW-TOs, API; |
17 | 23 | - [Forum](http://forum.nzbget.net) - get support, share your ideas, scripts, add-ons. |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
144 | 144 | { |
145 | 145 | debug("Destroying Connection"); |
146 | 146 | |
147 | Disconnect(); | |
147 | Connection::Disconnect(); | |
148 | 148 | } |
149 | 149 | |
150 | 150 | void Connection::SetSuppressErrors(bool suppressErrors) |
194 | 194 | CRYPTO_set_locking_callback(nullptr); |
195 | 195 | CRYPTO_set_id_callback(nullptr); |
196 | 196 | #endif |
197 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | |
197 | 198 | ERR_remove_state(0); |
199 | #endif | |
198 | 200 | #if OPENSSL_VERSION_NUMBER >= 0x10002000L && ! defined (LIBRESSL_VERSION_NUMBER) |
199 | 201 | SSL_COMP_free_compression_methods(); |
200 | 202 | #endif |
201 | 203 | //ENGINE_cleanup(); |
202 | 204 | CONF_modules_free(); |
203 | 205 | CONF_modules_unload(1); |
206 | #ifndef OPENSSL_NO_COMP | |
204 | 207 | COMP_zlib_cleanup(); |
208 | #endif | |
205 | 209 | ERR_free_strings(); |
206 | 210 | EVP_cleanup(); |
207 | 211 | CRYPTO_cleanup_all_ex_data(); |
213 | 217 | Close(); |
214 | 218 | |
215 | 219 | #ifdef HAVE_OPENSSL |
220 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | |
216 | 221 | ERR_remove_state(0); |
222 | #endif | |
217 | 223 | #endif |
218 | 224 | } |
219 | 225 | |
558 | 564 | // hostname verification |
559 | 565 | if (!m_host.Empty() && X509_check_host(cert, m_host, m_host.Length(), 0, nullptr) != 1) |
560 | 566 | { |
561 | char* certHost = nullptr; | |
567 | const unsigned char* certHost = nullptr; | |
562 | 568 | // Find the position of the CN field in the Subject field of the certificate |
563 | 569 | int common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name(cert), NID_commonName, -1); |
564 | 570 | if (common_name_loc >= 0) |
571 | 577 | ASN1_STRING* common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry); |
572 | 578 | if (common_name_asn1 != nullptr) |
573 | 579 | { |
574 | certHost = (char*)ASN1_STRING_data(common_name_asn1); | |
580 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L | |
581 | certHost = ASN1_STRING_get0_data(common_name_asn1); | |
582 | #else | |
583 | certHost = ASN1_STRING_data(common_name_asn1); | |
584 | #endif | |
575 | 585 | } |
576 | 586 | } |
577 | 587 | } |
44 | 44 | virtual void PrintError(const char* errMsg); |
45 | 45 | |
46 | 46 | private: |
47 | SOCKET m_socket; | |
47 | 48 | bool m_isClient; |
48 | 49 | CString m_host; |
49 | 50 | CString m_certFile; |
50 | 51 | CString m_keyFile; |
51 | 52 | CString m_cipher; |
52 | SOCKET m_socket; | |
53 | 53 | bool m_suppressErrors = false; |
54 | 54 | bool m_initialized = false; |
55 | 55 | bool m_connected = false; |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
21 | 21 | #include "WebDownloader.h" |
22 | 22 | #include "Log.h" |
23 | 23 | #include "Options.h" |
24 | #include "WorkState.h" | |
24 | 25 | #include "Util.h" |
25 | 26 | #include "FileSystem.h" |
26 | 27 | |
71 | 72 | |
72 | 73 | if ((((Status == adFailed) && (remainedDownloadRetries > 1)) || |
73 | 74 | ((Status == adConnectError) && (remainedConnectRetries > 1))) |
74 | && !IsStopped() && !(!m_force && g_Options->GetPauseDownload())) | |
75 | && !IsStopped() && !(!m_force && g_WorkState->GetPauseDownload())) | |
75 | 76 | { |
76 | 77 | detail("Waiting %i sec to retry", g_Options->GetUrlInterval()); |
77 | 78 | int msec = 0; |
78 | 79 | while (!IsStopped() && (msec < g_Options->GetUrlInterval() * 1000) && |
79 | !(!m_force && g_Options->GetPauseDownload())) | |
80 | { | |
81 | usleep(100 * 1000); | |
80 | !(!m_force && g_WorkState->GetPauseDownload())) | |
81 | { | |
82 | Util::Sleep(100); | |
82 | 83 | msec += 100; |
83 | 84 | } |
84 | 85 | } |
85 | 86 | |
86 | if (IsStopped() || (!m_force && g_Options->GetPauseDownload())) | |
87 | if (IsStopped() || (!m_force && g_WorkState->GetPauseDownload())) | |
87 | 88 | { |
88 | 89 | Status = adRetry; |
89 | 90 | break; |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
22 | 22 | #include "Log.h" |
23 | 23 | #include "Util.h" |
24 | 24 | #include "Options.h" |
25 | #include "WorkState.h" | |
25 | 26 | |
26 | 27 | static const int POSTPROCESS_PARCHECK = 92; |
27 | 28 | static const int POSTPROCESS_SUCCESS = 93; |
271 | 272 | m_postInfo->SetProgressLabel(text); |
272 | 273 | } |
273 | 274 | |
274 | if (g_Options->GetPausePostProcess() && !m_postInfo->GetNzbInfo()->GetForcePriority()) | |
275 | if (g_WorkState->GetPausePostProcess() && !m_postInfo->GetNzbInfo()->GetForcePriority()) | |
275 | 276 | { |
276 | 277 | time_t stageTime = m_postInfo->GetStageTime(); |
277 | 278 | time_t startTime = m_postInfo->GetStartTime(); |
278 | 279 | time_t waitTime = Util::CurrentTime(); |
279 | 280 | |
280 | 281 | // wait until Post-processor is unpaused |
281 | while (g_Options->GetPausePostProcess() && !m_postInfo->GetNzbInfo()->GetForcePriority() && !IsStopped()) | |
282 | { | |
283 | usleep(100 * 1000); | |
282 | while (g_WorkState->GetPausePostProcess() && !m_postInfo->GetNzbInfo()->GetForcePriority() && !IsStopped()) | |
283 | { | |
284 | Util::Sleep(100); | |
284 | 285 | |
285 | 286 | // update time stamps |
286 | 287 |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2013-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2013-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
20 | 20 | #include "nzbget.h" |
21 | 21 | #include "FeedCoordinator.h" |
22 | 22 | #include "Options.h" |
23 | #include "WorkState.h" | |
23 | 24 | #include "WebDownloader.h" |
24 | 25 | #include "Util.h" |
25 | 26 | #include "FileSystem.h" |
65 | 66 | |
66 | 67 | m_downloadQueueObserver.m_owner = this; |
67 | 68 | DownloadQueue::Guard()->Attach(&m_downloadQueueObserver); |
69 | ||
70 | m_workStateObserver.m_owner = this; | |
71 | g_WorkState->Attach(&m_workStateObserver); | |
68 | 72 | } |
69 | 73 | |
70 | 74 | FeedCoordinator::~FeedCoordinator() |
84 | 88 | |
85 | 89 | while (!DownloadQueue::IsLoaded()) |
86 | 90 | { |
87 | usleep(20 * 1000); | |
91 | Util::Sleep(20); | |
88 | 92 | } |
89 | 93 | |
90 | 94 | if (g_Options->GetServerMode()) |
93 | 97 | g_DiskState->LoadFeeds(&m_feeds, &m_feedHistory); |
94 | 98 | } |
95 | 99 | |
96 | int sleepInterval = 100; | |
97 | int updateCounter = 0; | |
98 | int cleanupCounter = 60000; | |
99 | ||
100 | time_t lastCleanup = 0; | |
100 | 101 | while (!IsStopped()) |
101 | 102 | { |
102 | usleep(sleepInterval * 1000); | |
103 | ||
104 | updateCounter += sleepInterval; | |
105 | if (updateCounter >= 1000) | |
106 | { | |
107 | // this code should not be called too often, once per second is OK | |
108 | ||
109 | if (!g_Options->GetPauseDownload() || m_force || g_Options->GetUrlForce()) | |
110 | { | |
111 | Guard guard(m_downloadsMutex); | |
112 | ||
113 | time_t current = Util::CurrentTime(); | |
114 | if ((int)m_activeDownloads.size() < g_Options->GetUrlConnections()) | |
103 | // this code should not be called too often, once per second is OK | |
104 | if (!g_WorkState->GetPauseDownload() || m_force || g_Options->GetUrlForce()) | |
105 | { | |
106 | Guard guard(m_downloadsMutex); | |
107 | ||
108 | time_t current = Util::CurrentTime(); | |
109 | if ((int)m_activeDownloads.size() < g_Options->GetUrlConnections()) | |
110 | { | |
111 | m_force = false; | |
112 | // check feed list and update feeds | |
113 | for (FeedInfo* feedInfo : &m_feeds) | |
115 | 114 | { |
116 | m_force = false; | |
117 | // check feed list and update feeds | |
118 | for (FeedInfo* feedInfo : &m_feeds) | |
115 | if (((feedInfo->GetInterval() > 0 && | |
116 | (feedInfo->GetNextUpdate() == 0 || | |
117 | current >= feedInfo->GetNextUpdate() || | |
118 | current < feedInfo->GetNextUpdate() - feedInfo->GetInterval() * 60)) || | |
119 | feedInfo->GetFetch()) && | |
120 | feedInfo->GetStatus() != FeedInfo::fsRunning) | |
119 | 121 | { |
120 | if (((feedInfo->GetInterval() > 0 && | |
121 | (feedInfo->GetNextUpdate() == 0 || | |
122 | current >= feedInfo->GetNextUpdate() || | |
123 | current < feedInfo->GetNextUpdate() - feedInfo->GetInterval() * 60)) || | |
124 | feedInfo->GetFetch()) && | |
125 | feedInfo->GetStatus() != FeedInfo::fsRunning) | |
126 | { | |
127 | StartFeedDownload(feedInfo, feedInfo->GetFetch()); | |
128 | } | |
129 | else if (feedInfo->GetFetch()) | |
130 | { | |
131 | m_force = true; | |
132 | } | |
122 | StartFeedDownload(feedInfo, feedInfo->GetFetch()); | |
123 | } | |
124 | else if (feedInfo->GetFetch()) | |
125 | { | |
126 | m_force = true; | |
133 | 127 | } |
134 | 128 | } |
135 | 129 | } |
136 | ||
137 | CheckSaveFeeds(); | |
138 | ResetHangingDownloads(); | |
139 | updateCounter = 0; | |
140 | } | |
141 | ||
142 | cleanupCounter += sleepInterval; | |
143 | if (cleanupCounter >= 60000) | |
130 | } | |
131 | ||
132 | CheckSaveFeeds(); | |
133 | ResetHangingDownloads(); | |
134 | ||
135 | if (std::abs(Util::CurrentTime() - lastCleanup) >= 60) | |
144 | 136 | { |
145 | 137 | // clean up feed history once a minute |
146 | 138 | CleanupHistory(); |
147 | 139 | CleanupCache(); |
148 | 140 | CheckSaveFeeds(); |
149 | cleanupCounter = 0; | |
141 | lastCleanup = Util::CurrentTime(); | |
142 | } | |
143 | ||
144 | Guard guard(m_downloadsMutex); | |
145 | if (m_force) | |
146 | { | |
147 | // don't sleep too long if there active feeds scheduled for redownload | |
148 | m_waitCond.WaitFor(m_downloadsMutex, 1000, [&]{ return IsStopped(); }); | |
149 | } | |
150 | else | |
151 | { | |
152 | // no active jobs, we can sleep longer: | |
153 | // - if option "UrlForce" is active or if the feed list is empty we need to wake up | |
154 | // only when a new feed preview is requested. We could wait indefinitely for that | |
155 | // but we need to do some job every now and then and therefore we sleep only 60 seconds. | |
156 | // - if option "UrlForce" is disabled we need also to wake up when state "DownloadPaused" | |
157 | // is changed. We detect this via notification from 'WorkState'. However such | |
158 | // notifications are not 100% reliable due to possible race conditions. Therefore | |
159 | // we sleep for max. 5 seconds. | |
160 | int waitInterval = g_Options->GetUrlForce() || m_feeds.empty() ? 60000 : 5000; | |
161 | m_waitCond.WaitFor(m_downloadsMutex, waitInterval, [&]{ return m_force || IsStopped(); }); | |
150 | 162 | } |
151 | 163 | } |
152 | 164 | |
160 | 172 | completed = m_activeDownloads.size() == 0; |
161 | 173 | } |
162 | 174 | CheckSaveFeeds(); |
163 | usleep(100 * 1000); | |
175 | Util::Sleep(100); | |
164 | 176 | ResetHangingDownloads(); |
165 | 177 | } |
166 | 178 | debug("FeedCoordinator: Downloads are completed"); |
179 | 191 | feedDownloader->Stop(); |
180 | 192 | } |
181 | 193 | debug("UrlDownloads are notified"); |
194 | ||
195 | // Resume Run() to exit it | |
196 | m_waitCond.NotifyAll(); | |
197 | } | |
198 | ||
199 | void FeedCoordinator::WorkStateUpdate(Subject* caller, void* aspect) | |
200 | { | |
201 | m_force = true; | |
202 | m_waitCond.NotifyAll(); | |
182 | 203 | } |
183 | 204 | |
184 | 205 | void FeedCoordinator::ResetHangingDownloads() |
521 | 542 | } |
522 | 543 | |
523 | 544 | StartFeedDownload(feedInfo.get(), true); |
545 | ||
546 | m_force = true; | |
547 | m_waitCond.NotifyAll(); | |
524 | 548 | } |
525 | 549 | |
526 | 550 | // wait until the download in a separate thread completes |
527 | 551 | while (feedInfo->GetStatus() == FeedInfo::fsRunning) |
528 | 552 | { |
529 | usleep(100 * 1000); | |
553 | Util::Sleep(100); | |
530 | 554 | } |
531 | 555 | |
532 | 556 | // now can process the feed |
585 | 609 | m_force = true; |
586 | 610 | } |
587 | 611 | } |
612 | ||
613 | m_waitCond.NotifyAll(); | |
588 | 614 | } |
589 | 615 | |
590 | 616 | std::unique_ptr<FeedFile> FeedCoordinator::parseFeed(FeedInfo* feedInfo) |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2013-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2013-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
66 | 66 | virtual void Update(Subject* caller, void* aspect) { m_owner->DownloadQueueUpdate(caller, aspect); } |
67 | 67 | }; |
68 | 68 | |
69 | class WorkStateObserver: public Observer | |
70 | { | |
71 | public: | |
72 | FeedCoordinator* m_owner; | |
73 | virtual void Update(Subject* caller, void* aspect) { m_owner->WorkStateUpdate(caller, aspect); } | |
74 | }; | |
75 | ||
69 | 76 | class FeedCacheItem |
70 | 77 | { |
71 | 78 | public: |
105 | 112 | FeedHistory m_feedHistory; |
106 | 113 | Mutex m_downloadsMutex; |
107 | 114 | DownloadQueueObserver m_downloadQueueObserver; |
115 | WorkStateObserver m_workStateObserver; | |
108 | 116 | bool m_force = false; |
109 | 117 | bool m_save = false; |
110 | 118 | FeedCache m_feedCache; |
119 | ConditionVar m_waitCond; | |
120 | bool m_wokenUp = false; | |
111 | 121 | |
112 | 122 | void StartFeedDownload(FeedInfo* feedInfo, bool force); |
113 | 123 | void FeedCompleted(FeedDownloader* feedDownloader); |
121 | 131 | void CheckSaveFeeds(); |
122 | 132 | std::unique_ptr<FeedFile> parseFeed(FeedInfo* feedInfo); |
123 | 133 | void SchedulerNextUpdate(FeedInfo* feedInfo, bool success); |
134 | void WorkStateUpdate(Subject* caller, void* aspect); | |
124 | 135 | }; |
125 | 136 | |
126 | 137 | extern FeedCoordinator* g_FeedCoordinator; |
50 | 50 | |
51 | 51 | if (m_command < fcEqual && !strValue) |
52 | 52 | { |
53 | intBuf.Format("%lld", intValue); | |
53 | intBuf.Format("%" PRId64, intValue); | |
54 | 54 | strValue = intBuf; |
55 | 55 | } |
56 | 56 |
71 | 71 | int m_id; |
72 | 72 | CString m_name; |
73 | 73 | CString m_url; |
74 | bool m_backlog; | |
74 | 75 | int m_interval; |
75 | 76 | CString m_filter; |
76 | 77 | uint32 m_filterHash; |
86 | 87 | CString m_outputFilename; |
87 | 88 | bool m_fetch = false; |
88 | 89 | bool m_force = false; |
89 | bool m_backlog; | |
90 | 90 | }; |
91 | 91 | |
92 | 92 | typedef std::deque<std::unique_ptr<FeedInfo>> Feeds; |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
20 | 20 | |
21 | 21 | #include "nzbget.h" |
22 | 22 | #include "Options.h" |
23 | #include "WorkState.h" | |
23 | 24 | #include "Frontend.h" |
24 | 25 | #include "Log.h" |
25 | 26 | #include "Connection.h" |
32 | 33 | { |
33 | 34 | debug("Creating Frontend"); |
34 | 35 | |
36 | m_workStateObserver.m_owner = this; | |
37 | g_WorkState->Attach(&m_workStateObserver); | |
38 | ||
35 | 39 | m_updateInterval = g_Options->GetUpdateInterval(); |
40 | } | |
41 | ||
42 | void Frontend::Stop() | |
43 | { | |
44 | Thread::Stop(); | |
45 | ||
46 | m_waitCond.NotifyAll(); | |
47 | } | |
48 | ||
49 | void Frontend::WorkStateUpdate(Subject* caller, void* aspect) | |
50 | { | |
51 | m_waitCond.NotifyAll(); | |
36 | 52 | } |
37 | 53 | |
38 | 54 | bool Frontend::PrepareData() |
56 | 72 | if (m_summary) |
57 | 73 | { |
58 | 74 | m_currentDownloadSpeed = g_StatMeter->CalcCurrentDownloadSpeed(); |
59 | m_pauseDownload = g_Options->GetPauseDownload(); | |
60 | m_downloadLimit = g_Options->GetDownloadRate(); | |
75 | m_pauseDownload = g_WorkState->GetPauseDownload(); | |
76 | m_downloadLimit = g_WorkState->GetSpeedLimit(); | |
61 | 77 | m_threadCount = Thread::GetThreadCount(); |
62 | 78 | g_StatMeter->CalcTotalStat(&m_upTimeSec, &m_dnTimeSec, &m_allBytes, &m_standBy); |
63 | 79 | |
107 | 123 | } |
108 | 124 | else |
109 | 125 | { |
110 | g_Options->SetResumeTime(0); | |
111 | g_Options->SetPauseDownload(pause); | |
126 | g_WorkState->SetResumeTime(0); | |
127 | g_WorkState->SetPauseDownload(pause); | |
112 | 128 | } |
113 | 129 | } |
114 | 130 | |
120 | 136 | } |
121 | 137 | else |
122 | 138 | { |
123 | g_Options->SetDownloadRate(rate); | |
139 | g_WorkState->SetSpeedLimit(rate); | |
124 | 140 | } |
125 | 141 | } |
126 | 142 | |
306 | 322 | IdList ids = { id }; |
307 | 323 | return client.RequestServerEditQueue(action, offset, nullptr, &ids, nullptr, rmId); |
308 | 324 | } |
325 | ||
326 | void Frontend::Wait(int milliseconds) | |
327 | { | |
328 | if (g_WorkState->GetPauseFrontend()) | |
329 | { | |
330 | Guard guard(m_waitMutex); | |
331 | m_waitCond.WaitFor(m_waitMutex, 2000); | |
332 | } | |
333 | else | |
334 | { | |
335 | Util::Sleep(milliseconds); | |
336 | } | |
337 | } |
26 | 26 | #include "DownloadInfo.h" |
27 | 27 | #include "MessageBase.h" |
28 | 28 | #include "QueueEditor.h" |
29 | #include "Observer.h" | |
29 | 30 | |
30 | 31 | class Frontend : public Thread |
31 | 32 | { |
50 | 51 | int m_dnTimeSec = 0; |
51 | 52 | int64 m_allBytes = 0; |
52 | 53 | bool m_standBy = false; |
54 | Mutex m_waitMutex; | |
55 | ConditionVar m_waitCond; | |
53 | 56 | |
57 | virtual void Stop(); | |
54 | 58 | bool PrepareData(); |
55 | 59 | void FreeData(); |
56 | 60 | GuardedMessageList GuardMessages(); |
62 | 66 | bool RequestSetDownloadRate(int rate); |
63 | 67 | bool ServerEditQueue(DownloadQueue::EEditAction action, int offset, int entry); |
64 | 68 | bool RequestEditQueue(DownloadQueue::EEditAction action, int offset, int id); |
69 | void Wait(int milliseconds); | |
65 | 70 | |
66 | 71 | private: |
72 | class WorkStateObserver : public Observer | |
73 | { | |
74 | public: | |
75 | Frontend* m_owner; | |
76 | virtual void Update(Subject* caller, void* aspect) { m_owner->WorkStateUpdate(caller, aspect); } | |
77 | }; | |
78 | ||
67 | 79 | MessageList m_remoteMessages; |
80 | WorkStateObserver m_workStateObserver; | |
68 | 81 | |
69 | 82 | bool RequestMessages(); |
70 | 83 | bool RequestFileList(); |
84 | void WorkStateUpdate(Subject* caller, void* aspect); | |
71 | 85 | }; |
72 | 86 | |
73 | 87 | #endif |
19 | 19 | |
20 | 20 | |
21 | 21 | #include "nzbget.h" |
22 | #include "Util.h" | |
22 | 23 | #include "LoggableFrontend.h" |
23 | 24 | #include "Log.h" |
24 | 25 | |
29 | 30 | while (!IsStopped()) |
30 | 31 | { |
31 | 32 | Update(); |
32 | usleep(m_updateInterval * 1000); | |
33 | Wait(m_updateInterval); | |
33 | 34 | } |
34 | 35 | // Printing the last messages |
35 | 36 | Update(); |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
212 | 212 | m_dataUpdatePos = m_updateInterval; |
213 | 213 | } |
214 | 214 | |
215 | usleep(10 * 1000); | |
216 | m_dataUpdatePos -= 10; | |
215 | // update more often (sleep shorter) if need faster reaction on user input | |
216 | int sleepInterval = m_inputMode == normal ? 100 : 10; | |
217 | Wait(sleepInterval); | |
218 | m_dataUpdatePos -= sleepInterval; | |
217 | 219 | } |
218 | 220 | |
219 | 221 | FreeData(); |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
914 | 914 | } |
915 | 915 | |
916 | 916 | int editQueueIdCount = 0; |
917 | if (editQueueIdTo != 0) | |
917 | if (editQueueIdFrom < editQueueIdTo) | |
918 | 918 | { |
919 | if (editQueueIdFrom < editQueueIdTo) | |
920 | { | |
921 | editQueueIdCount = editQueueIdTo - editQueueIdFrom + 1; | |
922 | } | |
923 | else | |
924 | { | |
925 | editQueueIdCount = editQueueIdFrom - editQueueIdTo + 1; | |
926 | } | |
919 | editQueueIdCount = editQueueIdTo - editQueueIdFrom + 1; | |
927 | 920 | } |
928 | 921 | else |
929 | 922 | { |
930 | editQueueIdCount = 1; | |
923 | editQueueIdCount = editQueueIdFrom - editQueueIdTo + 1; | |
931 | 924 | } |
932 | 925 | |
933 | 926 | for (int i = 0; i < editQueueIdCount; i++) |
934 | 927 | { |
935 | if (editQueueIdFrom < editQueueIdTo || editQueueIdTo == 0) | |
928 | if (editQueueIdFrom < editQueueIdTo) | |
936 | 929 | { |
937 | 930 | m_editQueueIdList.push_back(editQueueIdFrom + i); |
938 | 931 | } |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2015-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
20 | 20 | #include "nzbget.h" |
21 | 21 | #include "DiskService.h" |
22 | 22 | #include "Options.h" |
23 | #include "WorkState.h" | |
23 | 24 | #include "StatMeter.h" |
24 | 25 | #include "Log.h" |
25 | 26 | #include "Util.h" |
26 | 27 | #include "FileSystem.h" |
27 | 28 | |
29 | DiskService::DiskService() | |
30 | { | |
31 | g_WorkState->Attach(this); | |
32 | } | |
33 | ||
34 | void DiskService::Update(Subject* caller, void* aspect) | |
35 | { | |
36 | WakeUp(); | |
37 | } | |
38 | ||
39 | int DiskService::ServiceInterval() | |
40 | { | |
41 | return m_waitingRequiredDir ? 1 : | |
42 | g_Options->GetDiskSpace() <= 0 ? Service::Sleep : | |
43 | // notifications from 'WorkState' are not 100% reliable due to race conditions | |
44 | !g_WorkState->GetDownloading() ? 10 : | |
45 | 1; | |
46 | } | |
47 | ||
28 | 48 | void DiskService::ServiceWork() |
29 | 49 | { |
30 | m_interval++; | |
31 | if (m_interval == 5) | |
50 | debug("Disk service work"); | |
51 | ||
52 | if (g_Options->GetDiskSpace() > 0 && g_WorkState->GetDownloading()) | |
32 | 53 | { |
33 | if (!g_Options->GetPauseDownload() && | |
34 | g_Options->GetDiskSpace() > 0 && !g_StatMeter->GetStandBy()) | |
35 | { | |
36 | // check free disk space every 1 second | |
37 | CheckDiskSpace(); | |
38 | } | |
39 | m_interval = 0; | |
54 | // check free disk space every 1 second | |
55 | CheckDiskSpace(); | |
40 | 56 | } |
41 | 57 | |
42 | 58 | if (m_waitingRequiredDir) |
47 | 63 | |
48 | 64 | void DiskService::CheckDiskSpace() |
49 | 65 | { |
66 | debug("Disk service work: check disk space"); | |
67 | ||
50 | 68 | int64 freeSpace = FileSystem::FreeDiskSize(g_Options->GetDestDir()); |
51 | 69 | if (freeSpace > -1 && freeSpace / 1024 / 1024 < g_Options->GetDiskSpace()) |
52 | 70 | { |
53 | 71 | warn("Low disk space on %s. Pausing download", g_Options->GetDestDir()); |
54 | g_Options->SetPauseDownload(true); | |
72 | g_WorkState->SetPauseDownload(true); | |
55 | 73 | } |
56 | 74 | |
57 | 75 | if (!Util::EmptyStr(g_Options->GetInterDir())) |
60 | 78 | if (freeSpace > -1 && freeSpace / 1024 / 1024 < g_Options->GetDiskSpace()) |
61 | 79 | { |
62 | 80 | warn("Low disk space on %s. Pausing download", g_Options->GetInterDir()); |
63 | g_Options->SetPauseDownload(true); | |
81 | g_WorkState->SetPauseDownload(true); | |
64 | 82 | } |
65 | 83 | } |
66 | 84 | } |
67 | 85 | |
68 | 86 | void DiskService::CheckRequiredDir() |
69 | 87 | { |
88 | debug("Disk service work: check required dir"); | |
89 | ||
70 | 90 | if (!Util::EmptyStr(g_Options->GetRequiredDir())) |
71 | 91 | { |
72 | 92 | bool allExist = true; |
96 | 116 | info("All required directories available"); |
97 | 117 | } |
98 | 118 | |
99 | g_Options->SetTempPauseDownload(false); | |
100 | g_Options->SetTempPausePostprocess(false); | |
119 | g_WorkState->SetTempPauseDownload(false); | |
120 | g_WorkState->SetTempPausePostprocess(false); | |
101 | 121 | m_waitingRequiredDir = false; |
102 | 122 | } |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2015-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
21 | 21 | #define DISKSERVICE_H |
22 | 22 | |
23 | 23 | #include "Service.h" |
24 | #include "Observer.h" | |
24 | 25 | |
25 | class DiskService : public Service | |
26 | class DiskService : public Service, public Observer | |
26 | 27 | { |
28 | public: | |
29 | DiskService(); | |
30 | ||
27 | 31 | protected: |
28 | virtual int ServiceInterval() { return 200; } | |
32 | virtual int ServiceInterval(); | |
29 | 33 | virtual void ServiceWork(); |
34 | virtual void Update(Subject* caller, void* aspect); | |
30 | 35 | |
31 | 36 | private: |
32 | int m_interval = 0; | |
33 | 37 | bool m_waitingRequiredDir = true; |
34 | 38 | bool m_waitingReported = false; |
35 | 39 |
67 | 67 | { |
68 | 68 | while (m_updateScriptController) |
69 | 69 | { |
70 | usleep(20*1000); | |
70 | Util::Sleep(20); | |
71 | 71 | } |
72 | 72 | } |
73 | 73 | } |
178 | 178 | return false; |
179 | 179 | } |
180 | 180 | |
181 | int len = (int)(pend - p); | |
181 | size_t len = pend - p; | |
182 | 182 | if (len >= sizeof(fileName)) |
183 | 183 | { |
184 | 184 | error("Could not parse file %s", *fileName); |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
1905 | 1905 | { |
1906 | 1906 | for (OptEntry& opt : optEntries) |
1907 | 1907 | { |
1908 | const char* optname = opt.GetName(); | |
1909 | if (!strncasecmp(optname, "category", 8)) | |
1908 | const char* catoptname = opt.GetName(); | |
1909 | if (!strncasecmp(catoptname, "category", 8)) | |
1910 | 1910 | { |
1911 | char* p = (char*)optname + 8; | |
1911 | char* p = (char*)catoptname + 8; | |
1912 | 1912 | while (*p >= '0' && *p <= '9') p++; |
1913 | 1913 | if (p && (!strcasecmp(p, ".extensions"))) |
1914 | 1914 | { |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
299 | 299 | bool GetDirectRename() { return m_directRename; } |
300 | 300 | bool GetReorderFiles() { return m_reorderFiles; } |
301 | 301 | EFileNaming GetFileNaming() { return m_fileNaming; } |
302 | int GetDownloadRate() const { return m_downloadRate; } | |
302 | 303 | |
303 | 304 | Categories* GetCategories() { return &m_categories; } |
304 | 305 | Category* FindCategory(const char* name, bool searchAliases) { return m_categories.FindCategory(name, searchAliases); } |
310 | 311 | bool GetDaemonMode() { return m_daemonMode; } |
311 | 312 | void SetRemoteClientMode(bool remoteClientMode) { m_remoteClientMode = remoteClientMode; } |
312 | 313 | bool GetRemoteClientMode() { return m_remoteClientMode; } |
313 | void SetPauseDownload(bool pauseDownload) { m_pauseDownload = pauseDownload; } | |
314 | bool GetPauseDownload() const { return m_pauseDownload; } | |
315 | void SetPausePostProcess(bool pausePostProcess) { m_pausePostProcess = pausePostProcess; } | |
316 | bool GetPausePostProcess() const { return m_pausePostProcess; } | |
317 | void SetPauseScan(bool pauseScan) { m_pauseScan = pauseScan; } | |
318 | bool GetPauseScan() const { return m_pauseScan; } | |
319 | void SetTempPauseDownload(bool tempPauseDownload) { m_tempPauseDownload = tempPauseDownload; } | |
320 | bool GetTempPauseDownload() const { return m_tempPauseDownload; } | |
321 | bool GetTempPausePostprocess() const { return m_tempPausePostprocess; } | |
322 | void SetTempPausePostprocess(bool tempPausePostprocess) { m_tempPausePostprocess = tempPausePostprocess; } | |
323 | void SetDownloadRate(int rate) { m_downloadRate = rate; } | |
324 | int GetDownloadRate() const { return m_downloadRate; } | |
325 | void SetResumeTime(time_t resumeTime) { m_resumeTime = resumeTime; } | |
326 | time_t GetResumeTime() const { return m_resumeTime; } | |
327 | void SetLocalTimeOffset(int localTimeOffset) { m_localTimeOffset = localTimeOffset; } | |
328 | int GetLocalTimeOffset() { return m_localTimeOffset; } | |
329 | void SetQuotaReached(bool quotaReached) { m_quotaReached = quotaReached; } | |
330 | bool GetQuotaReached() { return m_quotaReached; } | |
331 | 314 | |
332 | 315 | private: |
333 | 316 | OptEntries m_optEntries; |
449 | 432 | int m_dailyQuota = 0; |
450 | 433 | bool m_reorderFiles = false; |
451 | 434 | EFileNaming m_fileNaming = nfArticle; |
452 | ||
453 | // Current state | |
435 | int m_downloadRate = 0; | |
436 | ||
437 | // Application mode | |
454 | 438 | bool m_serverMode = false; |
455 | 439 | bool m_daemonMode = false; |
456 | 440 | bool m_remoteClientMode = false; |
457 | bool m_pauseDownload = false; | |
458 | bool m_pausePostProcess = false; | |
459 | bool m_pauseScan = false; | |
460 | bool m_tempPauseDownload = true; | |
461 | bool m_tempPausePostprocess = true; | |
462 | int m_downloadRate = 0; | |
463 | time_t m_resumeTime = 0; | |
464 | int m_localTimeOffset = 0; | |
465 | bool m_quotaReached = false; | |
466 | 441 | |
467 | 442 | void Init(const char* exeName, const char* configFilename, bool noConfig, |
468 | 443 | CmdOptList* commandLineOptions, bool noDiskAccess, Extender* extender); |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2008-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2008-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
20 | 20 | #include "nzbget.h" |
21 | 21 | #include "Scheduler.h" |
22 | 22 | #include "Options.h" |
23 | #include "WorkState.h" | |
23 | 24 | #include "Log.h" |
24 | 25 | #include "NewsServer.h" |
25 | 26 | #include "ServerPool.h" |
50 | 51 | CheckTasks(); |
51 | 52 | } |
52 | 53 | |
54 | void Scheduler::ScheduleNextWork() | |
55 | { | |
56 | // Ideally we should calculate wait time until next scheduler task or until resume time. | |
57 | // The first isn't trivial and the second requires watching/reaction on changed scheduled resume time. | |
58 | // We do it simpler instead: check once per minute, when seconds are changing from 59 to 00. | |
59 | ||
60 | time_t curTime = Util::CurrentTime(); | |
61 | tm sched; | |
62 | gmtime_r(&curTime, &sched); | |
63 | sched.tm_min++; | |
64 | sched.tm_sec = 0; | |
65 | time_t nextMinute = Util::Timegm(&sched); | |
66 | ||
67 | m_serviceInterval = nextMinute - curTime; | |
68 | } | |
69 | ||
53 | 70 | void Scheduler::ServiceWork() |
54 | 71 | { |
72 | debug("Scheduler service work"); | |
73 | ||
55 | 74 | if (!DownloadQueue::IsLoaded()) |
56 | 75 | { |
57 | 76 | return; |
58 | 77 | } |
78 | ||
79 | debug("Scheduler service work: doing work"); | |
59 | 80 | |
60 | 81 | if (!m_firstChecked) |
61 | 82 | { |
67 | 88 | m_executeProcess = true; |
68 | 89 | CheckTasks(); |
69 | 90 | CheckScheduledResume(); |
91 | ScheduleNextWork(); | |
70 | 92 | } |
71 | 93 | |
72 | 94 | void Scheduler::CheckTasks() |
99 | 121 | } |
100 | 122 | } |
101 | 123 | |
102 | time_t localCurrent = current + g_Options->GetLocalTimeOffset(); | |
103 | time_t localLastCheck = m_lastCheck + g_Options->GetLocalTimeOffset(); | |
124 | time_t localCurrent = current + g_WorkState->GetLocalTimeOffset(); | |
125 | time_t localLastCheck = m_lastCheck + g_WorkState->GetLocalTimeOffset(); | |
104 | 126 | |
105 | 127 | tm tmCurrent; |
106 | 128 | gmtime_r(&localCurrent, &tmCurrent); |
158 | 180 | |
159 | 181 | void Scheduler::ExecuteTask(Task* task) |
160 | 182 | { |
183 | #ifdef DEBUG | |
161 | 184 | const char* commandName[] = { "Pause", "Unpause", "Pause Post-processing", "Unpause Post-processing", |
162 | 185 | "Set download rate", "Execute process", "Execute script", |
163 | 186 | "Pause Scan", "Unpause Scan", "Enable Server", "Disable Server", "Fetch Feed" }; |
164 | 187 | debug("Executing scheduled command: %s", commandName[task->m_command]); |
188 | #endif | |
165 | 189 | |
166 | 190 | bool executeProcess = m_executeProcess || task->m_hours == Task::STARTUP_TASK; |
167 | 191 | |
170 | 194 | case scDownloadRate: |
171 | 195 | if (!task->m_param.Empty()) |
172 | 196 | { |
173 | g_Options->SetDownloadRate(atoi(task->m_param) * 1024); | |
197 | g_WorkState->SetSpeedLimit(atoi(task->m_param) * 1024); | |
174 | 198 | m_downloadRateChanged = true; |
175 | 199 | } |
176 | 200 | break; |
177 | 201 | |
178 | 202 | case scPauseDownload: |
179 | 203 | case scUnpauseDownload: |
180 | g_Options->SetPauseDownload(task->m_command == scPauseDownload); | |
204 | g_WorkState->SetPauseDownload(task->m_command == scPauseDownload); | |
181 | 205 | m_pauseDownloadChanged = true; |
182 | 206 | break; |
183 | 207 | |
184 | 208 | case scPausePostProcess: |
185 | 209 | case scUnpausePostProcess: |
186 | g_Options->SetPausePostProcess(task->m_command == scPausePostProcess); | |
210 | g_WorkState->SetPausePostProcess(task->m_command == scPausePostProcess); | |
187 | 211 | m_pausePostProcessChanged = true; |
188 | 212 | break; |
189 | 213 | |
190 | 214 | case scPauseScan: |
191 | 215 | case scUnpauseScan: |
192 | g_Options->SetPauseScan(task->m_command == scPauseScan); | |
216 | g_WorkState->SetPauseScan(task->m_command == scPauseScan); | |
193 | 217 | m_pauseScanChanged = true; |
194 | 218 | break; |
195 | 219 | |
228 | 252 | { |
229 | 253 | if (m_downloadRateChanged) |
230 | 254 | { |
231 | info("Scheduler: setting download rate to %i KB/s", g_Options->GetDownloadRate() / 1024); | |
255 | info("Scheduler: setting download rate to %i KB/s", g_WorkState->GetSpeedLimit() / 1024); | |
232 | 256 | } |
233 | 257 | if (m_pauseDownloadChanged) |
234 | 258 | { |
235 | info("Scheduler: %s download", g_Options->GetPauseDownload() ? "pausing" : "unpausing"); | |
259 | info("Scheduler: %s download", g_WorkState->GetPauseDownload() ? "pausing" : "unpausing"); | |
236 | 260 | } |
237 | 261 | if (m_pausePostProcessChanged) |
238 | 262 | { |
239 | info("Scheduler: %s post-processing", g_Options->GetPausePostProcess() ? "pausing" : "unpausing"); | |
263 | info("Scheduler: %s post-processing", g_WorkState->GetPausePostProcess() ? "pausing" : "unpausing"); | |
240 | 264 | } |
241 | 265 | if (m_pauseScanChanged) |
242 | 266 | { |
243 | info("Scheduler: %s scan", g_Options->GetPauseScan() ? "pausing" : "unpausing"); | |
267 | info("Scheduler: %s scan", g_WorkState->GetPauseScan() ? "pausing" : "unpausing"); | |
244 | 268 | } |
245 | 269 | if (m_serverChanged) |
246 | 270 | { |
307 | 331 | |
308 | 332 | void Scheduler::CheckScheduledResume() |
309 | 333 | { |
310 | time_t resumeTime = g_Options->GetResumeTime(); | |
334 | time_t resumeTime = g_WorkState->GetResumeTime(); | |
311 | 335 | time_t currentTime = Util::CurrentTime(); |
312 | 336 | if (resumeTime > 0 && currentTime >= resumeTime) |
313 | 337 | { |
314 | 338 | info("Autoresume"); |
315 | g_Options->SetResumeTime(0); | |
316 | g_Options->SetPauseDownload(false); | |
317 | g_Options->SetPausePostProcess(false); | |
318 | g_Options->SetPauseScan(false); | |
319 | } | |
320 | } | |
339 | g_WorkState->SetResumeTime(0); | |
340 | g_WorkState->SetPauseDownload(false); | |
341 | g_WorkState->SetPausePostProcess(false); | |
342 | g_WorkState->SetPauseScan(false); | |
343 | } | |
344 | } |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2008-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2008-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
65 | 65 | void AddTask(std::unique_ptr<Task> task); |
66 | 66 | |
67 | 67 | protected: |
68 | virtual int ServiceInterval() { return 1000; } | |
68 | virtual int ServiceInterval() { return m_serviceInterval; } | |
69 | 69 | virtual void ServiceWork(); |
70 | 70 | |
71 | 71 | private: |
83 | 83 | bool m_serverChanged; |
84 | 84 | ServerStatusList m_serverStatusList; |
85 | 85 | bool m_firstChecked = false; |
86 | int m_serviceInterval = 1; | |
86 | 87 | |
87 | 88 | void ExecuteTask(Task* task); |
88 | 89 | void CheckTasks(); |
92 | 93 | void FetchFeed(const char* feedList); |
93 | 94 | void CheckScheduledResume(); |
94 | 95 | void FirstCheck(); |
96 | void ScheduleNextWork(); | |
95 | 97 | }; |
96 | 98 | |
97 | 99 | #endif |
281 | 281 | void DoSegFault() |
282 | 282 | { |
283 | 283 | char* N = nullptr; |
284 | strcpy(N, ""); | |
284 | *N = '\0'; | |
285 | 285 | } |
286 | 286 | }; |
287 | 287 |
0 | /* | |
1 | * This file is part of nzbget. See <http://nzbget.net>. | |
2 | * | |
3 | * Copyright (C) 2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | ||
20 | #include "nzbget.h" | |
21 | #include "WorkState.h" | |
22 | ||
23 | void WorkState::Changed() | |
24 | { | |
25 | Notify(nullptr); | |
26 | } |
0 | /* | |
1 | * This file is part of nzbget. See <http://nzbget.net>. | |
2 | * | |
3 | * Copyright (C) 2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | ||
20 | #ifndef WORKSTATE_H | |
21 | #define WORKSTATE_H | |
22 | ||
23 | #include "Observer.h" | |
24 | ||
25 | // WorkState is observable but notifications are not 100% reliable. | |
26 | // The changes via Set-methods and readings via Get-methods are not synchronized throughout the program. | |
27 | // As result race conditions may occur and some changes may go unnoticed. | |
28 | // When waiting for changes don't wait too long to avoid lock ups. | |
29 | ||
30 | class WorkState : public Subject | |
31 | { | |
32 | public: | |
33 | void SetPauseDownload(bool pauseDownload) { m_pauseDownload = pauseDownload; Changed(); } | |
34 | bool GetPauseDownload() const { return m_pauseDownload; } | |
35 | void SetPausePostProcess(bool pausePostProcess) { m_pausePostProcess = pausePostProcess; Changed(); } | |
36 | bool GetPausePostProcess() const { return m_pausePostProcess; } | |
37 | void SetPauseScan(bool pauseScan) { m_pauseScan = pauseScan; Changed(); } | |
38 | bool GetPauseScan() const { return m_pauseScan; } | |
39 | void SetTempPauseDownload(bool tempPauseDownload) { m_tempPauseDownload = tempPauseDownload; Changed(); } | |
40 | bool GetTempPauseDownload() const { return m_tempPauseDownload; } | |
41 | void SetTempPausePostprocess(bool tempPausePostprocess) { m_tempPausePostprocess = tempPausePostprocess; Changed(); } | |
42 | bool GetTempPausePostprocess() const { return m_tempPausePostprocess; } | |
43 | void SetPauseFrontend(bool pauseFrontend) { m_pauseFrontend = pauseFrontend; Changed(); } | |
44 | bool GetPauseFrontend() const { return m_pauseFrontend; } | |
45 | void SetSpeedLimit(int speedLimit) { m_speedLimit = speedLimit; Changed(); } | |
46 | int GetSpeedLimit() const { return m_speedLimit; } | |
47 | void SetResumeTime(time_t resumeTime) { m_resumeTime = resumeTime; Changed(); } | |
48 | time_t GetResumeTime() const { return m_resumeTime; } | |
49 | void SetLocalTimeOffset(int localTimeOffset) { m_localTimeOffset = localTimeOffset; Changed(); } | |
50 | int GetLocalTimeOffset() { return m_localTimeOffset; } | |
51 | void SetQuotaReached(bool quotaReached) { m_quotaReached = quotaReached; Changed(); } | |
52 | bool GetQuotaReached() { return m_quotaReached; } | |
53 | void SetDownloading(bool downloading) { m_downloading = downloading; Changed(); } | |
54 | bool GetDownloading() { return m_downloading; } | |
55 | ||
56 | private: | |
57 | bool m_pauseDownload = false; | |
58 | bool m_pausePostProcess = false; | |
59 | bool m_pauseScan = false; | |
60 | bool m_tempPauseDownload = true; | |
61 | bool m_tempPausePostprocess = true; | |
62 | bool m_pauseFrontend = false; | |
63 | int m_downloadRate = 0; | |
64 | time_t m_resumeTime = 0; | |
65 | int m_localTimeOffset = 0; | |
66 | bool m_quotaReached = false; | |
67 | int m_speedLimit = 0; | |
68 | bool m_downloading = false; | |
69 | ||
70 | void Changed(); | |
71 | }; | |
72 | ||
73 | extern WorkState* g_WorkState; | |
74 | ||
75 | #endif |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
23 | 23 | #include "Log.h" |
24 | 24 | #include "NzbFile.h" |
25 | 25 | #include "Options.h" |
26 | #include "WorkState.h" | |
26 | 27 | #include "CommandLineParser.h" |
27 | 28 | #include "ScriptConfig.h" |
28 | 29 | #include "Thread.h" |
70 | 71 | // Globals |
71 | 72 | Log* g_Log; |
72 | 73 | Options* g_Options; |
74 | WorkState* g_WorkState; | |
73 | 75 | ServerPool* g_ServerPool; |
74 | 76 | QueueCoordinator* g_QueueCoordinator; |
75 | 77 | UrlCoordinator* g_UrlCoordinator; |
192 | 194 | // globals |
193 | 195 | std::unique_ptr<Log> m_log; |
194 | 196 | std::unique_ptr<Options> m_options; |
197 | std::unique_ptr<WorkState> m_workState; | |
195 | 198 | std::unique_ptr<ServerPool> m_serverPool; |
196 | 199 | std::unique_ptr<QueueCoordinator> m_queueCoordinator; |
197 | 200 | std::unique_ptr<UrlCoordinator> m_urlCoordinator; |
222 | 225 | |
223 | 226 | bool m_reloading = false; |
224 | 227 | bool m_daemonized = false; |
228 | bool m_stopped = false; | |
229 | Mutex m_waitMutex; | |
230 | ConditionVar m_waitCond; | |
225 | 231 | |
226 | 232 | void Init(); |
227 | 233 | void Final(); |
338 | 344 | g_WinConsole = m_winConsole.get(); |
339 | 345 | #endif |
340 | 346 | |
347 | m_workState = std::make_unique<WorkState>(); | |
348 | g_WorkState = m_workState.get(); | |
349 | ||
341 | 350 | m_serviceCoordinator = std::make_unique<ServiceCoordinator>(); |
342 | 351 | g_ServiceCoordinator = m_serviceCoordinator.get(); |
343 | 352 | |
411 | 420 | m_commandLineParser->GetNoConfig(), (Options::CmdOptList*)m_commandLineParser->GetOptionList(), this); |
412 | 421 | m_options->SetRemoteClientMode(m_commandLineParser->GetRemoteClientMode()); |
413 | 422 | m_options->SetServerMode(m_commandLineParser->GetServerMode()); |
414 | m_options->SetPauseDownload(m_commandLineParser->GetPauseDownload()); | |
423 | m_workState->SetPauseDownload(m_commandLineParser->GetPauseDownload()); | |
424 | m_workState->SetSpeedLimit(g_Options->GetDownloadRate()); | |
415 | 425 | |
416 | 426 | m_log->InitOptions(); |
417 | 427 | |
423 | 433 | m_commandLineParser->GetClientOperation() == CommandLineParser::opClientNoOperation) |
424 | 434 | { |
425 | 435 | info("Pausing all activities due to errors in configuration"); |
426 | m_options->SetPauseDownload(true); | |
427 | m_options->SetPausePostProcess(true); | |
428 | m_options->SetPauseScan(true); | |
436 | m_workState->SetPauseDownload(true); | |
437 | m_workState->SetPausePostProcess(true); | |
438 | m_workState->SetPauseScan(true); | |
429 | 439 | } |
430 | 440 | |
431 | 441 | m_serverPool->SetTimeout(m_options->GetArticleTimeout()); |
536 | 546 | (m_remoteSecureServer && m_remoteSecureServer->IsRunning())) && |
537 | 547 | maxWaitMSec > 0) |
538 | 548 | { |
539 | usleep(100 * 1000); | |
549 | Util::Sleep(100); | |
540 | 550 | maxWaitMSec -= 100; |
541 | 551 | } |
542 | 552 | |
555 | 565 | (m_remoteSecureServer && m_remoteSecureServer->IsRunning())) && |
556 | 566 | maxWaitMSec > 0) |
557 | 567 | { |
558 | usleep(100 * 1000); | |
568 | Util::Sleep(100); | |
559 | 569 | maxWaitMSec -= 100; |
560 | 570 | } |
561 | 571 | |
613 | 623 | } |
614 | 624 | while (m_frontend->IsRunning()) |
615 | 625 | { |
616 | usleep(50 * 1000); | |
626 | Util::Sleep(50); | |
617 | 627 | } |
618 | 628 | debug("Frontend stopped"); |
619 | 629 | } |
693 | 703 | m_serviceCoordinator->Stop(); |
694 | 704 | } |
695 | 705 | } |
696 | usleep(100 * 1000); | |
706 | Util::Sleep(100); | |
707 | ||
708 | if (m_options->GetServerMode() && !m_stopped) | |
709 | { | |
710 | // wait for stop signal | |
711 | Guard guard(m_waitMutex); | |
712 | m_waitCond.Wait(m_waitMutex, [&]{ return m_stopped; }); | |
713 | } | |
697 | 714 | } |
698 | 715 | |
699 | 716 | debug("Main program loop terminated"); |
896 | 913 | #endif |
897 | 914 | } |
898 | 915 | } |
916 | ||
917 | // trigger stop/reload signal | |
918 | Guard guard(m_waitMutex); | |
919 | m_stopped = true; | |
920 | m_waitCond.NotifyAll(); | |
899 | 921 | } |
900 | 922 | |
901 | 923 | void NZBGet::PrintOptions() |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
114 | 114 | |
115 | 115 | // WINDOWS INCLUDES |
116 | 116 | |
117 | // Using "WIN32_LEAN_AND_MEAN" to disable including on many unneeded headers | |
117 | // Using "WIN32_LEAN_AND_MEAN" to disable including of many unneeded headers | |
118 | 118 | #define WIN32_LEAN_AND_MEAN |
119 | 119 | #define NOMINMAX |
120 | 120 | |
208 | 208 | #include <stdarg.h> |
209 | 209 | #include <time.h> |
210 | 210 | #include <ctype.h> |
211 | #include <inttypes.h> | |
211 | 212 | |
212 | 213 | #include <string> |
213 | 214 | #include <vector> |
221 | 222 | #include <fstream> |
222 | 223 | #include <memory> |
223 | 224 | #include <functional> |
225 | #include <thread> | |
226 | #include <mutex> | |
227 | #include <condition_variable> | |
228 | #include <chrono> | |
224 | 229 | |
225 | 230 | // NOTE: do not include <iostream> in "nzbget.h". <iostream> contains objects requiring |
226 | 231 | // intialization, causing every unit in nzbget to have initialization routine. This in particular |
271 | 276 | #include <cassert> |
272 | 277 | #ifdef HAVE_MEMORY_H |
273 | 278 | # include <memory.h> |
274 | #endif | |
275 | #ifdef HAVE_INTTYPES_H | |
276 | # include <inttypes.h> | |
277 | 279 | #endif |
278 | 280 | #endif /* NOT DISABLE_PARCHECK */ |
279 | 281 | |
301 | 303 | #define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR) |
302 | 304 | #define S_ISREG(mode) __S_ISTYPE((mode), _S_IFREG) |
303 | 305 | #define S_DIRMODE nullptr |
304 | #define usleep(usec) Sleep((usec) / 1000) | |
305 | 306 | #define socklen_t int |
306 | 307 | #define SHUT_WR 0x01 |
307 | 308 | #define SHUT_RDWR 0x02 |
382 | 383 | typedef unsigned long long uint64; |
383 | 384 | #endif |
384 | 385 | |
386 | #ifndef PRId64 | |
387 | #define PRId64 "lld" | |
388 | #endif | |
389 | #ifndef PRIi64 | |
390 | #define PRIi64 "lli" | |
391 | #endif | |
392 | #ifndef PRIu64 | |
393 | #define PRIu64 "llu" | |
394 | #endif | |
395 | ||
385 | 396 | typedef unsigned char uchar; |
386 | 397 | |
387 | 398 | // Assume little endian if byte order is not defined |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
24 | 24 | #include "Decoder.h" |
25 | 25 | #include "Log.h" |
26 | 26 | #include "Options.h" |
27 | #include "WorkState.h" | |
27 | 28 | #include "ServerPool.h" |
28 | 29 | #include "StatMeter.h" |
29 | 30 | #include "Util.h" |
96 | 97 | while (!m_connection && !(IsStopped() || serverConfigGeneration != g_ServerPool->GetGeneration())) |
97 | 98 | { |
98 | 99 | m_connection = g_ServerPool->GetConnection(level, wantServer, &failedServers); |
99 | usleep(5 * 1000); | |
100 | Util::Sleep(5); | |
100 | 101 | } |
101 | 102 | SetLastUpdateTimeNow(); |
102 | 103 | SetStatus(adRunning); |
103 | 104 | |
104 | if (IsStopped() || ((g_Options->GetPauseDownload() || g_Options->GetQuotaReached()) && !force) || | |
105 | (g_Options->GetTempPauseDownload() && !m_fileInfo->GetExtraPriority()) || | |
105 | if (IsStopped() || ((g_WorkState->GetPauseDownload() || g_WorkState->GetQuotaReached()) && !force) || | |
106 | (g_WorkState->GetTempPauseDownload() && !m_fileInfo->GetExtraPriority()) || | |
106 | 107 | serverConfigGeneration != g_ServerPool->GetGeneration()) |
107 | 108 | { |
108 | 109 | status = adRetry; |
193 | 194 | break; |
194 | 195 | } |
195 | 196 | |
196 | if (IsStopped() || ((g_Options->GetPauseDownload() || g_Options->GetQuotaReached()) && !force) || | |
197 | (g_Options->GetTempPauseDownload() && !m_fileInfo->GetExtraPriority()) || | |
197 | if (IsStopped() || ((g_WorkState->GetPauseDownload() || g_WorkState->GetQuotaReached()) && !force) || | |
198 | (g_WorkState->GetTempPauseDownload() && !m_fileInfo->GetExtraPriority()) || | |
198 | 199 | serverConfigGeneration != g_ServerPool->GetGeneration()) |
199 | 200 | { |
200 | 201 | status = adRetry; |
338 | 339 | while (!IsStopped() && !m_decoder.GetEof()) |
339 | 340 | { |
340 | 341 | // throttle the bandwidth |
341 | while (!IsStopped() && (g_Options->GetDownloadRate() > 0.0f) && | |
342 | (g_StatMeter->CalcCurrentDownloadSpeed() > g_Options->GetDownloadRate() || | |
343 | g_StatMeter->CalcMomentaryDownloadSpeed() > g_Options->GetDownloadRate())) | |
342 | while (!IsStopped() && (g_WorkState->GetSpeedLimit() > 0.0f) && | |
343 | (g_StatMeter->CalcCurrentDownloadSpeed() > g_WorkState->GetSpeedLimit() || | |
344 | g_StatMeter->CalcMomentaryDownloadSpeed() > g_WorkState->GetSpeedLimit())) | |
344 | 345 | { |
345 | 346 | SetLastUpdateTimeNow(); |
346 | usleep(10 * 1000); | |
347 | Util::Sleep(10); | |
347 | 348 | } |
348 | 349 | |
349 | 350 | char* buffer; |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2014-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2014-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
112 | 112 | |
113 | 113 | while (!m_articleData.GetData() && g_ArticleCache->GetFlushing()) |
114 | 114 | { |
115 | usleep(5 * 1000); | |
115 | Util::Sleep(5); | |
116 | 116 | m_articleData = g_ArticleCache->Alloc(m_articleSize); |
117 | 117 | } |
118 | 118 | |
125 | 125 | if (!m_articleData.GetData()) |
126 | 126 | { |
127 | 127 | bool directWrite = (g_Options->GetDirectWrite() || m_fileInfo->GetForceDirectWrite()) && m_format == Decoder::efYenc; |
128 | const char* filename = directWrite ? m_outputFilename : m_tempFilename; | |
129 | if (!m_outFile.Open(filename, directWrite ? DiskFile::omReadWrite : DiskFile::omWrite)) | |
128 | const char* outFilename = directWrite ? m_outputFilename : m_tempFilename; | |
129 | if (!m_outFile.Open(outFilename, directWrite ? DiskFile::omReadWrite : DiskFile::omWrite)) | |
130 | 130 | { |
131 | 131 | m_fileInfo->GetNzbInfo()->PrintMessage(Message::mkError, |
132 | "Could not %s file %s: %s", directWrite ? "open" : "create", filename, | |
132 | "Could not %s file %s: %s", directWrite ? "open" : "create", outFilename, | |
133 | 133 | *FileSystem::GetLastErrorMessage()); |
134 | 134 | return false; |
135 | 135 | } |
774 | 774 | { |
775 | 775 | g_DiskState->WriteCacheFlag(); |
776 | 776 | } |
777 | if (!m_allocated) | |
778 | { | |
779 | // Resume Run(), the notification arrives later, after releasing m_allocMutex | |
780 | m_allocCond.NotifyAll(); | |
781 | } | |
777 | 782 | m_allocated += size; |
778 | 783 | } |
779 | 784 | } |
820 | 825 | bool justFlushed = false; |
821 | 826 | while (!IsStopped() || m_allocated > 0) |
822 | 827 | { |
823 | if ((justFlushed || resetCounter >= 1000 || IsStopped() || | |
828 | if ((justFlushed || resetCounter >= 1000 || IsStopped() || | |
824 | 829 | (g_Options->GetDirectWrite() && m_allocated >= fillThreshold)) && |
825 | 830 | m_allocated > 0) |
826 | 831 | { |
827 | 832 | justFlushed = CheckFlush(m_allocated >= fillThreshold); |
828 | 833 | resetCounter = 0; |
829 | 834 | } |
835 | else if (!m_allocated) | |
836 | { | |
837 | Guard guard(m_allocMutex); | |
838 | m_allocCond.Wait(m_allocMutex, [&]{ return IsStopped() || m_allocated > 0; }); | |
839 | resetCounter = 0; | |
840 | } | |
830 | 841 | else |
831 | 842 | { |
832 | usleep(5 * 1000); | |
843 | Util::Sleep(5); | |
833 | 844 | resetCounter += 5; |
834 | 845 | } |
835 | 846 | } |
847 | } | |
848 | ||
849 | void ArticleCache::Stop() | |
850 | { | |
851 | Thread::Stop(); | |
852 | ||
853 | // Resume Run() to exit it | |
854 | Guard guard(m_allocMutex); | |
855 | m_allocCond.NotifyAll(); | |
836 | 856 | } |
837 | 857 | |
838 | 858 | bool ArticleCache::CheckFlush(bool flushEverything) |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2014-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2014-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
94 | 94 | }; |
95 | 95 | |
96 | 96 | virtual void Run(); |
97 | virtual void Stop(); | |
97 | 98 | CachedSegmentData Alloc(int size); |
98 | 99 | bool Realloc(CachedSegmentData* segment, int newSize); |
99 | 100 | void Free(CachedSegmentData* segment); |
110 | 111 | Mutex m_flushMutex; |
111 | 112 | Mutex m_contentMutex; |
112 | 113 | FileInfo* m_fileInfo = nullptr; |
114 | ConditionVar m_allocCond; | |
113 | 115 | |
114 | 116 | bool CheckFlush(bool flushEverything); |
115 | 117 | }; |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
373 | 373 | } |
374 | 374 | else |
375 | 375 | { |
376 | if (effLen >= 1) | |
377 | { | |
378 | *optr++ = UU_DECODE_CHAR (iptr[0]) << 2 | UU_DECODE_CHAR (iptr[1]) >> 4; | |
379 | } | |
376 | *optr++ = UU_DECODE_CHAR (iptr[0]) << 2 | UU_DECODE_CHAR (iptr[1]) >> 4; | |
380 | 377 | if (effLen >= 2) |
381 | 378 | { |
382 | 379 | *optr++ = UU_DECODE_CHAR (iptr[1]) << 4 | UU_DECODE_CHAR (iptr[2]) >> 2; |
24 | 24 | NewsServer::NewsServer(int id, bool active, const char* name, const char* host, int port, int ipVersion, |
25 | 25 | const char* user, const char* pass, bool joinGroup, bool tls, const char* cipher, |
26 | 26 | int maxConnections, int retention, int level, int group, bool optional) : |
27 | m_id(id), m_active(active), m_port(port), m_ipVersion(ipVersion), m_level(level), m_normLevel(level), | |
28 | m_group(group), m_maxConnections(maxConnections), m_joinGroup(joinGroup), m_tls(tls), | |
29 | m_name(name), m_host(host ? host : ""), m_user(user ? user : ""), m_password(pass ? pass : ""), | |
30 | m_cipher(cipher ? cipher : ""), m_retention(retention), m_optional(optional) | |
27 | m_id(id), m_active(active), m_name(name), m_host(host ? host : ""), m_port(port), m_ipVersion(ipVersion), | |
28 | m_user(user ? user : ""), m_password(pass ? pass : ""), m_joinGroup(joinGroup), m_tls(tls), | |
29 | m_cipher(cipher ? cipher : ""), m_maxConnections(maxConnections), m_retention(retention), | |
30 | m_level(level), m_normLevel(level), m_group(group), m_optional(optional) | |
31 | 31 | { |
32 | 32 | if (m_name.Empty()) |
33 | 33 | { |
64 | 64 | int m_stateId = 0; |
65 | 65 | bool m_active; |
66 | 66 | CString m_name; |
67 | int m_group; | |
68 | 67 | CString m_host; |
69 | 68 | int m_port; |
70 | 69 | int m_ipVersion; |
71 | 70 | CString m_user; |
72 | 71 | CString m_password; |
73 | int m_maxConnections; | |
74 | int m_level; | |
75 | int m_normLevel; | |
76 | 72 | bool m_joinGroup; |
77 | 73 | bool m_tls; |
78 | 74 | CString m_cipher; |
75 | int m_maxConnections; | |
79 | 76 | int m_retention; |
77 | int m_level; | |
78 | int m_normLevel; | |
79 | int m_group; | |
80 | 80 | bool m_optional = false; |
81 | 81 | time_t m_blockTime = 0; |
82 | 82 | }; |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2014-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2014-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
20 | 20 | #include "nzbget.h" |
21 | 21 | #include "StatMeter.h" |
22 | 22 | #include "Options.h" |
23 | #include "WorkState.h" | |
23 | 24 | #include "ServerPool.h" |
24 | 25 | #include "DiskState.h" |
25 | 26 | #include "Util.h" |
56 | 57 | void ServerVolume::AddData(int bytes) |
57 | 58 | { |
58 | 59 | time_t curTime = Util::CurrentTime(); |
59 | time_t locCurTime = curTime + g_Options->GetLocalTimeOffset(); | |
60 | time_t locDataTime = m_dataTime + g_Options->GetLocalTimeOffset(); | |
60 | time_t locCurTime = curTime + g_WorkState->GetLocalTimeOffset(); | |
61 | time_t locDataTime = m_dataTime + g_WorkState->GetLocalTimeOffset(); | |
61 | 62 | |
62 | 63 | int lastMinSlot = m_minSlot; |
63 | 64 | int lastHourSlot = m_hourSlot; |
137 | 138 | |
138 | 139 | for (int i = 0; i < 60; i++) |
139 | 140 | { |
140 | msg.AppendFmt("[%i]=%lli ", i, m_bytesPerSeconds[i]); | |
141 | msg.AppendFmt("[%i]=%" PRIi64 " ", i, m_bytesPerSeconds[i]); | |
141 | 142 | } |
142 | 143 | info("Secs: %s", *msg); |
143 | 144 | |
144 | 145 | msg.Clear(); |
145 | 146 | for (int i = 0; i < 60; i++) |
146 | 147 | { |
147 | msg.AppendFmt("[%i]=%lli ", i, m_bytesPerMinutes[i]); | |
148 | msg.AppendFmt("[%i]=%" PRIi64 " ", i, m_bytesPerMinutes[i]); | |
148 | 149 | } |
149 | 150 | info("Mins: %s", *msg); |
150 | 151 | |
151 | 152 | msg.Clear(); |
152 | 153 | for (int i = 0; i < 24; i++) |
153 | 154 | { |
154 | msg.AppendFmt("[%i]=%lli ", i, m_bytesPerHours[i]); | |
155 | msg.AppendFmt("[%i]=%" PRIi64 " ", i, m_bytesPerHours[i]); | |
155 | 156 | } |
156 | 157 | info("Hours: %s", *msg); |
157 | 158 | |
158 | 159 | msg.Clear(); |
159 | 160 | for (int i = 0; i < (int)m_bytesPerDays.size(); i++) |
160 | 161 | { |
161 | msg.AppendFmt("[%i]=%lli ", m_firstDay + i, m_bytesPerDays[i]); | |
162 | msg.AppendFmt("[%i]=%" PRIi64 " ", m_firstDay + i, m_bytesPerDays[i]); | |
162 | 163 | } |
163 | 164 | info("Days: %s", *msg); |
164 | 165 | } |
187 | 188 | tmSplittedTime.tm_isdst = -1; |
188 | 189 | time_t locTime = mktime(&tmSplittedTime); |
189 | 190 | time_t localTimeDelta = utcTime - locTime; |
190 | g_Options->SetLocalTimeOffset((int)localTimeDelta + g_Options->GetTimeCorrection()); | |
191 | g_WorkState->SetLocalTimeOffset((int)localTimeDelta + g_Options->GetTimeCorrection()); | |
191 | 192 | m_lastTimeOffset = utcTime; |
192 | 193 | |
193 | debug("UTC delta: %i (%i+%i)", g_Options->GetLocalTimeOffset(), (int)localTimeDelta, g_Options->GetTimeCorrection()); | |
194 | debug("UTC delta: %i (%i+%i)", g_WorkState->GetLocalTimeOffset(), (int)localTimeDelta, g_Options->GetTimeCorrection()); | |
194 | 195 | } |
195 | 196 | |
196 | 197 | /* |
379 | 380 | int timeDiff = (int)Util::CurrentTime() - m_speedStartTime * SPEEDMETER_SLOTSIZE; |
380 | 381 | info(" Speed: %i", speed); |
381 | 382 | info(" SpeedStartTime: %i", m_speedStartTime); |
382 | info(" SpeedTotalBytes: %lli", m_speedTotalBytes); | |
383 | info(" SpeedTotalBytes: %" PRIi64, m_speedTotalBytes); | |
383 | 384 | info(" SpeedBytesIndex: %i", m_speedBytesIndex); |
384 | info(" AllBytes: %lli", m_allBytes); | |
385 | info(" AllBytes: %" PRIi64, m_allBytes); | |
385 | 386 | info(" Time: %i", (int)Util::CurrentTime()); |
386 | 387 | info(" TimeDiff: %i", timeDiff); |
387 | 388 | for (int i=0; i < SPEEDMETER_SLOTS; i++) |
445 | 446 | |
446 | 447 | for (ServerVolume& serverVolume : m_serverVolumes) |
447 | 448 | { |
448 | serverVolume.CalcSlots(serverVolume.GetDataTime() + g_Options->GetLocalTimeOffset()); | |
449 | serverVolume.CalcSlots(serverVolume.GetDataTime() + g_WorkState->GetLocalTimeOffset()); | |
449 | 450 | } |
450 | 451 | |
451 | 452 | return ok; |
464 | 465 | bool monthlyQuotaReached = g_Options->GetMonthlyQuota() > 0 && monthBytes >= (int64)g_Options->GetMonthlyQuota() * 1024 * 1024; |
465 | 466 | bool dailyQuotaReached = g_Options->GetDailyQuota() > 0 && dayBytes >= (int64)g_Options->GetDailyQuota() * 1024 * 1024; |
466 | 467 | |
467 | if (monthlyQuotaReached && !g_Options->GetQuotaReached()) | |
468 | if (monthlyQuotaReached && !g_WorkState->GetQuotaReached()) | |
468 | 469 | { |
469 | 470 | warn("Monthly quota reached at %s", *Util::FormatSize(monthBytes)); |
470 | 471 | } |
471 | else if (dailyQuotaReached && !g_Options->GetQuotaReached()) | |
472 | else if (dailyQuotaReached && !g_WorkState->GetQuotaReached()) | |
472 | 473 | { |
473 | 474 | warn("Daily quota reached at %s", *Util::FormatSize(dayBytes)); |
474 | 475 | } |
475 | else if (!monthlyQuotaReached && !dailyQuotaReached && g_Options->GetQuotaReached()) | |
476 | else if (!monthlyQuotaReached && !dailyQuotaReached && g_WorkState->GetQuotaReached()) | |
476 | 477 | { |
477 | 478 | info("Quota lifted"); |
478 | 479 | } |
479 | 480 | |
480 | g_Options->SetQuotaReached(monthlyQuotaReached || dailyQuotaReached); | |
481 | g_WorkState->SetQuotaReached(monthlyQuotaReached || dailyQuotaReached); | |
481 | 482 | } |
482 | 483 | |
483 | 484 | void StatMeter::CalcQuotaUsage(int64& monthBytes, int64& dayBytes) |
486 | 487 | |
487 | 488 | ServerVolume totalVolume = m_serverVolumes[0]; |
488 | 489 | |
489 | time_t locTime = Util::CurrentTime() + g_Options->GetLocalTimeOffset(); | |
490 | time_t locTime = Util::CurrentTime() + g_WorkState->GetLocalTimeOffset(); | |
490 | 491 | int daySlot = (int)(locTime / 86400) - totalVolume.GetFirstDay(); |
491 | 492 | |
492 | 493 | dayBytes = 0; |
514 | 515 | { |
515 | 516 | int elapsedDays; |
516 | 517 | |
517 | time_t locCurTime = Util::CurrentTime() + g_Options->GetLocalTimeOffset(); | |
518 | time_t locCurTime = Util::CurrentTime() + g_WorkState->GetLocalTimeOffset(); | |
518 | 519 | tm dayparts; |
519 | 520 | gmtime_r(&locCurTime, &dayparts); |
520 | 521 |
83 | 83 | void AddServerData(int bytes, int serverId); |
84 | 84 | void CalcTotalStat(int* upTimeSec, int* dnTimeSec, int64* allBytes, bool* standBy); |
85 | 85 | void CalcQuotaUsage(int64& monthBytes, int64& dayBytes); |
86 | bool GetStandBy() { return m_standBy; } | |
87 | 86 | void IntervalCheck(); |
88 | 87 | void EnterLeaveStandBy(bool enter); |
89 | 88 | GuardedServerVolumes GuardServerVolumes(); |
33 | 33 | while (!IsStopped()) |
34 | 34 | { |
35 | 35 | Update(); |
36 | usleep(100 * 1000); | |
36 | Util::Sleep(100); | |
37 | 37 | } |
38 | 38 | // Printing the last messages |
39 | 39 | Update(); |
123 | 123 | } |
124 | 124 | |
125 | 125 | info("Press Ctrl+C to quit"); |
126 | while (getchar()) usleep(1000*200); | |
126 | while (getchar()) Util::Sleep(200); | |
127 | 127 | |
128 | 128 | for (std::unique_ptr<NntpServer>& serv: instances) |
129 | 129 | { |
139 | 139 | { |
140 | 140 | hasRunning |= serv->IsRunning(); |
141 | 141 | } |
142 | usleep(50 * 1000); | |
142 | Util::Sleep(50); | |
143 | 143 | } while (hasRunning); |
144 | 144 | |
145 | 145 | return 0; |
39 | 39 | int m_id; |
40 | 40 | int m_serverId; |
41 | 41 | std::unique_ptr<Connection> m_connection; |
42 | int m_latency; | |
43 | int m_speed; | |
44 | 42 | const char* m_dataDir; |
45 | 43 | const char* m_cacheDir; |
46 | 44 | const char* m_secureCert; |
47 | 45 | const char* m_secureKey; |
46 | int m_latency; | |
47 | int m_speed; | |
48 | 48 | const char* m_messageid; |
49 | 49 | CString m_filename; |
50 | 50 | int m_part; |
102 | 102 | break; |
103 | 103 | } |
104 | 104 | m_connection.reset(); |
105 | usleep(500 * 1000); | |
105 | Util::Sleep(500); | |
106 | 106 | continue; |
107 | 107 | } |
108 | 108 | |
215 | 215 | |
216 | 216 | if (m_latency) |
217 | 217 | { |
218 | usleep(1000 * m_latency); | |
218 | Util::Sleep(m_latency); | |
219 | 219 | } |
220 | 220 | |
221 | 221 | bool ok = false; |
267 | 267 | |
268 | 268 | void NntpProcessor::SendSegment() |
269 | 269 | { |
270 | detail("[%i] Sending segment %s (%i=%lli:%i)", m_id, *m_filename, m_part, (long long)m_offset, m_size); | |
270 | detail("[%i] Sending segment %s (%i=%" PRIi64 ":%i)", m_id, *m_filename, m_part, m_offset, m_size); | |
271 | 271 | |
272 | 272 | if (m_speed > 0) |
273 | 273 | { |
274 | m_start = Util::GetCurrentTicks(); | |
274 | m_start = Util::CurrentTicks(); | |
275 | 275 | } |
276 | 276 | |
277 | 277 | BString<1024> fullFilename("%s/%s", m_dataDir, *m_filename); |
278 | 278 | BString<1024> cacheFileDir("%s/%s", m_cacheDir, *m_filename); |
279 | BString<1024> cacheFileName("%i=%lli-%i", m_part, (long long)m_offset, m_size); | |
279 | BString<1024> cacheFileName("%i=%" PRIi64 "-%i", m_part, m_offset, m_size); | |
280 | 280 | BString<1024> cacheFullFilename("%s/%s", *cacheFileDir, *cacheFileName); |
281 | 281 | BString<1024> cacheKey("%s/%s", *m_filename, *cacheFileName); |
282 | 282 | |
382 | 382 | return; |
383 | 383 | } |
384 | 384 | |
385 | int64 expectedTime = (int64)1000 * size / (m_speed * 1024) - (Util::GetCurrentTicks() - m_start) / 1000; | |
385 | int64 expectedTime = (int64)1000 * size / (m_speed * 1024) - (Util::CurrentTicks() - m_start) / 1000; | |
386 | 386 | |
387 | 387 | int chunkNum = 21; |
388 | 388 | int chunkSize = size; |
406 | 406 | } |
407 | 407 | |
408 | 408 | m_connection->Send(buffer + sent, len); |
409 | int64 now = Util::GetCurrentTicks(); | |
409 | int64 now = Util::CurrentTicks(); | |
410 | 410 | if (now + pause * 1000 < m_start + expectedTime * 1000) |
411 | 411 | { |
412 | usleep(pause * 1000); | |
412 | Util::Sleep(pause); | |
413 | 413 | } |
414 | 414 | sent += len; |
415 | 415 | } |
64 | 64 | int m_id; |
65 | 65 | CString m_host; |
66 | 66 | int m_port; |
67 | int m_latency; | |
68 | int m_speed; | |
69 | CString m_dataDir; | |
70 | CString m_cacheDir; | |
71 | 67 | CString m_secureCert; |
72 | 68 | CString m_secureKey; |
73 | 69 | std::unique_ptr<Connection> m_connection; |
70 | CString m_dataDir; | |
71 | CString m_cacheDir; | |
72 | int m_latency; | |
73 | int m_speed; | |
74 | 74 | NntpCache* m_cache; |
75 | 75 | }; |
76 | 76 |
117 | 117 | for (int segno = 1; segno <= segmentCount; segno++) |
118 | 118 | { |
119 | 119 | int segSize = (int)(segOffset + m_segmentSize < fileSize ? m_segmentSize : fileSize - segOffset); |
120 | outfile.Print("<segment bytes=\"%i\" number=\"%i\">%s%s%s?%i=%lli:%i</segment>\n", | |
121 | m_segmentSize, segno, | |
120 | outfile.Print("<segment bytes=\"%i\" number=\"%i\">%s%s%s?%i=%" PRIi64 ":%i</segment>\n", | |
121 | m_segmentSize, segno, | |
122 | 122 | relativePath ? relativePath : "", |
123 | 123 | relativePath ? "/" : "", |
124 | FileSystem::BaseFileName(filename), segno, (long long)segOffset, (int)segSize); | |
124 | FileSystem::BaseFileName(filename), segno, segOffset, segSize); | |
125 | 125 | segOffset += segSize; |
126 | 126 | } |
127 | 127 |
63 | 63 | StringBuilder outbuf; |
64 | 64 | outbuf.Reserve(std::max(2048, std::min((int)(m_size * 1.1), 16 * 1024 * 1024))); |
65 | 65 | |
66 | outbuf.Append(CString::FormatStr("=ybegin part=%i line=128 size=%lli name=%s\r\n", m_part, (long long)m_fileSize, FileSystem::BaseFileName(m_filename))); | |
67 | outbuf.Append(CString::FormatStr("=ypart begin=%lli end=%lli\r\n", (long long)(m_offset + 1), (long long)(m_offset + m_size))); | |
66 | outbuf.Append(CString::FormatStr("=ybegin part=%i line=128 size=%" PRIi64 " name=%s\r\n", m_part, m_fileSize, FileSystem::BaseFileName(m_filename))); | |
67 | outbuf.Append(CString::FormatStr("=ypart begin=%" PRIi64 " end=%" PRIi64 "\r\n", m_offset + 1, m_offset + m_size)); | |
68 | 68 | |
69 | 69 | Crc32 crc; |
70 | 70 | CharBuffer inbuf(std::min(m_size, 16 * 1024 * 1024)); |
104 | 104 | { |
105 | 105 | break; |
106 | 106 | } |
107 | usleep(100 * 1000); | |
107 | Util::Sleep(100); | |
108 | 108 | } |
109 | 109 | } |
110 | 110 |
79 | 79 | curTime + timeoutSec > Util::CurrentTime() && |
80 | 80 | curTime >= Util::CurrentTime()) // in a case clock was changed |
81 | 81 | { |
82 | usleep(200 * 1000); | |
82 | Util::Sleep(200); | |
83 | 83 | } |
84 | 84 | |
85 | 85 | if (unrar.IsRunning()) |
90 | 90 | // wait until terminated or killed |
91 | 91 | while (unrar.IsRunning()) |
92 | 92 | { |
93 | usleep(200 * 1000); | |
93 | Util::Sleep(200); | |
94 | 94 | } |
95 | 95 | |
96 | 96 | *maxSize = unrar.m_maxSize; |
160 | 160 | char filename[1024]; |
161 | 161 | FindLargestFile(m_destDir, filename, sizeof(filename), &m_maxSize, &m_compressed); |
162 | 162 | bool sizeOK = SizeDiffOK(m_maxSize, m_expectedSize, 20); |
163 | PrintMessage(Message::mkDetail, "Found main file %s with size %lli bytes%s", | |
163 | PrintMessage(Message::mkDetail, "Found main file %s with size %" PRIi64 " bytes%s", | |
164 | 164 | filename, m_maxSize, sizeOK ? "" : ", size mismatch"); |
165 | 165 | return sizeOK; |
166 | 166 | } |
172 | 172 | char filename[1024]; |
173 | 173 | FindLargestFile(dupeDir, filename, sizeof(filename), &dupeMaxSize, &dupeCompressed); |
174 | 174 | bool ok = dupeMaxSize == m_maxSize && dupeCompressed == m_compressed; |
175 | PrintMessage(Message::mkDetail, "Found main file %s with size %lli bytes%s", | |
175 | PrintMessage(Message::mkDetail, "Found main file %s with size %" PRIi64 " bytes%s", | |
176 | 176 | filename, m_maxSize, ok ? "" : ", size mismatch"); |
177 | 177 | return ok; |
178 | 178 | } |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
41 | 41 | "internal error occurred", |
42 | 42 | "out of memory" }; |
43 | 43 | |
44 | // Sleep interval for synchronisation (microseconds) | |
45 | #ifdef WIN32 | |
46 | // Windows doesn't allow sleep intervals less than one millisecond | |
47 | #define SYNC_SLEEP_INTERVAL 1000 | |
48 | #else | |
49 | #define SYNC_SLEEP_INTERVAL 100 | |
50 | #endif | |
51 | ||
52 | 44 | class RepairThread; |
53 | 45 | |
54 | 46 | class Repairer : public Par2::Par2Repairer, public ParChecker::AbstractRepairer |
73 | 65 | private: |
74 | 66 | typedef vector<Thread*> Threads; |
75 | 67 | |
68 | ParChecker* m_owner; | |
76 | 69 | Par2::CommandLine commandLine; |
77 | ParChecker* m_owner; | |
78 | 70 | Threads m_threads; |
79 | 71 | bool m_parallel; |
80 | 72 | Mutex progresslock; |
82 | 74 | virtual void BeginRepair(); |
83 | 75 | virtual void EndRepair(); |
84 | 76 | void RepairBlock(Par2::u32 inputindex, Par2::u32 outputindex, size_t blocklength); |
77 | static void SyncSleep(); | |
85 | 78 | |
86 | 79 | friend class ParChecker; |
87 | 80 | friend class RepairThread; |
252 | 245 | |
253 | 246 | if (!jobAdded) |
254 | 247 | { |
255 | usleep(SYNC_SLEEP_INTERVAL); | |
248 | SyncSleep(); | |
256 | 249 | } |
257 | 250 | } |
258 | 251 | |
267 | 260 | if (repairThread->IsWorking()) |
268 | 261 | { |
269 | 262 | working = true; |
270 | usleep(SYNC_SLEEP_INTERVAL); | |
263 | SyncSleep(); | |
271 | 264 | break; |
272 | 265 | } |
273 | 266 | } |
304 | 297 | } |
305 | 298 | } |
306 | 299 | |
300 | // Sleep for synchronisation | |
301 | void Repairer::SyncSleep() | |
302 | { | |
303 | #ifdef WIN32 | |
304 | // Windows doesn't allow sleep intervals less than one millisecond | |
305 | Sleep(1); | |
306 | #else | |
307 | usleep(100); | |
308 | #endif | |
309 | } | |
310 | ||
307 | 311 | void RepairThread::Run() |
308 | 312 | { |
309 | 313 | while (!IsStopped()) |
315 | 319 | } |
316 | 320 | else |
317 | 321 | { |
318 | usleep(SYNC_SLEEP_INTERVAL); | |
322 | Repairer::SyncSleep(); | |
319 | 323 | } |
320 | 324 | } |
321 | 325 | } |
689 | 693 | Guard guard(m_queuedParFilesMutex); |
690 | 694 | queuedParFilesChanged = m_queuedParFilesChanged; |
691 | 695 | } |
692 | usleep(100 * 1000); | |
696 | Util::Sleep(100); | |
693 | 697 | } |
694 | 698 | } |
695 | 699 | } |
755 | 759 | Guard guard(m_queuedParFilesMutex); |
756 | 760 | queuedParFilesChanged = m_queuedParFilesChanged; |
757 | 761 | } |
758 | usleep(100 * 1000); | |
762 | Util::Sleep(100); | |
759 | 763 | } |
760 | 764 | } |
761 | 765 | } |
821 | 825 | DirBrowser dir(m_destDir); |
822 | 826 | while (const char* filename = dir.Next()) |
823 | 827 | { |
824 | if (IsParredFile(filename) && !IsProcessedFile(filename)) | |
828 | if (!IsParredFile(filename) && !IsProcessedFile(filename)) | |
825 | 829 | { |
826 | 830 | for (Par2::Par2RepairerSourceFile *sourcefile : GetRepairer()->sourcefiles) |
827 | 831 | { |
828 | 832 | std::string target = sourcefile->TargetFileName(); |
829 | const char* filename2 = target.c_str(); | |
830 | const char* basename2 = FileSystem::BaseFileName(filename2); | |
831 | int baseLen = strlen(basename2); | |
832 | ||
833 | if (!strncasecmp(filename, basename2, baseLen)) | |
833 | const char* current = FileSystem::BaseFileName(target.c_str()); | |
834 | ||
835 | // if file was renamed by par-renamer we also check the original filename | |
836 | const char* original = FindFileOrigname(current); | |
837 | ||
838 | if (MaybeSplittedFragement(filename, current) || | |
839 | (!Util::EmptyStr(original) && strcasecmp(original, current) && | |
840 | MaybeSplittedFragement(filename, original))) | |
834 | 841 | { |
835 | const char* p = filename + baseLen; | |
836 | if (*p == '.') | |
837 | { | |
838 | for (p++; *p && strchr("0123456789", *p); p++) ; | |
839 | if (!*p) | |
840 | { | |
841 | debug("Found splitted fragment %s", filename); | |
842 | BString<1024> fullfilename("%s%c%s", *m_destDir, PATH_SEPARATOR, filename); | |
843 | Par2::CommandLine::ExtraFile extrafile(*fullfilename, FileSystem::FileSize(fullfilename)); | |
844 | extrafiles.push_back(extrafile); | |
845 | } | |
846 | } | |
842 | detail("Found splitted fragment %s", filename); | |
843 | BString<1024> fullfilename("%s%c%s", *m_destDir, PATH_SEPARATOR, filename); | |
844 | Par2::CommandLine::ExtraFile extrafile(*fullfilename, FileSystem::FileSize(fullfilename)); | |
845 | extrafiles.push_back(extrafile); | |
846 | break; | |
847 | 847 | } |
848 | 848 | } |
849 | 849 | } |
862 | 862 | } |
863 | 863 | |
864 | 864 | return fragmentsAdded; |
865 | } | |
866 | ||
867 | bool ParChecker::MaybeSplittedFragement(const char* filename1, const char* filename2) | |
868 | { | |
869 | // check if name is same but the first name has additional numerical extension | |
870 | int len = strlen(filename2); | |
871 | if (!strncasecmp(filename1, filename2, len)) | |
872 | { | |
873 | const char* p = filename1 + len; | |
874 | if (*p == '.') | |
875 | { | |
876 | for (p++; *p && strchr("0123456789", *p); p++) ; | |
877 | if (!*p) | |
878 | { | |
879 | return true; | |
880 | } | |
881 | } | |
882 | } | |
883 | ||
884 | // check if same name (without extension) and extensions are numerical and exactly 3 characters long | |
885 | const char* ext1 = strrchr(filename1, '.'); | |
886 | const char* ext2 = strrchr(filename2, '.'); | |
887 | if (ext1 && ext2 && (strlen(ext1) == 4) && (strlen(ext2) == 4) && | |
888 | !strncasecmp(filename1, filename2, ext1 - filename1)) | |
889 | { | |
890 | for (ext1++; *ext1 && strchr("0123456789", *ext1); ext1++) ; | |
891 | for (ext2++; *ext2 && strchr("0123456789", *ext2); ext2++) ; | |
892 | if (!*ext1 && !*ext2) | |
893 | { | |
894 | return true; | |
895 | } | |
896 | } | |
897 | ||
898 | return false; | |
865 | 899 | } |
866 | 900 | |
867 | 901 | bool ParChecker::AddMissingFiles() |
1394 | 1428 | int64 blockEnd = blockStart + blocksize < fileSize - 1 ? blockStart + blocksize : fileSize - 1; |
1395 | 1429 | bool blockOK = false; |
1396 | 1430 | bool blockEndFound = false; |
1397 | Par2::u64 curOffset = 0; | |
1431 | int64 curOffset = 0; | |
1398 | 1432 | for (Segment& segment : segments) |
1399 | 1433 | { |
1400 | 1434 | if (!blockOK && segment.GetSuccess() && segment.GetOffset() <= blockStart && |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
131 | 131 | virtual void RegisterParredFile(const char* filename) {} |
132 | 132 | virtual bool IsParredFile(const char* filename) { return false; } |
133 | 133 | virtual EFileStatus FindFileCrc(const char* filename, uint32* crc, SegmentList* segments) { return fsUnknown; } |
134 | virtual const char* FindFileOrigname(const char* filename) { return nullptr; } | |
134 | 135 | virtual void RequestDupeSources(DupeSourceList* dupeSourceList) {} |
135 | 136 | virtual void StatDupeSources(DupeSourceList* dupeSourceList) {} |
136 | 137 | EStage GetStage() { return m_stage; } |
220 | 221 | bool DumbCalcFileRangeCrc(DiskFile& file, int64 start, int64 end, uint32* downloadCrc); |
221 | 222 | void CheckEmptyFiles(); |
222 | 223 | CString GetPacketCreator(); |
224 | bool MaybeSplittedFragement(const char* filename1, const char* filename2); | |
223 | 225 | |
224 | 226 | friend class Repairer; |
225 | 227 | }; |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2018 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
20 | 20 | #include "nzbget.h" |
21 | 21 | #include "PrePostProcessor.h" |
22 | 22 | #include "Options.h" |
23 | #include "WorkState.h" | |
23 | 24 | #include "Log.h" |
24 | 25 | #include "HistoryCoordinator.h" |
25 | 26 | #include "DupeCoordinator.h" |
48 | 49 | |
49 | 50 | while (!DownloadQueue::IsLoaded()) |
50 | 51 | { |
51 | usleep(20 * 1000); | |
52 | Util::Sleep(20); | |
52 | 53 | } |
53 | 54 | |
54 | 55 | if (g_Options->GetServerMode()) |
58 | 59 | |
59 | 60 | while (!IsStopped()) |
60 | 61 | { |
61 | if (!g_Options->GetTempPausePostprocess() && m_queuedJobs) | |
62 | if (g_WorkState->GetTempPausePostprocess()) | |
63 | { | |
64 | // Postprocess is paused: just wait and loop | |
65 | Util::Sleep(200); | |
66 | continue; | |
67 | } | |
68 | ||
69 | if (m_queuedJobs) | |
62 | 70 | { |
63 | 71 | // check post-queue every 200 msec |
64 | 72 | CheckPostQueue(); |
65 | } | |
66 | ||
67 | usleep(200 * 1000); | |
73 | Util::Sleep(200); | |
74 | } | |
75 | else | |
76 | { | |
77 | // Wait until we get the stop signal or more jobs in the queue | |
78 | Guard guard(m_waitMutex); | |
79 | m_waitCond.Wait(m_waitMutex, [&]{ return m_queuedJobs || IsStopped(); }); | |
80 | } | |
68 | 81 | } |
69 | 82 | |
70 | 83 | WaitJobs(); |
88 | 101 | } |
89 | 102 | } |
90 | 103 | CheckPostQueue(); |
91 | usleep(200 * 1000); | |
104 | Util::Sleep(200); | |
92 | 105 | } |
93 | 106 | |
94 | 107 | // kill remaining post-processing jobs; not safe but we can't wait any longer |
123 | 136 | break; |
124 | 137 | } |
125 | 138 | } |
126 | usleep(200 * 1000); | |
139 | Util::Sleep(200); | |
127 | 140 | } |
128 | 141 | |
129 | 142 | // disconnect remaining direct unpack jobs |
141 | 154 | void PrePostProcessor::Stop() |
142 | 155 | { |
143 | 156 | Thread::Stop(); |
144 | GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); | |
145 | ||
146 | for (NzbInfo* postJob : m_activeJobs) | |
147 | { | |
148 | if (postJob->GetPostInfo() && postJob->GetPostInfo()->GetPostThread()) | |
149 | { | |
150 | postJob->GetPostInfo()->GetPostThread()->Stop(); | |
151 | } | |
152 | } | |
153 | ||
154 | for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) | |
155 | { | |
156 | if (nzbInfo->GetUnpackThread()) | |
157 | { | |
158 | ((DirectUnpack*)nzbInfo->GetUnpackThread())->Stop(downloadQueue, nzbInfo); | |
159 | } | |
160 | } | |
157 | ||
158 | { | |
159 | GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); | |
160 | ||
161 | for (NzbInfo* postJob : m_activeJobs) | |
162 | { | |
163 | if (postJob->GetPostInfo() && postJob->GetPostInfo()->GetPostThread()) | |
164 | { | |
165 | postJob->GetPostInfo()->GetPostThread()->Stop(); | |
166 | } | |
167 | } | |
168 | ||
169 | for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) | |
170 | { | |
171 | if (nzbInfo->GetUnpackThread()) | |
172 | { | |
173 | ((DirectUnpack*)nzbInfo->GetUnpackThread())->Stop(downloadQueue, nzbInfo); | |
174 | } | |
175 | } | |
176 | } | |
177 | ||
178 | // Resume Run() to exit it | |
179 | Guard guard(m_waitMutex); | |
180 | m_waitCond.NotifyAll(); | |
161 | 181 | } |
162 | 182 | |
163 | 183 | /** |
323 | 343 | nzbInfo->PrintMessage(Message::mkInfo, "Queueing %s for post-processing", nzbInfo->GetName()); |
324 | 344 | |
325 | 345 | nzbInfo->EnterPostProcess(); |
326 | m_queuedJobs++; | |
327 | 346 | |
328 | 347 | if (nzbInfo->GetParStatus() == NzbInfo::psNone && |
329 | 348 | g_Options->GetParCheck() != Options::pcAlways && |
339 | 358 | ((DirectUnpack*)nzbInfo->GetUnpackThread())->NzbDownloaded(downloadQueue, nzbInfo); |
340 | 359 | } |
341 | 360 | |
342 | downloadQueue->Save(); | |
361 | nzbInfo->SetChanged(true); | |
362 | downloadQueue->SaveChanged(); | |
363 | ||
364 | // We have more jobs in the queue, notify Run() | |
365 | Guard guard(m_waitMutex); | |
366 | m_queuedJobs++; | |
367 | m_waitCond.NotifyAll(); | |
343 | 368 | } |
344 | 369 | else |
345 | 370 | { |
585 | 610 | !g_QueueScriptCoordinator->HasJob(nzbInfo1->GetId(), nullptr) && |
586 | 611 | nzbInfo1->GetDirectUnpackStatus() != NzbInfo::nsRunning && |
587 | 612 | (!nzbInfo || nzbInfo1->GetPriority() > nzbInfo->GetPriority()) && |
588 | (!g_Options->GetPausePostProcess() || nzbInfo1->GetForcePriority()) && | |
613 | (!g_WorkState->GetPausePostProcess() || nzbInfo1->GetForcePriority()) && | |
589 | 614 | (allowPar || !nzbInfo1->GetPostInfo()->GetNeedParCheck()) && |
590 | 615 | (std::find(m_activeJobs.begin(), m_activeJobs.end(), nzbInfo1) == m_activeJobs.end()) && |
591 | 616 | nzbInfo1->IsDownloadCompleted(true)) |
619 | 644 | |
620 | 645 | PostInfo* postInfo = postJob->GetPostInfo(); |
621 | 646 | if (postInfo->GetStage() == PostInfo::ptQueued && |
622 | (!g_Options->GetPausePostProcess() || postInfo->GetNzbInfo()->GetForcePriority())) | |
647 | (!g_WorkState->GetPausePostProcess() || postInfo->GetNzbInfo()->GetForcePriority())) | |
623 | 648 | { |
624 | 649 | StartJob(downloadQueue, postInfo, allowPar); |
625 | 650 | CheckRequestPar(downloadQueue); |
831 | 856 | NzbCompleted(downloadQueue, nzbInfo, false); |
832 | 857 | } |
833 | 858 | |
859 | Guard guard(m_waitMutex); | |
834 | 860 | m_queuedJobs--; |
835 | 861 | } |
836 | 862 | |
866 | 892 | } |
867 | 893 | } |
868 | 894 | |
869 | if (needPause && !g_Options->GetTempPauseDownload()) | |
895 | if (needPause && !g_WorkState->GetTempPauseDownload()) | |
870 | 896 | { |
871 | 897 | info("Pausing download before post-processing"); |
872 | 898 | } |
873 | else if (!needPause && g_Options->GetTempPauseDownload()) | |
899 | else if (!needPause && g_WorkState->GetTempPauseDownload()) | |
874 | 900 | { |
875 | 901 | info("Unpausing download after post-processing"); |
876 | 902 | } |
877 | 903 | |
878 | g_Options->SetTempPauseDownload(needPause); | |
904 | g_WorkState->SetTempPauseDownload(needPause); | |
879 | 905 | } |
880 | 906 | |
881 | 907 | bool PrePostProcessor::EditList(DownloadQueue* downloadQueue, IdList* idList, |
43 | 43 | private: |
44 | 44 | int m_queuedJobs = 0; |
45 | 45 | RawNzbList m_activeJobs; |
46 | Mutex m_waitMutex; | |
47 | ConditionVar m_waitCond; | |
46 | 48 | |
47 | 49 | void CheckPostQueue(); |
48 | 50 | void CheckRequestPar(DownloadQueue* downloadQueue); |
172 | 172 | uint8 buf[256]; |
173 | 173 | while (size > 0) |
174 | 174 | { |
175 | int64 len = size <= sizeof(buf) ? size : sizeof(buf); | |
175 | int64 len = size <= (int64)sizeof(buf) ? size : (int64)sizeof(buf); | |
176 | 176 | if (!Read(file, block, buf, len)) return false; |
177 | 177 | size -= len; |
178 | 178 | } |
288 | 288 | block.trailsize = blocksize - sizeof(buf) - 4; |
289 | 289 | } |
290 | 290 | |
291 | #ifdef DEBUG | |
291 | 292 | static int num = 0; |
292 | debug("%i) %llu, %i, %i, %i, %u, %llu", ++num, (long long)block.crc, (int)block.type, (int)block.flags, (int)size, (int)block.addsize, (long long)block.trailsize); | |
293 | debug("%i) %u, %i, %i, %i, %" PRIu64 ", %" PRIu64, ++num, block.crc, block.type, block.flags, size, block.addsize, block.trailsize); | |
294 | #endif | |
293 | 295 | |
294 | 296 | return block; |
295 | 297 | } |
449 | 451 | if ((block.flags & RAR5_BLOCK_DATAAREA) && !ReadV(file, &block, &datasize)) return {0}; |
450 | 452 | block.trailsize += datasize; |
451 | 453 | |
454 | #ifdef DEBUG | |
452 | 455 | static int num = 0; |
453 | debug("%i) %llu, %i, %i, %i, %u, %llu", ++num, (long long)block.crc, (int)block.type, (int)block.flags, (int)size, (int)block.addsize, (long long)block.trailsize); | |
456 | debug("%i) %u, %i, %i, %i, %" PRIu64 ", %" PRIu64, ++num, block.crc, block.type, block.flags, size, block.addsize, block.trailsize); | |
457 | #endif | |
454 | 458 | |
455 | 459 | return block; |
456 | 460 | } |
526 | 530 | } |
527 | 531 | } |
528 | 532 | |
529 | debug("%llu, %i, %s", (long long)block.trailsize, (int)namelen, (const char*)name); | |
533 | debug("%" PRIu64 ", %" PRIu64 ", %s", block.trailsize, namelen, (const char*)name); | |
530 | 534 | |
531 | 535 | return true; |
532 | 536 | } |
533 | 537 | |
534 | 538 | void RarVolume::LogDebugInfo() |
535 | 539 | { |
540 | #ifdef DEBUG | |
536 | 541 | debug("Volume: version:%i, multi:%i, vol-no:%i, new-naming:%i, has-next:%i, encrypted:%i, file-count:%i, [%s]", |
537 | 542 | (int)m_version, (int)m_multiVolume, m_volumeNo, (int)m_newNaming, (int)m_hasNextVolume, |
538 | 543 | (int)m_encrypted, (int)m_files.size(), FileSystem::BaseFileName(m_filename)); |
539 | 544 | |
540 | 545 | for (RarFile& file : m_files) |
541 | 546 | { |
542 | debug(" time:%i, size:%lli, attr:%i, split-before:%i, split-after:%i, [%s]", | |
543 | (int)file.m_time, (long long)file.m_size, (int)file.m_attr, | |
544 | (int)file.m_splitBefore, (int)file.m_splitAfter, *file.m_filename); | |
545 | } | |
547 | debug(" time:%i, size:%" PRIi64 ", attr:%i, split-before:%i, split-after:%i, [%s]", | |
548 | file.m_time, file.m_size, file.m_attr, | |
549 | file.m_splitBefore, file.m_splitAfter, *file.m_filename); | |
550 | } | |
551 | #endif | |
546 | 552 | } |
547 | 553 | |
548 | 554 | bool RarVolume::DecryptRar3Prepare(const uint8 salt[8]) |
272 | 272 | }), |
273 | 273 | m_sets.end()); |
274 | 274 | |
275 | #ifdef DEBUG | |
275 | 276 | // debug log |
276 | 277 | for (RarVolumeSet& set : m_sets) |
277 | 278 | { |
281 | 282 | debug(" %s", FileSystem::BaseFileName(volume->GetFilename())); |
282 | 283 | } |
283 | 284 | } |
285 | #endif | |
284 | 286 | } |
285 | 287 | |
286 | 288 | bool RarRenamer::SameArchiveName(const char* filename1, const char* filename2, bool newNaming) |
345 | 347 | { |
346 | 348 | setPartLen = partNo.Length(); |
347 | 349 | } |
348 | bool ok = atoi(partNo) == volume->GetVolumeNo() + 1 && | |
350 | bool ok = (uint32)atoi(partNo) == volume->GetVolumeNo() + 1 && | |
349 | 351 | partNo.Length() == setPartLen && |
350 | 352 | !strncmp(setBasename, filename, regExPart.GetMatchStart(1)); |
351 | 353 | if (!ok) |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2016-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
212 | 212 | { |
213 | 213 | if (!strcasecmp(completedFile.GetFilename(), oldFilename)) |
214 | 214 | { |
215 | if (Util::EmptyStr(completedFile.GetOrigname())) | |
216 | { | |
217 | completedFile.SetOrigname(completedFile.GetFilename()); | |
218 | } | |
215 | 219 | completedFile.SetFilename(newFilename); |
216 | 220 | break; |
217 | 221 | } |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
22 | 22 | #include "DupeCoordinator.h" |
23 | 23 | #include "ParParser.h" |
24 | 24 | #include "Options.h" |
25 | #include "WorkState.h" | |
25 | 26 | #include "DiskState.h" |
26 | 27 | #include "Log.h" |
27 | 28 | #include "FileSystem.h" |
111 | 112 | completedFile->GetStatus() == CompletedFile::cfPartial && segments->size() > 0 && |
112 | 113 | !m_postInfo->GetNzbInfo()->GetReprocess()? ParChecker::fsPartial : |
113 | 114 | ParChecker::fsUnknown; |
115 | } | |
116 | ||
117 | const char* RepairController::PostParChecker::FindFileOrigname(const char* filename) | |
118 | { | |
119 | for (CompletedFile& completedFile : m_postInfo->GetNzbInfo()->GetCompletedFiles()) | |
120 | { | |
121 | if (!strcasecmp(completedFile.GetFilename(), filename)) | |
122 | { | |
123 | return completedFile.GetOrigname(); | |
124 | } | |
125 | } | |
126 | ||
127 | return nullptr; | |
114 | 128 | } |
115 | 129 | |
116 | 130 | void RepairController::PostParChecker::RequestDupeSources(DupeSourceList* dupeSourceList) |
518 | 532 | |
519 | 533 | void RepairController::CheckPauseState(PostInfo* postInfo) |
520 | 534 | { |
521 | if (g_Options->GetPausePostProcess() && !postInfo->GetNzbInfo()->GetForcePriority()) | |
535 | if (g_WorkState->GetPausePostProcess() && !postInfo->GetNzbInfo()->GetForcePriority()) | |
522 | 536 | { |
523 | 537 | time_t stageTime = postInfo->GetStageTime(); |
524 | 538 | time_t startTime = postInfo->GetStartTime(); |
527 | 541 | time_t waitTime = Util::CurrentTime(); |
528 | 542 | |
529 | 543 | // wait until Post-processor is unpaused |
530 | while (g_Options->GetPausePostProcess() && !postInfo->GetNzbInfo()->GetForcePriority() && !IsStopped()) | |
531 | { | |
532 | usleep(50 * 1000); | |
544 | while (g_WorkState->GetPausePostProcess() && !postInfo->GetNzbInfo()->GetForcePriority() && !IsStopped()) | |
545 | { | |
546 | Util::Sleep(50); | |
533 | 547 | |
534 | 548 | // update time stamps |
535 | 549 |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
67 | 67 | virtual void RegisterParredFile(const char* filename); |
68 | 68 | virtual bool IsParredFile(const char* filename); |
69 | 69 | virtual EFileStatus FindFileCrc(const char* filename, uint32* crc, SegmentList* segments); |
70 | virtual const char* FindFileOrigname(const char* filename); | |
70 | 71 | virtual void RequestDupeSources(DupeSourceList* dupeSourceList); |
71 | 72 | virtual void StatDupeSources(DupeSourceList* dupeSourceList); |
72 | 73 | private: |
873 | 873 | |
874 | 874 | if (m_unpacker == upUnrar && !strncmp(text, "Unrar: Extracting from ", 23)) |
875 | 875 | { |
876 | #ifdef DEBUG | |
876 | 877 | const char *filename = text + 23; |
877 | 878 | debug("Filename: %s", filename); |
879 | #endif | |
878 | 880 | SetProgressLabel(text + 7); |
879 | 881 | } |
880 | 882 |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2017-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
207 | 207 | fileInfo->SetPaused(false); |
208 | 208 | } |
209 | 209 | |
210 | downloadQueue->Save(); | |
210 | nzbInfo->SetChanged(true); | |
211 | downloadQueue->SaveChanged(); | |
211 | 212 | } |
212 | 213 | |
213 | 214 | if (fileInfo->GetParFile()) |
257 | 258 | // all first articles downloaded |
258 | 259 | UnpausePars(nzbInfo); |
259 | 260 | nzbInfo->SetWaitingPar(true); |
260 | downloadQueue->Save(); | |
261 | nzbInfo->SetChanged(true); | |
262 | downloadQueue->SaveChanged(); | |
261 | 263 | } |
262 | 264 | |
263 | 265 | if (nzbInfo->GetWaitingPar() && !nzbInfo->GetLoadingPar()) |
375 | 377 | { |
376 | 378 | nzbInfo->PrintMessage(Message::mkInfo, "Renaming in-progress file %s to %s", |
377 | 379 | fileInfo->GetFilename(), *newName); |
380 | if (Util::EmptyStr(fileInfo->GetOrigname())) | |
381 | { | |
382 | fileInfo->SetOrigname(fileInfo->GetFilename()); | |
383 | } | |
378 | 384 | fileInfo->SetFilename(newName); |
379 | 385 | fileInfo->SetFilenameConfirmed(true); |
380 | 386 | renamedCount++; |
381 | 387 | } |
382 | 388 | else if (RenameCompletedFile(nzbInfo, fileInfo->GetFilename(), newName)) |
383 | 389 | { |
390 | if (Util::EmptyStr(fileInfo->GetOrigname())) | |
391 | { | |
392 | fileInfo->SetOrigname(fileInfo->GetFilename()); | |
393 | } | |
384 | 394 | fileInfo->SetFilename(newName); |
385 | 395 | fileInfo->SetFilenameConfirmed(true); |
386 | 396 | renamedCount++; |
403 | 413 | |
404 | 414 | if (newName && RenameCompletedFile(nzbInfo, completedFile.GetFilename(), newName)) |
405 | 415 | { |
416 | if (Util::EmptyStr(completedFile.GetOrigname())) | |
417 | { | |
418 | completedFile.SetOrigname(completedFile.GetFilename()); | |
419 | } | |
406 | 420 | completedFile.SetFilename(newName); |
407 | 421 | renamedCount++; |
408 | 422 | } |
522 | 536 | void RenameContentAnalyzer::Append(const void* buffer, int len) |
523 | 537 | { |
524 | 538 | #ifndef DISABLE_PARCHECK |
525 | if (m_dataSize < sizeof(m_signature)) | |
539 | if ((size_t)m_dataSize < sizeof(m_signature)) | |
526 | 540 | { |
527 | 541 | memcpy(m_signature + m_dataSize, buffer, std::min((size_t)len, sizeof(m_signature) - m_dataSize)); |
528 | 542 | } |
529 | 543 | |
530 | if (m_dataSize >= sizeof(m_signature) && (*(Par2::MAGIC*)m_signature) == Par2::packet_magic) | |
544 | if ((size_t)m_dataSize >= sizeof(m_signature) && (*(Par2::MAGIC*)m_signature) == Par2::packet_magic) | |
531 | 545 | { |
532 | 546 | m_parFile = true; |
533 | 547 | m_parSetId = ((Par2::PACKET_HEADER*)m_signature)->setid.print().c_str(); |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2018 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
26 | 26 | #include "FileSystem.h" |
27 | 27 | |
28 | 28 | static const char* FORMATVERSION_SIGNATURE = "nzbget diskstate file version "; |
29 | const int DISKSTATE_QUEUE_VERSION = 61; | |
30 | const int DISKSTATE_FILE_VERSION = 5; | |
29 | const int DISKSTATE_QUEUE_VERSION = 62; | |
30 | const int DISKSTATE_FILE_VERSION = 6; | |
31 | 31 | const int DISKSTATE_STATS_VERSION = 3; |
32 | 32 | const int DISKSTATE_FEEDS_VERSION = 3; |
33 | 33 | |
44 | 44 | { |
45 | 45 | va_list ap; |
46 | 46 | va_start(ap, format); |
47 | CString str; | |
48 | str.FormatV(format, ap); | |
47 | BString<1024> str; | |
48 | int len = str.FormatV(format, ap); | |
49 | 49 | va_end(ap); |
50 | ||
51 | int len = str.Length(); | |
52 | 50 | |
53 | 51 | // replacing terminating <NULL> with <LF> |
54 | 52 | str[len++] = '\n'; |
116 | 114 | private: |
117 | 115 | BString<1024> m_destFilename; |
118 | 116 | BString<1024> m_tempFilename; |
117 | int m_formatVersion; | |
119 | 118 | bool m_transactional; |
120 | int m_formatVersion; | |
121 | 119 | int m_fileVersion; |
122 | 120 | StateDiskFile m_file; |
123 | 121 | |
312 | 310 | } |
313 | 311 | } |
314 | 312 | |
313 | // progress-file isn't needed after saving of full queue data | |
314 | StateFile progressStateFile("progress", DISKSTATE_QUEUE_VERSION, true); | |
315 | progressStateFile.Discard(); | |
316 | ||
315 | 317 | return ok; |
316 | 318 | } |
317 | 319 | |
334 | 336 | |
335 | 337 | formatVersion = stateFile.GetFileVersion(); |
336 | 338 | |
337 | if (formatVersion < 47) | |
339 | if (formatVersion <= 0) | |
340 | { | |
341 | error("Failed to read queue: diskstate file is corrupted"); | |
342 | goto error; | |
343 | } | |
344 | else if (formatVersion < 47) | |
338 | 345 | { |
339 | 346 | error("Failed to read queue and history data. Only queue and history from NZBGet v13 or newer can be converted by this NZBGet version. " |
340 | 347 | "Old queue and history data still can be converted using NZBGet v16 as an intermediate version."); |
350 | 357 | } |
351 | 358 | } |
352 | 359 | |
360 | { | |
361 | StateFile stateFile("progress", DISKSTATE_QUEUE_VERSION, true); | |
362 | if (stateFile.FileExists()) | |
363 | { | |
364 | StateDiskFile* infile = stateFile.BeginRead(); | |
365 | if (!infile) | |
366 | { | |
367 | return false; | |
368 | } | |
369 | ||
370 | if (stateFile.GetFileVersion() <= 0) | |
371 | { | |
372 | error("Failed to read queue: diskstate file is corrupted"); | |
373 | goto error; | |
374 | } | |
375 | ||
376 | if (!LoadProgress(downloadQueue->GetQueue(), servers, *infile, stateFile.GetFileVersion())) goto error; | |
377 | } | |
378 | } | |
379 | ||
353 | 380 | if (formatVersion == 0 || formatVersion >= 57) |
354 | 381 | { |
355 | 382 | StateFile stateFile("history", DISKSTATE_QUEUE_VERSION, true); |
360 | 387 | { |
361 | 388 | return false; |
362 | 389 | } |
390 | ||
391 | if (stateFile.GetFileVersion() <= 0) | |
392 | { | |
393 | error("Failed to read queue: diskstate file is corrupted"); | |
394 | goto error; | |
395 | } | |
396 | ||
363 | 397 | if (!LoadHistory(downloadQueue->GetHistory(), servers, *infile, stateFile.GetFileVersion())) goto error; |
364 | 398 | } |
365 | 399 | } |
383 | 417 | FileInfo::ResetGenId(true); |
384 | 418 | |
385 | 419 | CalcFileStats(downloadQueue, formatVersion); |
420 | ||
421 | return ok; | |
422 | } | |
423 | ||
424 | bool DiskState::SaveDownloadProgress(DownloadQueue* downloadQueue) | |
425 | { | |
426 | int count = 0; | |
427 | for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) | |
428 | { | |
429 | count += nzbInfo->GetChanged() ? 1 : 0; | |
430 | } | |
431 | ||
432 | debug("Saving queue progress to disk"); | |
433 | ||
434 | bool ok = true; | |
435 | ||
436 | { | |
437 | StateFile stateFile("progress", DISKSTATE_QUEUE_VERSION, true); | |
438 | if (count > 0) | |
439 | { | |
440 | StateDiskFile* outfile = stateFile.BeginWrite(); | |
441 | if (!outfile) | |
442 | { | |
443 | return false; | |
444 | } | |
445 | ||
446 | SaveProgress(downloadQueue->GetQueue(), *outfile, count); | |
447 | ||
448 | // now rename to dest file name | |
449 | ok = stateFile.FinishWrite(); | |
450 | } | |
451 | else | |
452 | { | |
453 | stateFile.Discard(); | |
454 | } | |
455 | } | |
386 | 456 | |
387 | 457 | return ok; |
388 | 458 | } |
416 | 486 | |
417 | 487 | error: |
418 | 488 | error("Error reading nzb list from disk"); |
489 | return false; | |
490 | } | |
491 | ||
492 | void DiskState::SaveProgress(NzbList* queue, StateDiskFile& outfile, int changedCount) | |
493 | { | |
494 | debug("Saving nzb progress to disk"); | |
495 | ||
496 | outfile.PrintLine("%i", changedCount); | |
497 | for (NzbInfo* nzbInfo : queue) | |
498 | { | |
499 | if (nzbInfo->GetChanged()) | |
500 | { | |
501 | outfile.PrintLine("%i", nzbInfo->GetId()); | |
502 | SaveNzbInfo(nzbInfo, outfile); | |
503 | } | |
504 | } | |
505 | } | |
506 | ||
507 | bool DiskState::LoadProgress(NzbList* queue, Servers* servers, StateDiskFile& infile, int formatVersion) | |
508 | { | |
509 | debug("Loading nzb progress from disk"); | |
510 | ||
511 | // load nzb-infos | |
512 | int size; | |
513 | if (infile.ScanLine("%i", &size) != 1) goto error; | |
514 | for (int i = 0; i < size; i++) | |
515 | { | |
516 | int id; | |
517 | if (infile.ScanLine("%i", &id) != 1) goto error; | |
518 | ||
519 | NzbInfo* nzbInfo = queue->Find(id); | |
520 | if (!nzbInfo) | |
521 | { | |
522 | error("NZB with id %i could not be found", id); | |
523 | goto error; | |
524 | } | |
525 | ||
526 | if (!LoadNzbInfo(nzbInfo, servers, infile, formatVersion)) goto error; | |
527 | } | |
528 | ||
529 | return true; | |
530 | ||
531 | error: | |
532 | error("Error reading nzb progress from disk"); | |
419 | 533 | return false; |
420 | 534 | } |
421 | 535 | |
472 | 586 | outfile.PrintLine("%i", (int)nzbInfo->GetCompletedFiles()->size()); |
473 | 587 | for (CompletedFile& completedFile : nzbInfo->GetCompletedFiles()) |
474 | 588 | { |
475 | outfile.PrintLine("%i,%i,%u,%i,%s,%s,%s", completedFile.GetId(), (int)completedFile.GetStatus(), | |
589 | outfile.PrintLine("%i,%i,%u,%i,%s,%s", completedFile.GetId(), (int)completedFile.GetStatus(), | |
476 | 590 | completedFile.GetCrc(), (int)completedFile.GetParFile(), |
477 | 591 | completedFile.GetHash16k() ? completedFile.GetHash16k() : "", |
478 | completedFile.GetParSetId() ? completedFile.GetParSetId() : "", | |
479 | completedFile.GetFilename()); | |
592 | completedFile.GetParSetId() ? completedFile.GetParSetId() : ""); | |
593 | outfile.PrintLine("%s", completedFile.GetFilename()); | |
594 | outfile.PrintLine("%s", completedFile.GetOrigname() ? completedFile.GetOrigname() : ""); | |
480 | 595 | } |
481 | 596 | |
482 | 597 | outfile.PrintLine("%i", (int)nzbInfo->GetParameters()->size()); |
715 | 830 | nzbInfo->SetUnpackSec(unpackSec); |
716 | 831 | } |
717 | 832 | |
833 | nzbInfo->GetCompletedFiles()->clear(); | |
718 | 834 | if (infile.ScanLine("%i", &fileCount) != 1) goto error; |
719 | 835 | for (int i = 0; i < fileCount; i++) |
720 | 836 | { |
727 | 843 | int parFile = 0; |
728 | 844 | char* hash16k = nullptr; |
729 | 845 | char* parSetId = nullptr; |
846 | char filenameBuf[1024]; | |
847 | char origName[1024]; | |
730 | 848 | |
731 | 849 | if (formatVersion >= 49) |
732 | 850 | { |
764 | 882 | { |
765 | 883 | fileName++; |
766 | 884 | } |
885 | if (formatVersion >= 62) | |
886 | { | |
887 | if (!infile.ReadLine(filenameBuf, sizeof(filenameBuf))) goto error; | |
888 | fileName = filenameBuf; | |
889 | if (!infile.ReadLine(origName, sizeof(origName))) goto error; | |
890 | } | |
767 | 891 | } |
768 | 892 | |
769 | 893 | nzbInfo->GetCompletedFiles()->emplace_back(id, fileName, |
894 | Util::EmptyStr(origName) ? nullptr : origName, | |
770 | 895 | (CompletedFile::EStatus)status, crc, (bool)parFile, |
771 | 896 | Util::EmptyStr(hash16k) ? nullptr : hash16k, |
772 | 897 | Util::EmptyStr(parSetId) ? nullptr : parSetId); |
773 | 898 | } |
774 | 899 | |
900 | nzbInfo->GetParameters()->clear(); | |
775 | 901 | int parameterCount; |
776 | 902 | if (infile.ScanLine("%i", ¶meterCount) != 1) goto error; |
777 | 903 | for (int i = 0; i < parameterCount; i++) |
787 | 913 | } |
788 | 914 | } |
789 | 915 | |
916 | nzbInfo->GetScriptStatuses()->clear(); | |
790 | 917 | int scriptCount; |
791 | 918 | if (infile.ScanLine("%i", &scriptCount) != 1) goto error; |
792 | 919 | for (int i = 0; i < scriptCount; i++) |
816 | 943 | } |
817 | 944 | } |
818 | 945 | |
946 | nzbInfo->GetFileList()->clear(); | |
819 | 947 | if (infile.ScanLine("%i", &fileCount) != 1) goto error; |
820 | 948 | for (int i = 0; i < fileCount; i++) |
821 | 949 | { |
908 | 1036 | { |
909 | 1037 | outfile.PrintLine("%s", fileInfo->GetSubject()); |
910 | 1038 | outfile.PrintLine("%s", fileInfo->GetFilename()); |
1039 | outfile.PrintLine("%s", fileInfo->GetOrigname() ? fileInfo->GetOrigname() : ""); | |
911 | 1040 | |
912 | 1041 | outfile.PrintLine("%i,%i", (int)fileInfo->GetFilenameConfirmed(), (int)fileInfo->GetTime()); |
913 | 1042 | |
970 | 1099 | |
971 | 1100 | if (!infile.ReadLine(buf, sizeof(buf))) goto error; |
972 | 1101 | if (fileSummary) fileInfo->SetFilename(buf); |
1102 | ||
1103 | if (formatVersion >= 6) | |
1104 | { | |
1105 | if (!infile.ReadLine(buf, sizeof(buf))) goto error; | |
1106 | if (fileSummary) fileInfo->SetOrigname(Util::EmptyStr(buf) ? nullptr : buf); | |
1107 | } | |
973 | 1108 | |
974 | 1109 | if (formatVersion >= 5) |
975 | 1110 | { |
1063 | 1198 | outfile.PrintLine("%u,%u,%u,%u,%u,%u", High1, Low1, High2, Low2, High3, Low3); |
1064 | 1199 | |
1065 | 1200 | outfile.PrintLine("%s", fileInfo->GetFilename()); |
1066 | outfile.PrintLine("%s", fileInfo->GetHash16k()); | |
1201 | outfile.PrintLine("%s", fileInfo->GetHash16k() ? fileInfo->GetHash16k() : ""); | |
1202 | outfile.PrintLine("%s", fileInfo->GetParSetId() ? fileInfo->GetParSetId() : ""); | |
1067 | 1203 | outfile.PrintLine("%i", (int)fileInfo->GetParFile()); |
1068 | 1204 | |
1069 | 1205 | SaveServerStats(fileInfo->GetServerStats(), outfile); |
1122 | 1258 | { |
1123 | 1259 | if (!infile.ReadLine(buf, sizeof(buf))) goto error; |
1124 | 1260 | fileInfo->SetHash16k(*buf ? buf : nullptr); |
1261 | if (formatVersion >= 6) | |
1262 | { | |
1263 | if (!infile.ReadLine(buf, sizeof(buf))) goto error; | |
1264 | fileInfo->SetParSetId(*buf ? buf : nullptr); | |
1265 | } | |
1125 | 1266 | int parFile = 0; |
1126 | 1267 | if (infile.ScanLine("%i", &parFile) != 1) goto error; |
1127 | 1268 | fileInfo->SetParFile((bool)parFile); |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
35 | 35 | bool DownloadQueueExists(); |
36 | 36 | bool SaveDownloadQueue(DownloadQueue* downloadQueue, bool saveHistory); |
37 | 37 | bool LoadDownloadQueue(DownloadQueue* downloadQueue, Servers* servers); |
38 | bool SaveDownloadProgress(DownloadQueue* downloadQueue); | |
38 | 39 | bool SaveFile(FileInfo* fileInfo); |
39 | 40 | bool LoadFile(FileInfo* fileInfo, bool fileSummary, bool articles); |
40 | 41 | bool SaveAllFileInfos(DownloadQueue* downloadQueue); |
62 | 63 | bool LoadFileState(FileInfo* fileInfo, Servers* servers, StateDiskFile& infile, int formatVersion, bool completed); |
63 | 64 | void SaveQueue(NzbList* queue, StateDiskFile& outfile); |
64 | 65 | bool LoadQueue(NzbList* queue, Servers* servers, StateDiskFile& infile, int formatVersion); |
66 | void SaveProgress(NzbList* queue, StateDiskFile& outfile, int changedCount); | |
67 | bool LoadProgress(NzbList* queue, Servers* servers, StateDiskFile& infile, int formatVersion); | |
65 | 68 | void SaveNzbInfo(NzbInfo* nzbInfo, StateDiskFile& outfile); |
66 | 69 | bool LoadNzbInfo(NzbInfo* nzbInfo, Servers* servers, StateDiskFile& infile, int formatVersion); |
67 | 70 | void SaveDupInfo(DupInfo* dupInfo, StateDiskFile& outfile); |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
837 | 837 | } |
838 | 838 | |
839 | 839 | |
840 | CompletedFile::CompletedFile(int id, const char* filename, EStatus status, uint32 crc, | |
841 | bool parFile, const char* hash16k, const char* parSetId) : | |
842 | m_id(id), m_filename(filename), m_status(status), m_crc(crc), m_parFile(parFile), | |
843 | m_hash16k(hash16k), m_parSetId(parSetId) | |
840 | CompletedFile::CompletedFile(int id, const char* filename, const char* origname, EStatus status, | |
841 | uint32 crc, bool parFile, const char* hash16k, const char* parSetId) : | |
842 | m_id(id), m_filename(filename), m_origname(origname), m_status(status), | |
843 | m_crc(crc), m_parFile(parFile), m_hash16k(hash16k), m_parSetId(parSetId) | |
844 | 844 | { |
845 | 845 | if (FileInfo::m_idMax < m_id) |
846 | 846 | { |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2018 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
139 | 139 | void SetSubject(const char* subject) { m_subject = subject; } |
140 | 140 | const char* GetFilename() { return m_filename; } |
141 | 141 | void SetFilename(const char* filename) { m_filename = filename; } |
142 | void SetOrigname(const char* origname) { m_origname = origname; } | |
143 | const char* GetOrigname() { return m_origname; } | |
142 | 144 | void MakeValidFilename(); |
143 | 145 | bool GetFilenameConfirmed() { return m_filenameConfirmed; } |
144 | 146 | void SetFilenameConfirmed(bool filenameConfirmed) { m_filenameConfirmed = filenameConfirmed; } |
208 | 210 | ServerStatList m_serverStats; |
209 | 211 | CString m_subject; |
210 | 212 | CString m_filename; |
213 | CString m_origname; | |
211 | 214 | int64 m_size = 0; |
212 | 215 | int64 m_remainingSize = 0; |
213 | 216 | int64 m_successSize = 0; |
258 | 261 | cfFailure |
259 | 262 | }; |
260 | 263 | |
261 | CompletedFile(int id, const char* filename, EStatus status, uint32 crc, | |
262 | bool parFile, const char* hash16k, const char* parSetId); | |
264 | CompletedFile(int id, const char* filename, const char* oldname, EStatus status, | |
265 | uint32 crc, bool parFile, const char* hash16k, const char* parSetId); | |
263 | 266 | int GetId() { return m_id; } |
264 | 267 | void SetFilename(const char* filename) { m_filename = filename; } |
265 | 268 | const char* GetFilename() { return m_filename; } |
269 | void SetOrigname(const char* origname) { m_origname = origname; } | |
270 | const char* GetOrigname() { return m_origname; } | |
266 | 271 | bool GetParFile() { return m_parFile; } |
267 | 272 | EStatus GetStatus() { return m_status; } |
268 | 273 | uint32 GetCrc() { return m_crc; } |
274 | 279 | private: |
275 | 280 | int m_id; |
276 | 281 | CString m_filename; |
282 | CString m_origname; | |
277 | 283 | EStatus m_status; |
278 | 284 | uint32 m_crc; |
279 | 285 | bool m_parFile; |
894 | 900 | }; |
895 | 901 | |
896 | 902 | HistoryInfo(std::unique_ptr<NzbInfo> nzbInfo) : m_info(nzbInfo.release()), |
897 | m_kind(nzbInfo->GetKind() == NzbInfo::nkNzb ? hkNzb : hkUrl) {} | |
903 | m_kind(GetNzbInfo()->GetKind() == NzbInfo::nkNzb ? hkNzb : hkUrl) {} | |
898 | 904 | HistoryInfo(std::unique_ptr<DupInfo> dupInfo) : m_info(dupInfo.release()), m_kind(hkDup) {} |
899 | 905 | ~HistoryInfo(); |
900 | 906 | EKind GetKind() { return m_kind; } |
907 | 913 | const char* GetName(); |
908 | 914 | |
909 | 915 | private: |
916 | void* m_info; | |
910 | 917 | EKind m_kind; |
911 | void* m_info; | |
912 | 918 | time_t m_time = 0; |
913 | 919 | }; |
914 | 920 | |
925 | 931 | eaNzbAdded, |
926 | 932 | eaNzbDeleted, |
927 | 933 | eaNzbNamed, |
934 | eaNzbReturned, | |
928 | 935 | eaFileCompleted, |
929 | 936 | eaFileDeleted, |
930 | 937 | eaUrlFound, |
931 | 938 | eaUrlAdded, |
932 | 939 | eaUrlDeleted, |
933 | 940 | eaUrlCompleted, |
934 | eaUrlFailed | |
941 | eaUrlFailed, | |
942 | eaUrlReturned | |
935 | 943 | }; |
936 | 944 | |
937 | 945 | struct Aspect |
1012 | 1020 | virtual bool EditList(IdList* idList, NameList* nameList, EMatchMode matchMode, EEditAction action, const char* args) = 0; |
1013 | 1021 | virtual void HistoryChanged() = 0; |
1014 | 1022 | virtual void Save() = 0; |
1023 | virtual void SaveChanged() = 0; | |
1015 | 1024 | void CalcRemainingSize(int64* remaining, int64* remainingForced); |
1016 | 1025 | |
1017 | 1026 | protected: |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2018 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
130 | 130 | { |
131 | 131 | nzbInfo->UpdateCompletedStats(fileInfo); |
132 | 132 | nzbInfo->GetCompletedFiles()->emplace_back(fileInfo->GetId(), fileInfo->GetFilename(), |
133 | CompletedFile::cfNone, 0, fileInfo->GetParFile(), fileInfo->GetHash16k(), fileInfo->GetParSetId()); | |
133 | fileInfo->GetOrigname(), CompletedFile::cfNone, 0, fileInfo->GetParFile(), | |
134 | fileInfo->GetHash16k(), fileInfo->GetParSetId()); | |
134 | 135 | } |
135 | 136 | |
136 | 137 | // Cleaning up parked files if par-check was successful or unpack was successful or |
422 | 423 | // start postprocessing |
423 | 424 | debug("Restarting postprocessing for %s", *nicename); |
424 | 425 | g_PrePostProcessor->NzbDownloaded(downloadQueue, nzbInfo); |
426 | DownloadQueue::Aspect aspect = {DownloadQueue::eaNzbReturned, downloadQueue, nzbInfo, nullptr}; | |
427 | downloadQueue->Notify(&aspect); | |
425 | 428 | } |
426 | 429 | } |
427 | 430 | |
437 | 440 | nzbInfo->SetDupeHint(nzbInfo->GetDupeHint() == NzbInfo::dhNone ? NzbInfo::dhRedownloadManual : nzbInfo->GetDupeHint()); |
438 | 441 | downloadQueue->GetQueue()->Add(std::unique_ptr<NzbInfo>(nzbInfo), true); |
439 | 442 | downloadQueue->GetHistory()->erase(itHistory); |
443 | ||
444 | DownloadQueue::Aspect aspect = {DownloadQueue::eaUrlReturned, downloadQueue, nzbInfo, nullptr}; | |
445 | downloadQueue->Notify(&aspect); | |
446 | ||
440 | 447 | return; |
441 | 448 | } |
442 | 449 | |
524 | 531 | MoveToQueue(downloadQueue, itHistory, historyInfo, false); |
525 | 532 | |
526 | 533 | g_PrePostProcessor->NzbAdded(downloadQueue, nzbInfo); |
534 | ||
535 | DownloadQueue::Aspect aspect = {DownloadQueue::eaNzbReturned, downloadQueue, nzbInfo, nullptr}; | |
536 | downloadQueue->Notify(&aspect); | |
527 | 537 | } |
528 | 538 | |
529 | 539 | void HistoryCoordinator::HistoryReturn(DownloadQueue* downloadQueue, HistoryList::iterator itHistory, |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
33 | 33 | void Redownload(DownloadQueue* downloadQueue, HistoryInfo* historyInfo); |
34 | 34 | |
35 | 35 | protected: |
36 | virtual int ServiceInterval() { return 600000; } | |
36 | virtual int ServiceInterval() { return 60 * 60; } | |
37 | 37 | virtual void ServiceWork(); |
38 | 38 | |
39 | 39 | private: |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net> |
4 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
21 | 21 | #include "nzbget.h" |
22 | 22 | #include "QueueCoordinator.h" |
23 | 23 | #include "Options.h" |
24 | #include "WorkState.h" | |
24 | 25 | #include "ServerPool.h" |
25 | 26 | #include "ArticleDownloader.h" |
26 | 27 | #include "ArticleWriter.h" |
70 | 71 | |
71 | 72 | m_wantSave = false; |
72 | 73 | m_historyChanged = false; |
74 | ||
75 | // queue has changed, time to wake up if in standby | |
76 | m_owner->WakeUp(); | |
77 | } | |
78 | ||
79 | void QueueCoordinator::CoordinatorDownloadQueue::SaveChanged() | |
80 | { | |
81 | if (g_Options->GetServerMode()) | |
82 | { | |
83 | g_DiskState->SaveDownloadProgress(this); | |
84 | m_stateChanged = true; | |
85 | } | |
73 | 86 | } |
74 | 87 | |
75 | 88 | QueueCoordinator::QueueCoordinator() |
77 | 90 | debug("Creating QueueCoordinator"); |
78 | 91 | |
79 | 92 | CoordinatorDownloadQueue::Init(&m_downloadQueue); |
93 | g_WorkState->Attach(this); | |
80 | 94 | } |
81 | 95 | |
82 | 96 | QueueCoordinator::~QueueCoordinator() |
178 | 192 | bool articeDownloadsRunning = false; |
179 | 193 | time_t lastReset = 0; |
180 | 194 | g_StatMeter->IntervalCheck(); |
195 | int waitInterval = 100; | |
181 | 196 | |
182 | 197 | while (!IsStopped()) |
183 | 198 | { |
198 | 213 | downloadsChecked = true; |
199 | 214 | m_hasMoreJobs = hasMoreArticles || articeDownloadsRunning; |
200 | 215 | if (hasMoreArticles && !IsStopped() && (int)m_activeDownloads.size() < m_downloadsLimit && |
201 | (!g_Options->GetTempPauseDownload() || fileInfo->GetExtraPriority())) | |
216 | (!g_WorkState->GetTempPauseDownload() || fileInfo->GetExtraPriority())) | |
202 | 217 | { |
203 | 218 | StartArticleDownload(fileInfo, articleInfo, connection); |
204 | 219 | articeDownloadsRunning = true; |
226 | 241 | if (standBy != wasStandBy) |
227 | 242 | { |
228 | 243 | g_StatMeter->EnterLeaveStandBy(standBy); |
244 | g_WorkState->SetDownloading(!standBy); | |
229 | 245 | wasStandBy = standBy; |
230 | 246 | if (standBy) |
231 | 247 | { |
234 | 250 | } |
235 | 251 | |
236 | 252 | // sleep longer in StandBy |
237 | int sleepInterval = downloadStarted ? 0 : standBy ? 100 : 5; | |
238 | usleep(sleepInterval * 1000); | |
239 | ||
240 | if (!standBy) | |
241 | { | |
253 | if (standBy) | |
254 | { | |
255 | Util::SetStandByMode(true); | |
256 | Guard guard(m_waitMutex); | |
257 | // sleeping max. 2 seconds; can't sleep much longer because we can't rely on | |
258 | // notifications from 'WorkState' and we also have periodical work to do here | |
259 | waitInterval = std::min(waitInterval * 2, 2000); | |
260 | m_waitCond.WaitFor(m_waitMutex, waitInterval, [&]{ return m_hasMoreJobs || IsStopped(); }); | |
261 | } | |
262 | else | |
263 | { | |
264 | int sleepInterval = downloadStarted ? 0 : 5; | |
265 | Util::Sleep(sleepInterval); | |
242 | 266 | g_StatMeter->AddSpeedReading(0); |
243 | } | |
244 | ||
245 | Util::SetStandByMode(standBy); | |
246 | ||
247 | time_t currentTime = Util::CurrentTime(); | |
248 | if (lastReset != currentTime) | |
267 | waitInterval = 100; | |
268 | } | |
269 | ||
270 | if (lastReset != Util::CurrentTime()) | |
249 | 271 | { |
250 | 272 | // this code should not be called too often, once per second is OK |
251 | 273 | g_ServerPool->CloseUnusedConnections(); |
257 | 279 | g_StatMeter->IntervalCheck(); |
258 | 280 | g_Log->IntervalCheck(); |
259 | 281 | AdjustDownloadsLimit(); |
260 | lastReset = currentTime; | |
282 | Util::SetStandByMode(false); | |
283 | lastReset = Util::CurrentTime(); | |
261 | 284 | } |
262 | 285 | } |
263 | 286 | |
264 | 287 | WaitJobs(); |
265 | 288 | SaveAllPartialState(); |
289 | SaveQueueIfChanged(); | |
266 | 290 | SaveAllFileState(); |
267 | 291 | |
268 | 292 | debug("Exiting QueueCoordinator-loop"); |
293 | } | |
294 | ||
295 | void QueueCoordinator::WakeUp() | |
296 | { | |
297 | debug("Waking up QueueCoordinator"); | |
298 | // Resume Run() | |
299 | Guard guard(m_waitMutex); | |
300 | m_hasMoreJobs = true; | |
301 | m_waitCond.NotifyAll(); | |
269 | 302 | } |
270 | 303 | |
271 | 304 | void QueueCoordinator::WaitJobs() |
282 | 315 | break; |
283 | 316 | } |
284 | 317 | } |
285 | usleep(100 * 1000); | |
318 | Util::Sleep(100); | |
286 | 319 | ResetHangingDownloads(); |
287 | 320 | } |
288 | 321 | |
418 | 451 | { |
419 | 452 | // If more than two files have same filename we don't filter them out since that |
420 | 453 | // naming might be intentional and correct filenames must be read from article bodies. |
421 | int dupeCount = std::count_if(nzbInfo->GetFileList()->begin(), nzbInfo->GetFileList()->end(), | |
454 | int dupeCount = (int)std::count_if(nzbInfo->GetFileList()->begin(), nzbInfo->GetFileList()->end(), | |
422 | 455 | [fileInfo2](std::unique_ptr<FileInfo>& fileInfo3) |
423 | 456 | { |
424 | 457 | return !strcmp(fileInfo3->GetFilename(), fileInfo2->GetFilename()); |
454 | 487 | Thread::Stop(); |
455 | 488 | |
456 | 489 | debug("Stopping ArticleDownloads"); |
457 | GuardedDownloadQueue guard = DownloadQueue::Guard(); | |
458 | for (ArticleDownloader* articleDownloader : m_activeDownloads) | |
459 | { | |
460 | articleDownloader->Stop(); | |
490 | { | |
491 | GuardedDownloadQueue guard = DownloadQueue::Guard(); | |
492 | for (ArticleDownloader* articleDownloader : m_activeDownloads) | |
493 | { | |
494 | articleDownloader->Stop(); | |
495 | } | |
461 | 496 | } |
462 | 497 | debug("ArticleDownloads are notified"); |
498 | ||
499 | // Resume Run() to exit it | |
500 | Guard guard(m_waitMutex); | |
501 | m_waitCond.NotifyAll(); | |
463 | 502 | } |
464 | 503 | |
465 | 504 | /* |
494 | 533 | bool nzbPaused = nzbInfo->GetFileList()->size() - nzbInfo->GetPausedFileCount() <= 0; |
495 | 534 | |
496 | 535 | if ((!fileInfo || nzbHigherPriority) && !nzbPaused && |
497 | (!(g_Options->GetPauseDownload() || g_Options->GetQuotaReached()) || nzbInfo->GetForcePriority())) | |
536 | (!(g_WorkState->GetPauseDownload() || g_WorkState->GetQuotaReached()) || nzbInfo->GetForcePriority())) | |
498 | 537 | { |
499 | 538 | for (FileInfo* fileInfo1 : nzbInfo->GetFileList()) |
500 | 539 | { |
618 | 657 | articleDownloader->Start(); |
619 | 658 | } |
620 | 659 | |
621 | void QueueCoordinator::Update(Subject* Caller, void* Aspect) | |
622 | { | |
660 | void QueueCoordinator::Update(Subject* caller, void* aspect) | |
661 | { | |
662 | if (caller == g_WorkState) | |
663 | { | |
664 | debug("Notification from WorkState received"); | |
665 | WakeUp(); | |
666 | return; | |
667 | } | |
668 | ||
623 | 669 | debug("Notification from ArticleDownloader received"); |
624 | 670 | |
625 | ArticleDownloader* articleDownloader = (ArticleDownloader*)Caller; | |
671 | ArticleDownloader* articleDownloader = (ArticleDownloader*)caller; | |
626 | 672 | if ((articleDownloader->GetStatus() == ArticleDownloader::adFinished) || |
627 | 673 | (articleDownloader->GetStatus() == ArticleDownloader::adFailed) || |
628 | 674 | (articleDownloader->GetStatus() == ArticleDownloader::adRetry)) |
767 | 813 | if (deleteFileObj) |
768 | 814 | { |
769 | 815 | DeleteFileInfo(downloadQueue, fileInfo, fileCompleted); |
770 | downloadQueue->Save(); | |
816 | nzbInfo->SetChanged(true); | |
817 | downloadQueue->SaveChanged(); | |
771 | 818 | } |
772 | 819 | } |
773 | 820 | |
775 | 822 | { |
776 | 823 | while (g_ArticleCache->FileBusy(fileInfo)) |
777 | 824 | { |
778 | usleep(5*1000); | |
825 | Util::Sleep(5); | |
779 | 826 | } |
780 | 827 | |
781 | 828 | NzbInfo* nzbInfo = fileInfo->GetNzbInfo(); |
819 | 866 | fileInfo->GetId(), |
820 | 867 | completed && fileInfo->GetOutputFilename() ? |
821 | 868 | FileSystem::BaseFileName(fileInfo->GetOutputFilename()) : fileInfo->GetFilename(), |
822 | fileStatus, | |
869 | fileInfo->GetOrigname(), fileStatus, | |
823 | 870 | fileStatus == CompletedFile::cfSuccess ? fileInfo->GetCrc() : 0, |
824 | 871 | fileInfo->GetParFile(), fileInfo->GetHash16k(), fileInfo->GetParSetId()); |
825 | 872 | } |
865 | 912 | } |
866 | 913 | } |
867 | 914 | |
868 | void QueueCoordinator::SaveAllPartialState() | |
915 | void QueueCoordinator::SaveQueueIfChanged() | |
869 | 916 | { |
870 | 917 | if (!g_Options->GetServerMode()) |
871 | 918 | { |
872 | 919 | return; |
873 | 920 | } |
874 | 921 | |
875 | bool hasUnsavedData = false; | |
922 | bool hasChanges = false; | |
876 | 923 | GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); |
877 | 924 | for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) |
878 | 925 | { |
879 | if (g_Options->GetContinuePartial()) | |
880 | { | |
881 | for (FileInfo* fileInfo : nzbInfo->GetFileList()) | |
882 | { | |
883 | SavePartialState(fileInfo); | |
884 | } | |
885 | } | |
886 | hasUnsavedData |= nzbInfo->GetChanged(); | |
887 | } | |
888 | ||
889 | if (hasUnsavedData) | |
926 | hasChanges |= nzbInfo->GetChanged(); | |
927 | } | |
928 | ||
929 | if (hasChanges) | |
890 | 930 | { |
891 | 931 | downloadQueue->Save(); |
892 | 932 | } |
933 | } | |
934 | ||
935 | void QueueCoordinator::SaveAllPartialState() | |
936 | { | |
937 | if (!g_Options->GetServerMode() || !g_Options->GetContinuePartial()) | |
938 | { | |
939 | return; | |
940 | } | |
941 | ||
942 | GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); | |
943 | for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) | |
944 | { | |
945 | for (FileInfo* fileInfo : nzbInfo->GetFileList()) | |
946 | { | |
947 | SavePartialState(fileInfo); | |
948 | } | |
949 | } | |
950 | ||
951 | downloadQueue->SaveChanged(); | |
893 | 952 | } |
894 | 953 | |
895 | 954 | void QueueCoordinator::SavePartialState(FileInfo* fileInfo) |
977 | 1036 | downloadQueue->CalcRemainingSize(&remaining, &remainingForced); |
978 | 1037 | info(" Remaining: %.1f MB, Forced: %.1f MB", remaining / 1024.0 / 1024.0, remainingForced / 1024.0 / 1024.0); |
979 | 1038 | info(" Download: %s, Post-process: %s, Scan: %s", |
980 | (g_Options->GetPauseDownload() ? "paused" : g_Options->GetTempPauseDownload() ? "temp-paused" : "active"), | |
981 | (g_Options->GetPausePostProcess() ? "paused" : "active"), | |
982 | (g_Options->GetPauseScan() ? "paused" : "active")); | |
1039 | (g_WorkState->GetPauseDownload() ? "paused" : g_WorkState->GetTempPauseDownload() ? "temp-paused" : "active"), | |
1040 | (g_WorkState->GetPausePostProcess() ? "paused" : "active"), | |
1041 | (g_WorkState->GetPauseScan() ? "paused" : "active")); | |
983 | 1042 | |
984 | 1043 | info(" ---------- QueueCoordinator"); |
985 | 1044 | info(" Active Downloads: %i, Limit: %i", (int)m_activeDownloads.size(), m_downloadsLimit); |
1314 | 1373 | downloadQueue->EditEntry(nzbInfo->GetId(), DownloadQueue::eaGroupSortFiles, nullptr); |
1315 | 1374 | } |
1316 | 1375 | |
1317 | downloadQueue->Save(); | |
1376 | nzbInfo->SetChanged(true); | |
1377 | downloadQueue->SaveChanged(); | |
1318 | 1378 | |
1319 | 1379 | DownloadQueue::Aspect namedAspect = { DownloadQueue::eaNzbNamed, downloadQueue, nzbInfo, nullptr }; |
1320 | 1380 | downloadQueue->Notify(&namedAspect); |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
40 | 40 | virtual ~QueueCoordinator(); |
41 | 41 | virtual void Run(); |
42 | 42 | virtual void Stop(); |
43 | void Update(Subject* Caller, void* Aspect); | |
43 | void Update(Subject* caller, void* aspect); | |
44 | 44 | |
45 | 45 | // editing queue |
46 | 46 | NzbInfo* AddNzbFileToQueue(std::unique_ptr<NzbInfo> nzbInfo, NzbInfo* urlInfo, bool addFirst); |
66 | 66 | EEditAction action, const char* args); |
67 | 67 | virtual void HistoryChanged() { m_historyChanged = true; } |
68 | 68 | virtual void Save(); |
69 | virtual void SaveChanged(); | |
69 | 70 | private: |
70 | 71 | QueueCoordinator* m_owner; |
71 | 72 | bool m_massEdit = false; |
93 | 94 | bool m_hasMoreJobs = true; |
94 | 95 | int m_downloadsLimit; |
95 | 96 | int m_serverConfigGeneration = 0; |
97 | Mutex m_waitMutex; | |
98 | ConditionVar m_waitCond; | |
96 | 99 | |
97 | 100 | bool GetNextArticle(DownloadQueue* downloadQueue, FileInfo* &fileInfo, ArticleInfo* &articleInfo); |
98 | 101 | bool GetNextFirstArticle(NzbInfo* nzbInfo, FileInfo* &fileInfo, ArticleInfo* &articleInfo); |
107 | 110 | void ResetHangingDownloads(); |
108 | 111 | void AdjustDownloadsLimit(); |
109 | 112 | void Load(); |
113 | void SaveQueueIfChanged(); | |
110 | 114 | void SaveAllPartialState(); |
111 | 115 | void SavePartialState(FileInfo* fileInfo); |
112 | 116 | void LoadPartialState(FileInfo* fileInfo); |
113 | 117 | void SaveAllFileState(); |
114 | 118 | void WaitJobs(); |
119 | void WakeUp(); | |
115 | 120 | }; |
116 | 121 | |
117 | 122 | extern QueueCoordinator* g_QueueCoordinator; |
32 | 32 | class EditItem |
33 | 33 | { |
34 | 34 | public: |
35 | int m_offset; | |
36 | 35 | FileInfo* m_fileInfo; |
37 | 36 | NzbInfo* m_nzbInfo; |
37 | int m_offset; | |
38 | 38 | |
39 | 39 | EditItem(FileInfo* fileInfo, NzbInfo* nzbInfo, int offset) : |
40 | 40 | m_fileInfo(fileInfo), m_nzbInfo(nzbInfo), m_offset(offset) {} |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2018 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
20 | 20 | #include "nzbget.h" |
21 | 21 | #include "Scanner.h" |
22 | 22 | #include "Options.h" |
23 | #include "WorkState.h" | |
23 | 24 | #include "Log.h" |
24 | 25 | #include "QueueCoordinator.h" |
25 | 26 | #include "HistoryCoordinator.h" |
72 | 73 | |
73 | 74 | void Scanner::InitOptions() |
74 | 75 | { |
75 | m_nzbDirInterval = g_Options->GetNzbDirInterval() * 1000; | |
76 | m_nzbDirInterval = 1; | |
76 | 77 | m_scanScript = ScanScriptController::HasScripts(); |
77 | 78 | } |
78 | 79 | |
80 | int Scanner::ServiceInterval() | |
81 | { | |
82 | return m_requestedNzbDirScan ? Service::Now : | |
83 | g_Options->GetNzbDirInterval() <= 0 ? Service::Sleep : | |
84 | // g_Options->GetPauseScan() ? Service::Sleep : // for that to work we need to react on changing of pause-state | |
85 | m_nzbDirInterval; | |
86 | } | |
87 | ||
79 | 88 | void Scanner::ServiceWork() |
80 | 89 | { |
90 | debug("Scanner service work"); | |
91 | ||
81 | 92 | if (!DownloadQueue::IsLoaded()) |
82 | 93 | { |
83 | 94 | return; |
84 | 95 | } |
85 | 96 | |
97 | m_nzbDirInterval = g_Options->GetNzbDirInterval(); | |
98 | ||
99 | if (g_WorkState->GetPauseScan() && !m_requestedNzbDirScan) | |
100 | { | |
101 | return; | |
102 | } | |
103 | ||
104 | debug("Scanner service work: doing work"); | |
105 | ||
86 | 106 | Guard guard(m_scanMutex); |
87 | 107 | |
88 | if (m_requestedNzbDirScan || | |
89 | (!g_Options->GetPauseScan() && g_Options->GetNzbDirInterval() > 0 && | |
90 | m_nzbDirInterval >= g_Options->GetNzbDirInterval() * 1000)) | |
91 | { | |
92 | // check nzbdir every g_pOptions->GetNzbDirInterval() seconds or if requested | |
93 | bool checkStat = !m_requestedNzbDirScan; | |
94 | m_requestedNzbDirScan = false; | |
95 | m_scanning = true; | |
108 | // check nzbdir every g_pOptions->GetNzbDirInterval() seconds or if requested | |
109 | bool checkStat = !m_requestedNzbDirScan; | |
110 | m_requestedNzbDirScan = false; | |
111 | m_scanning = true; | |
112 | CheckIncomingNzbs(g_Options->GetNzbDir(), "", checkStat); | |
113 | if (!checkStat && m_scanScript) | |
114 | { | |
115 | // if immediate scan requested, we need second scan to process files extracted by scan-scripts | |
96 | 116 | CheckIncomingNzbs(g_Options->GetNzbDir(), "", checkStat); |
97 | if (!checkStat && m_scanScript) | |
98 | { | |
99 | // if immediate scan requested, we need second scan to process files extracted by scan-scripts | |
100 | CheckIncomingNzbs(g_Options->GetNzbDir(), "", checkStat); | |
101 | } | |
102 | m_scanning = false; | |
103 | m_nzbDirInterval = 0; | |
104 | ||
105 | // if NzbDirFileAge is less than NzbDirInterval (that can happen if NzbDirInterval | |
106 | // is set for rare scans like once per hour) we make 4 scans: | |
107 | // - one additional scan is neccessary to check sizes of detected files; | |
108 | // - another scan is required to check files which were extracted by scan-scripts; | |
109 | // - third scan is needed to check sizes of extracted files. | |
110 | if (g_Options->GetNzbDirInterval() > 0 && g_Options->GetNzbDirFileAge() < g_Options->GetNzbDirInterval()) | |
111 | { | |
112 | int maxPass = m_scanScript ? 3 : 1; | |
113 | if (m_pass < maxPass) | |
114 | { | |
115 | // scheduling another scan of incoming directory in NzbDirFileAge seconds. | |
116 | m_nzbDirInterval = (g_Options->GetNzbDirInterval() - g_Options->GetNzbDirFileAge()) * 1000; | |
117 | m_pass++; | |
118 | } | |
119 | else | |
120 | { | |
121 | m_pass = 0; | |
122 | } | |
123 | } | |
124 | ||
125 | DropOldFiles(); | |
126 | m_queueList.clear(); | |
127 | } | |
128 | m_nzbDirInterval += 200; | |
117 | } | |
118 | m_scanning = false; | |
119 | ||
120 | // if NzbDirFileAge is less than NzbDirInterval (that can happen if NzbDirInterval | |
121 | // is set for rare scans like once per hour) we make 4 scans: | |
122 | // - one additional scan is neccessary to check sizes of detected files; | |
123 | // - another scan is required to check files which were extracted by scan-scripts; | |
124 | // - third scan is needed to check sizes of extracted files. | |
125 | if (g_Options->GetNzbDirInterval() > 0 && g_Options->GetNzbDirFileAge() < g_Options->GetNzbDirInterval()) | |
126 | { | |
127 | int maxPass = m_scanScript ? 3 : 1; | |
128 | if (m_pass < maxPass) | |
129 | { | |
130 | // scheduling another scan of incoming directory in NzbDirFileAge seconds. | |
131 | m_nzbDirInterval = g_Options->GetNzbDirFileAge(); | |
132 | m_pass++; | |
133 | } | |
134 | else | |
135 | { | |
136 | m_pass = 0; | |
137 | } | |
138 | } | |
139 | ||
140 | DropOldFiles(); | |
141 | m_queueList.clear(); | |
129 | 142 | } |
130 | 143 | |
131 | 144 | /** |
485 | 498 | Guard guard(m_scanMutex); |
486 | 499 | m_scanning = true; |
487 | 500 | m_requestedNzbDirScan = true; |
501 | WakeUp(); | |
488 | 502 | } |
489 | 503 | |
490 | 504 | while (syncMode && (m_scanning || m_requestedNzbDirScan)) |
491 | 505 | { |
492 | usleep(100 * 1000); | |
506 | Util::Sleep(100); | |
493 | 507 | } |
494 | 508 | } |
495 | 509 | |
496 | 510 | Scanner::EAddStatus Scanner::AddExternalFile(const char* nzbName, const char* category, |
497 | int priority, const char* dupeKey, int dupeScore, EDupeMode dupeMode, | |
511 | int priority, const char* dupeKey, int dupeScore, EDupeMode dupeMode, | |
498 | 512 | NzbParameterList* parameters, bool addTop, bool addPaused, NzbInfo* urlInfo, |
499 | 513 | const char* fileName, const char* buffer, int bufSize, int* nzbId) |
500 | 514 | { |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
45 | 45 | void InitPPParameters(const char* category, NzbParameterList* parameters, bool reset); |
46 | 46 | |
47 | 47 | protected: |
48 | virtual int ServiceInterval() { return 200; } | |
48 | virtual int ServiceInterval(); | |
49 | 49 | virtual void ServiceWork(); |
50 | 50 | |
51 | 51 | private: |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
20 | 20 | #include "nzbget.h" |
21 | 21 | #include "UrlCoordinator.h" |
22 | 22 | #include "Options.h" |
23 | #include "WorkState.h" | |
23 | 24 | #include "WebDownloader.h" |
24 | 25 | #include "Util.h" |
25 | 26 | #include "FileSystem.h" |
59 | 60 | } |
60 | 61 | } |
61 | 62 | |
63 | UrlCoordinator::UrlCoordinator() | |
64 | { | |
65 | m_downloadQueueObserver.m_owner = this; | |
66 | DownloadQueue::Guard()->Attach(&m_downloadQueueObserver); | |
67 | } | |
68 | ||
62 | 69 | UrlCoordinator::~UrlCoordinator() |
63 | 70 | { |
64 | 71 | debug("Destroying UrlCoordinator"); |
78 | 85 | |
79 | 86 | while (!DownloadQueue::IsLoaded()) |
80 | 87 | { |
81 | usleep(20 * 1000); | |
82 | } | |
83 | ||
84 | int resetCounter = 0; | |
88 | Util::Sleep(20); | |
89 | } | |
85 | 90 | |
86 | 91 | while (!IsStopped()) |
87 | 92 | { |
93 | time_t lastReset = 0; | |
88 | 94 | bool downloadStarted = false; |
89 | if (!g_Options->GetPauseDownload() || g_Options->GetUrlForce()) | |
90 | { | |
91 | // start download for next URL | |
95 | ||
96 | { | |
97 | NzbInfo* nzbInfo = nullptr; | |
92 | 98 | GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); |
93 | 99 | if ((int)m_activeDownloads.size() < g_Options->GetUrlConnections()) |
94 | 100 | { |
95 | NzbInfo* nzbInfo = GetNextUrl(downloadQueue); | |
96 | bool hasMoreUrls = nzbInfo != nullptr; | |
97 | bool urlDownloadsRunning = !m_activeDownloads.empty(); | |
98 | m_hasMoreJobs = hasMoreUrls || urlDownloadsRunning; | |
99 | if (hasMoreUrls && !IsStopped()) | |
101 | nzbInfo = GetNextUrl(downloadQueue); | |
102 | if (nzbInfo && (!g_WorkState->GetPauseDownload() || g_Options->GetUrlForce())) | |
100 | 103 | { |
101 | 104 | StartUrlDownload(nzbInfo); |
102 | 105 | downloadStarted = true; |
103 | 106 | } |
104 | 107 | } |
105 | } | |
106 | ||
107 | int sleepInterval = downloadStarted ? 0 : 100; | |
108 | usleep(sleepInterval * 1000); | |
109 | ||
110 | resetCounter += sleepInterval; | |
111 | if (resetCounter >= 1000) | |
108 | m_hasMoreJobs = !m_activeDownloads.empty() || nzbInfo; | |
109 | } | |
110 | ||
111 | if (lastReset != Util::CurrentTime()) | |
112 | 112 | { |
113 | 113 | // this code should not be called too often, once per second is OK |
114 | 114 | ResetHangingDownloads(); |
115 | resetCounter = 0; | |
115 | lastReset = Util::CurrentTime(); | |
116 | } | |
117 | ||
118 | if (!m_hasMoreJobs && !IsStopped()) | |
119 | { | |
120 | Guard guard(m_waitMutex); | |
121 | m_waitCond.Wait(m_waitMutex, [&] { return m_hasMoreJobs || IsStopped(); }); | |
122 | } | |
123 | else | |
124 | { | |
125 | int sleepInterval = downloadStarted ? 0 : 100; | |
126 | Util::Sleep(sleepInterval); | |
116 | 127 | } |
117 | 128 | } |
118 | 129 | |
135 | 146 | break; |
136 | 147 | } |
137 | 148 | } |
138 | usleep(100 * 1000); | |
149 | Util::Sleep(100); | |
139 | 150 | ResetHangingDownloads(); |
140 | 151 | } |
141 | 152 | |
147 | 158 | Thread::Stop(); |
148 | 159 | |
149 | 160 | debug("Stopping UrlDownloads"); |
150 | GuardedDownloadQueue guard = DownloadQueue::Guard(); | |
151 | for (UrlDownloader* urlDownloader : m_activeDownloads) | |
152 | { | |
153 | urlDownloader->Stop(); | |
161 | { | |
162 | GuardedDownloadQueue guard = DownloadQueue::Guard(); | |
163 | for (UrlDownloader* urlDownloader : m_activeDownloads) | |
164 | { | |
165 | urlDownloader->Stop(); | |
166 | } | |
154 | 167 | } |
155 | 168 | debug("UrlDownloads are notified"); |
169 | ||
170 | // Resume Run() to exit it | |
171 | Guard guard(m_waitMutex); | |
172 | m_waitCond.NotifyAll(); | |
173 | } | |
174 | ||
175 | void UrlCoordinator::DownloadQueueUpdate(Subject* caller, void* aspect) | |
176 | { | |
177 | debug("Notification from download queue received"); | |
178 | ||
179 | DownloadQueue::Aspect* queueAspect = (DownloadQueue::Aspect*)aspect; | |
180 | if (queueAspect->action == DownloadQueue::eaUrlAdded || | |
181 | queueAspect->action == DownloadQueue::eaUrlReturned) | |
182 | { | |
183 | // Resume Run() | |
184 | Guard guard(m_waitMutex); | |
185 | m_hasMoreJobs = true; | |
186 | m_waitCond.NotifyAll(); | |
187 | } | |
156 | 188 | } |
157 | 189 | |
158 | 190 | void UrlCoordinator::ResetHangingDownloads() |
193 | 225 | */ |
194 | 226 | NzbInfo* UrlCoordinator::GetNextUrl(DownloadQueue* downloadQueue) |
195 | 227 | { |
196 | bool pauseDownload = g_Options->GetPauseDownload(); | |
197 | ||
198 | 228 | NzbInfo* nzbInfo = nullptr; |
199 | 229 | |
200 | 230 | for (NzbInfo* nzbInfo1 : downloadQueue->GetQueue()) |
202 | 232 | if (nzbInfo1->GetKind() == NzbInfo::nkUrl && |
203 | 233 | nzbInfo1->GetUrlStatus() == NzbInfo::lsNone && |
204 | 234 | nzbInfo1->GetDeleteStatus() == NzbInfo::dsNone && |
205 | (!pauseDownload || g_Options->GetUrlForce()) && | |
206 | 235 | (!nzbInfo || nzbInfo1->GetPriority() > nzbInfo->GetPriority())) |
207 | 236 | { |
208 | 237 | nzbInfo = nzbInfo1; |
396 | 425 | |
397 | 426 | downloadQueue->Save(); |
398 | 427 | } |
428 |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
32 | 32 | class UrlCoordinator : public Thread, public Observer, public Debuggable |
33 | 33 | { |
34 | 34 | public: |
35 | UrlCoordinator(); | |
35 | 36 | virtual ~UrlCoordinator(); |
36 | 37 | virtual void Run(); |
37 | 38 | virtual void Stop(); |
48 | 49 | private: |
49 | 50 | typedef std::list<UrlDownloader*> ActiveDownloads; |
50 | 51 | |
52 | class DownloadQueueObserver: public Observer | |
53 | { | |
54 | public: | |
55 | UrlCoordinator* m_owner; | |
56 | virtual void Update(Subject* caller, void* aspect) { m_owner->DownloadQueueUpdate(caller, aspect); } | |
57 | }; | |
58 | ||
51 | 59 | ActiveDownloads m_activeDownloads; |
52 | 60 | bool m_hasMoreJobs = true; |
53 | 61 | bool m_force; |
62 | Mutex m_waitMutex; | |
63 | ConditionVar m_waitCond; | |
64 | DownloadQueueObserver m_downloadQueueObserver; | |
54 | 65 | |
55 | 66 | NzbInfo* GetNextUrl(DownloadQueue* downloadQueue); |
56 | 67 | void StartUrlDownload(NzbInfo* nzbInfo); |
57 | 68 | void UrlCompleted(UrlDownloader* urlDownloader); |
58 | 69 | void ResetHangingDownloads(); |
59 | 70 | void WaitJobs(); |
71 | void DownloadQueueUpdate(Subject* caller, void* aspect); | |
60 | 72 | }; |
61 | 73 | |
62 | 74 | extern UrlCoordinator* g_UrlCoordinator; |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net> |
4 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
22 | 22 | #include "BinRpc.h" |
23 | 23 | #include "Log.h" |
24 | 24 | #include "Options.h" |
25 | #include "WorkState.h" | |
25 | 26 | #include "QueueEditor.h" |
26 | 27 | #include "Util.h" |
27 | 28 | #include "FileSystem.h" |
312 | 313 | return; |
313 | 314 | } |
314 | 315 | |
315 | g_Options->SetResumeTime(0); | |
316 | g_WorkState->SetResumeTime(0); | |
316 | 317 | |
317 | 318 | switch (ntohl(PauseUnpauseRequest.m_action)) |
318 | 319 | { |
319 | 320 | case rpDownload: |
320 | g_Options->SetPauseDownload(ntohl(PauseUnpauseRequest.m_pause)); | |
321 | g_WorkState->SetPauseDownload(ntohl(PauseUnpauseRequest.m_pause)); | |
321 | 322 | break; |
322 | 323 | |
323 | 324 | case rpPostProcess: |
324 | g_Options->SetPausePostProcess(ntohl(PauseUnpauseRequest.m_pause)); | |
325 | g_WorkState->SetPausePostProcess(ntohl(PauseUnpauseRequest.m_pause)); | |
325 | 326 | break; |
326 | 327 | |
327 | 328 | case rpScan: |
328 | g_Options->SetPauseScan(ntohl(PauseUnpauseRequest.m_pause)); | |
329 | g_WorkState->SetPauseScan(ntohl(PauseUnpauseRequest.m_pause)); | |
329 | 330 | break; |
330 | 331 | } |
331 | 332 | |
340 | 341 | return; |
341 | 342 | } |
342 | 343 | |
343 | g_Options->SetDownloadRate(ntohl(SetDownloadRequest.m_downloadRate)); | |
344 | g_WorkState->SetSpeedLimit(ntohl(SetDownloadRequest.m_downloadRate)); | |
344 | 345 | SendBoolResponse(true, "Rate-Command completed successfully"); |
345 | 346 | } |
346 | 347 | |
673 | 674 | Util::SplitInt64(remainingSize, &sizeHi, &sizeLo); |
674 | 675 | ListResponse.m_remainingSizeHi = htonl(sizeHi); |
675 | 676 | ListResponse.m_remainingSizeLo = htonl(sizeLo); |
676 | ListResponse.m_downloadLimit = htonl(g_Options->GetDownloadRate()); | |
677 | ListResponse.m_downloadPaused = htonl(g_Options->GetPauseDownload()); | |
678 | ListResponse.m_postPaused = htonl(g_Options->GetPausePostProcess()); | |
679 | ListResponse.m_scanPaused = htonl(g_Options->GetPauseScan()); | |
677 | ListResponse.m_downloadRate = htonl(g_WorkState->GetSpeedLimit()); | |
678 | ListResponse.m_downloadPaused = htonl(g_WorkState->GetPauseDownload()); | |
679 | ListResponse.m_postPaused = htonl(g_WorkState->GetPausePostProcess()); | |
680 | ListResponse.m_scanPaused = htonl(g_WorkState->GetPauseScan()); | |
680 | 681 | ListResponse.m_threadCount = htonl(Thread::GetThreadCount() - 1); // not counting itself |
681 | 682 | ListResponse.m_postJobCount = htonl(postJobCount); |
682 | 683 |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net> |
4 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
496 | 496 | } |
497 | 497 | |
498 | 498 | printf("-----------------------------------\n"); |
499 | printf("Groups: %i\n", downloadQueue->GetQueue()->size()); | |
499 | printf("Groups: %i\n", (int)downloadQueue->GetQueue()->size()); | |
500 | 500 | if (pattern) |
501 | 501 | { |
502 | 502 | printf("Matches: %i\n", matches); |
540 | 540 | int averageSpeed = (int)(ntohl(ListResponse.m_downloadTimeSec) > 0 ? allBytes / ntohl(ListResponse.m_downloadTimeSec) : 0); |
541 | 541 | printf("Session download rate: %s\n", *Util::FormatSpeed(averageSpeed)); |
542 | 542 | |
543 | if (ntohl(ListResponse.m_downloadLimit) > 0) | |
544 | { | |
545 | printf("Speed limit: %s\n", *Util::FormatSpeed(ntohl(ListResponse.m_downloadLimit))); | |
543 | if (ntohl(ListResponse.m_downloadRate) > 0) | |
544 | { | |
545 | printf("Speed limit: %s\n", *Util::FormatSpeed(ntohl(ListResponse.m_downloadRate))); | |
546 | 546 | } |
547 | 547 | |
548 | 548 | int sec = ntohl(ListResponse.m_upTimeSec); |
796 | 796 | |
797 | 797 | if (textLen > 0) |
798 | 798 | { |
799 | strcpy(trailingData, text); | |
799 | strncpy(trailingData, text, textLen); | |
800 | 800 | } |
801 | 801 | |
802 | 802 | int32* ids = (int32*)(trailingData + textLen); |
811 | 811 | char *names = trailingData + textLen + idLength; |
812 | 812 | for (CString& name : nameList) |
813 | 813 | { |
814 | int len = strlen(name); | |
814 | // "len" must be less or equal than: "buffer size" - "already used buffer" - "ending \0" | |
815 | size_t len = strnlen(name, length - (names - trailingData) - 1); | |
815 | 816 | strncpy(names, name, len + 1); |
816 | 817 | names += len + 1; |
817 | 818 | } |
78 | 78 | break; |
79 | 79 | } |
80 | 80 | m_connection.reset(); |
81 | usleep(500 * 1000); | |
81 | Util::Sleep(500); | |
82 | 82 | continue; |
83 | 83 | } |
84 | 84 | |
111 | 111 | Guard guard(m_processorsMutex); |
112 | 112 | completed = m_activeProcessors.size() == 0; |
113 | 113 | } |
114 | usleep(100 * 1000); | |
114 | Util::Sleep(100); | |
115 | 115 | } |
116 | 116 | debug("RemoteServer: request processor are completed"); |
117 | 117 |
52 | 52 | |
53 | 53 | for (int j = uaControl; j <= uaAdd; j++) |
54 | 54 | { |
55 | for (int i = 0; i < sizeof(m_serverAuthToken[j]) - 1; i++) | |
55 | for (size_t i = 0; i < sizeof(m_serverAuthToken[j]) - 1; i++) | |
56 | 56 | { |
57 | 57 | int ch = rand() % (10 + 26 + 26); |
58 | 58 | if (0 <= ch && ch < 10) |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
21 | 21 | #include "XmlRpc.h" |
22 | 22 | #include "Log.h" |
23 | 23 | #include "Options.h" |
24 | #include "WorkState.h" | |
24 | 25 | #include "Scanner.h" |
25 | 26 | #include "FeedCoordinator.h" |
26 | 27 | #include "ServerPool.h" |
403 | 404 | int valueLen = 0; |
404 | 405 | if (const char* methodPtr = WebUtil::JsonFindField(m_request, "method", &valueLen)) |
405 | 406 | { |
406 | valueLen = valueLen >= sizeof(methodName) ? sizeof(methodName) - 1 : valueLen; | |
407 | valueLen = valueLen >= (int)sizeof(methodName) ? (int)sizeof(methodName) - 1 : valueLen; | |
407 | 408 | methodName.Set(methodPtr + 1, valueLen - 2); |
408 | 409 | } |
409 | 410 | if (const char* requestIdPtr = WebUtil::JsonFindField(m_request, "id", &valueLen)) |
410 | 411 | { |
411 | valueLen = valueLen >= sizeof(requestId) ? sizeof(requestId) - 1 : valueLen; | |
412 | valueLen = valueLen >= (int)sizeof(requestId) ? (int)sizeof(requestId) - 1 : valueLen; | |
412 | 413 | requestId.Set(requestIdPtr, valueLen); |
413 | 414 | } |
414 | 415 | } |
1101 | 1102 | { |
1102 | 1103 | bool ok = true; |
1103 | 1104 | |
1104 | g_Options->SetResumeTime(0); | |
1105 | g_WorkState->SetResumeTime(0); | |
1105 | 1106 | |
1106 | 1107 | switch (m_pauseAction) |
1107 | 1108 | { |
1108 | 1109 | case paDownload: |
1109 | g_Options->SetPauseDownload(m_pause); | |
1110 | g_WorkState->SetPauseDownload(m_pause); | |
1110 | 1111 | break; |
1111 | 1112 | |
1112 | 1113 | case paPostProcess: |
1113 | g_Options->SetPausePostProcess(m_pause); | |
1114 | g_WorkState->SetPausePostProcess(m_pause); | |
1114 | 1115 | break; |
1115 | 1116 | |
1116 | 1117 | case paScan: |
1117 | g_Options->SetPauseScan(m_pause); | |
1118 | g_WorkState->SetPauseScan(m_pause); | |
1118 | 1119 | break; |
1119 | 1120 | |
1120 | 1121 | default: |
1136 | 1137 | |
1137 | 1138 | time_t curTime = Util::CurrentTime(); |
1138 | 1139 | |
1139 | g_Options->SetResumeTime(curTime + seconds); | |
1140 | g_WorkState->SetResumeTime(curTime + seconds); | |
1140 | 1141 | |
1141 | 1142 | BuildBoolResponse(true); |
1142 | 1143 | } |
1178 | 1179 | return; |
1179 | 1180 | } |
1180 | 1181 | |
1181 | g_Options->SetDownloadRate(rate * 1024); | |
1182 | g_WorkState->SetSpeedLimit(rate * 1024); | |
1182 | 1183 | BuildBoolResponse(true); |
1183 | 1184 | } |
1184 | 1185 | |
1321 | 1322 | int articleCacheMBytes = (int)(articleCache / 1024 / 1024); |
1322 | 1323 | |
1323 | 1324 | int downloadRate = (int)(g_StatMeter->CalcCurrentDownloadSpeed()); |
1324 | int downloadLimit = (int)(g_Options->GetDownloadRate()); | |
1325 | bool downloadPaused = g_Options->GetPauseDownload(); | |
1326 | bool postPaused = g_Options->GetPausePostProcess(); | |
1327 | bool scanPaused = g_Options->GetPauseScan(); | |
1328 | bool quotaReached = g_Options->GetQuotaReached(); | |
1325 | int downloadLimit = (int)(g_WorkState->GetSpeedLimit()); | |
1326 | bool downloadPaused = g_WorkState->GetPauseDownload(); | |
1327 | bool postPaused = g_WorkState->GetPausePostProcess(); | |
1328 | bool scanPaused = g_WorkState->GetPauseScan(); | |
1329 | bool quotaReached = g_WorkState->GetQuotaReached(); | |
1329 | 1330 | int threadCount = Thread::GetThreadCount() - 1; // not counting itself |
1330 | 1331 | |
1331 | 1332 | uint32 downloadedSizeHi, downloadedSizeLo; |
1353 | 1354 | int freeDiskSpaceMB = (int)(freeDiskSpace / 1024 / 1024); |
1354 | 1355 | |
1355 | 1356 | int serverTime = (int)Util::CurrentTime(); |
1356 | int resumeTime = (int)g_Options->GetResumeTime(); | |
1357 | int resumeTime = (int)g_WorkState->GetResumeTime(); | |
1357 | 1358 | bool feedActive = g_FeedCoordinator->HasActiveDownloads(); |
1358 | 1359 | int queuedScripts = g_QueueScriptCoordinator->GetQueueSize(); |
1359 | 1360 |
96 | 96 | |
97 | 97 | m_logFile->Seek(0, DiskFile::soEnd); |
98 | 98 | |
99 | #ifdef DEBUG | |
99 | 100 | #ifdef WIN32 |
100 | 101 | uint64 processId = GetCurrentProcessId(); |
101 | 102 | uint64 threadId = GetCurrentThreadId(); |
103 | 104 | uint64 processId = (uint64)getpid(); |
104 | 105 | uint64 threadId = (uint64)pthread_self(); |
105 | 106 | #endif |
106 | #ifdef DEBUG | |
107 | m_logFile->Print("%s\t%llu\t%llu\t%s%s", time, processId, threadId, tmp2, LINE_ENDING); | |
107 | m_logFile->Print("%s\t%" PRIu64 "\t%" PRIu64 "\t%s%s", time, processId, threadId, tmp2, LINE_ENDING); | |
108 | 108 | #else |
109 | 109 | m_logFile->Print("%s\t%s%s", time, tmp2, LINE_ENDING); |
110 | 110 | #endif |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2015-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
75 | 75 | } |
76 | 76 | |
77 | 77 | template <int size> |
78 | void BString<size>::Format(const char* format, ...) | |
79 | { | |
80 | va_list ap; | |
81 | va_start(ap, format); | |
82 | FormatV(format, ap); | |
83 | va_end(ap); | |
84 | } | |
85 | ||
86 | template <int size> | |
87 | void BString<size>::FormatV(const char* format, va_list ap) | |
88 | { | |
89 | vsnprintf(m_data, size, format, ap); | |
78 | int BString<size>::Format(const char* format, ...) | |
79 | { | |
80 | va_list ap; | |
81 | va_start(ap, format); | |
82 | int len = FormatV(format, ap); | |
83 | va_end(ap); | |
84 | return len; | |
85 | } | |
86 | ||
87 | template <int size> | |
88 | int BString<size>::FormatV(const char* format, va_list ap) | |
89 | { | |
90 | // ensure result isn't negative (in case of bad argument) | |
91 | int len = std::max(vsnprintf(m_data, size, format, ap), 0); | |
92 | return len; | |
90 | 93 | } |
91 | 94 | |
92 | 95 | bool CString::operator==(const CString& other) |
158 | 161 | va_end(ap2); |
159 | 162 | } |
160 | 163 | |
161 | void CString::Format(const char* format, ...) | |
162 | { | |
163 | va_list ap; | |
164 | va_start(ap, format); | |
165 | FormatV(format, ap); | |
166 | va_end(ap); | |
167 | } | |
168 | ||
169 | void CString::FormatV(const char* format, va_list ap) | |
164 | int CString::Format(const char* format, ...) | |
165 | { | |
166 | va_list ap; | |
167 | va_start(ap, format); | |
168 | int len = FormatV(format, ap); | |
169 | va_end(ap); | |
170 | return len; | |
171 | } | |
172 | ||
173 | int CString::FormatV(const char* format, va_list ap) | |
170 | 174 | { |
171 | 175 | va_list ap2; |
172 | 176 | va_copy(ap2, ap); |
173 | 177 | |
174 | int newLen = vsnprintf(nullptr, 0, format, ap); | |
175 | if (newLen < 0) return; // bad argument | |
178 | // "std::max" to ensure result isn't negative (in case of bad argument) | |
179 | int newLen = std::max(vsnprintf(nullptr, 0, format, ap), 0); | |
176 | 180 | |
177 | 181 | m_data = (char*)realloc(m_data, newLen + 1); |
178 | vsnprintf(m_data, newLen + 1, format, ap2); | |
182 | newLen = vsnprintf(m_data, newLen + 1, format, ap2); | |
179 | 183 | |
180 | 184 | va_end(ap2); |
185 | return newLen; | |
181 | 186 | } |
182 | 187 | |
183 | 188 | int CString::Find(const char* str, int pos) |
280 | 285 | m_data = (wchar_t*)malloc((strlen(utfstr) * 2 + 1) * sizeof(wchar_t)); |
281 | 286 | |
282 | 287 | wchar_t* out = m_data; |
283 | unsigned int codepoint; | |
288 | unsigned int codepoint = 0; | |
284 | 289 | while (*utfstr != 0) |
285 | 290 | { |
286 | 291 | unsigned char ch = (unsigned char)*utfstr; |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2015-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
45 | 45 | void Append(const char* str, int len = 0); |
46 | 46 | void AppendFmt(const char* format, ...) PRINTF_SYNTAX(2); |
47 | 47 | void AppendFmtV(const char* format, va_list ap); |
48 | void Format(const char* format, ...) PRINTF_SYNTAX(2); | |
49 | void FormatV(const char* format, va_list ap); | |
48 | int Format(const char* format, ...) PRINTF_SYNTAX(2); | |
49 | int FormatV(const char* format, va_list ap); | |
50 | 50 | |
51 | 51 | protected: |
52 | 52 | char m_data[size]; |
82 | 82 | void Append(const char* str, int len = 0); |
83 | 83 | void AppendFmt(const char* format, ...) PRINTF_SYNTAX(2); |
84 | 84 | void AppendFmtV(const char* format, va_list ap); |
85 | void Format(const char* format, ...) PRINTF_SYNTAX(2); | |
86 | void FormatV(const char* format, va_list ap); | |
85 | int Format(const char* format, ...) PRINTF_SYNTAX(2); | |
86 | int FormatV(const char* format, va_list ap); | |
87 | 87 | int Find(const char* str, int pos = 0); |
88 | 88 | void Replace(int pos, int len, const char* str, int strLen = 0); |
89 | 89 | void Replace(const char* from, const char* to); |
149 | 149 | CharBuffer(int size) : m_size(size) { m_data = (char*)malloc(size); } |
150 | 150 | CharBuffer(CharBuffer& other) : m_data(other.m_data), m_size(other.m_size) { other.m_data = nullptr; other.m_size = 0; } |
151 | 151 | ~CharBuffer() { free(m_data); } |
152 | CharBuffer& operator=(CharBuffer&& other) = delete; | |
152 | 153 | int Size() { return m_size; } |
153 | 154 | void Reserve(int size) { m_data = (char*)realloc(m_data, size); m_size = size; } |
154 | 155 | void Clear() { free(m_data); m_data = nullptr; m_size = 0; } |
65 | 65 | time_t start = Util::CurrentTime(); |
66 | 66 | while (!IsStopped() && (Util::CurrentTime() - start) < WAIT_SECONDS) |
67 | 67 | { |
68 | usleep(10 * 1000); | |
68 | Util::Sleep(10); | |
69 | 69 | } |
70 | 70 | |
71 | 71 | if (!IsStopped()) |
393 | 393 | } |
394 | 394 | while (watchDog.IsRunning()) |
395 | 395 | { |
396 | usleep(5 * 1000); | |
396 | Util::Sleep(5); | |
397 | 397 | } |
398 | 398 | #endif |
399 | 399 | |
583 | 583 | args.emplace_back(nullptr); |
584 | 584 | char* const* argdata = (char* const*)args.data(); |
585 | 585 | |
586 | #ifdef DEBUG | |
586 | 587 | debug("Starting process: %s", script); |
587 | 588 | for (const char* arg : m_args) |
588 | 589 | { |
589 | 590 | debug("arg: %s", arg); |
590 | 591 | } |
592 | #endif | |
591 | 593 | |
592 | 594 | debug("forking"); |
593 | 595 | pid_t pid = fork(); |
738 | 740 | time_t curtime = Util::CurrentTime(); |
739 | 741 | while (!script->m_completed && std::abs(curtime - Util::CurrentTime()) <= 10) |
740 | 742 | { |
741 | usleep(100 * 1000); | |
743 | Util::Sleep(100); | |
742 | 744 | } |
743 | 745 | } |
744 | 746 | script->Terminate(); |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2015-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
29 | 29 | g_ServiceCoordinator->RegisterService(this); |
30 | 30 | } |
31 | 31 | |
32 | void Service::WakeUp() | |
33 | { | |
34 | g_ServiceCoordinator->WakeUp(); | |
35 | }; | |
36 | ||
32 | 37 | |
33 | 38 | ServiceCoordinator::ServiceCoordinator() |
34 | 39 | { |
45 | 50 | { |
46 | 51 | debug("Entering ServiceCoordinator-loop"); |
47 | 52 | |
48 | const int stepMSec = 100; | |
49 | int curTick = 0; | |
50 | ||
51 | 53 | while (!IsStopped()) |
52 | 54 | { |
55 | // perform service work | |
53 | 56 | for (Service* service : m_services) |
54 | 57 | { |
55 | if (curTick >= service->m_lastTick + service->ServiceInterval() || // interval expired | |
56 | curTick == 0 || // first start | |
57 | curTick + 10000 < service->m_lastTick) // int overflow | |
58 | int serviceInterval = service->ServiceInterval(); | |
59 | if (serviceInterval >= Service::Now && | |
60 | abs(Util::CurrentTime() - service->m_lastWork) >= serviceInterval) | |
58 | 61 | { |
59 | 62 | service->ServiceWork(); |
60 | service->m_lastTick = curTick; | |
63 | service->m_lastWork = Util::CurrentTime(); | |
61 | 64 | } |
62 | 65 | } |
63 | 66 | |
64 | curTick += stepMSec; | |
65 | usleep(stepMSec * 1000); | |
67 | // calculate wait interval | |
68 | int waitInterval = 60 * 60 * 24; // something very large | |
69 | time_t curTime = Util::CurrentTime(); | |
70 | for (Service* service : m_services) | |
71 | { | |
72 | int serviceInterval = service->ServiceInterval(); | |
73 | int remaining = Service::Sleep; | |
74 | if (serviceInterval >= Service::Now) | |
75 | { | |
76 | remaining = serviceInterval - (curTime - service->m_lastWork); | |
77 | waitInterval = std::min(waitInterval, remaining); | |
78 | } | |
79 | debug("serviceInterval: %i, remaining: %i", serviceInterval, remaining); | |
80 | } | |
81 | ||
82 | debug("Waiting in ServiceCoordinator: %i", waitInterval); | |
83 | if (waitInterval > 0) | |
84 | { | |
85 | Guard guard(m_waitMutex); | |
86 | m_waitCond.WaitFor(m_waitMutex, waitInterval * 1000, [&] { return m_workenUp || IsStopped(); }); | |
87 | m_workenUp = false; | |
88 | } | |
66 | 89 | } |
67 | 90 | |
68 | 91 | debug("Exiting ServiceCoordinator-loop"); |
92 | } | |
93 | ||
94 | void ServiceCoordinator::Stop() | |
95 | { | |
96 | Thread::Stop(); | |
97 | ||
98 | // Resume Run() to exit it | |
99 | Guard guard(m_waitMutex); | |
100 | m_waitCond.NotifyAll(); | |
101 | } | |
102 | ||
103 | void ServiceCoordinator::WakeUp() | |
104 | { | |
105 | debug("Waking up ServiceCoordinator"); | |
106 | // Resume Run() | |
107 | Guard guard(m_waitMutex); | |
108 | m_workenUp = true; | |
109 | m_waitCond.NotifyAll(); | |
69 | 110 | } |
70 | 111 | |
71 | 112 | void ServiceCoordinator::RegisterService(Service* service) |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2015-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
27 | 27 | public: |
28 | 28 | Service(); |
29 | 29 | |
30 | static const int Now = 0; | |
31 | static const int Sleep = -1; | |
32 | ||
30 | 33 | protected: |
31 | 34 | virtual int ServiceInterval() = 0; |
32 | 35 | virtual void ServiceWork() = 0; |
36 | void WakeUp(); | |
33 | 37 | |
34 | 38 | private: |
35 | int m_lastTick = 0; | |
39 | time_t m_lastWork = 0; | |
36 | 40 | |
37 | 41 | friend class ServiceCoordinator; |
38 | 42 | }; |
45 | 49 | ServiceCoordinator(); |
46 | 50 | virtual ~ServiceCoordinator(); |
47 | 51 | virtual void Run(); |
52 | virtual void Stop(); | |
48 | 53 | |
49 | 54 | private: |
50 | 55 | ServiceList m_services; |
56 | Mutex m_waitMutex; | |
57 | ConditionVar m_waitCond; | |
58 | bool m_workenUp = false; | |
51 | 59 | |
52 | 60 | void RegisterService(Service* service); |
61 | void WakeUp(); | |
53 | 62 | |
54 | 63 | friend class Service; |
55 | 64 | }; |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
23 | 23 | |
24 | 24 | int Thread::m_threadCount = 1; // take the main program thread into account |
25 | 25 | std::unique_ptr<Mutex> Thread::m_threadMutex; |
26 | ||
27 | ||
28 | Mutex::Mutex() | |
29 | { | |
30 | #ifdef WIN32 | |
31 | InitializeCriticalSection(&m_mutexObj); | |
32 | #else | |
33 | pthread_mutex_init(&m_mutexObj, nullptr); | |
34 | #endif | |
35 | } | |
36 | ||
37 | Mutex::~Mutex() | |
38 | { | |
39 | #ifdef WIN32 | |
40 | DeleteCriticalSection(&m_mutexObj); | |
41 | #else | |
42 | pthread_mutex_destroy(&m_mutexObj); | |
43 | #endif | |
44 | } | |
45 | ||
46 | void Mutex::Lock() | |
47 | { | |
48 | #ifdef WIN32 | |
49 | EnterCriticalSection(&m_mutexObj); | |
50 | #ifdef DEBUG | |
51 | // CriticalSections on Windows can be locked many times from the same thread, | |
52 | // but we do not want this and must treat such situations as errors and detect them. | |
53 | if (m_mutexObj.RecursionCount > 1) | |
54 | { | |
55 | error("Internal program error: inconsistent thread-lock detected"); | |
56 | } | |
57 | #endif | |
58 | #else | |
59 | pthread_mutex_lock(&m_mutexObj); | |
60 | #endif | |
61 | } | |
62 | ||
63 | void Mutex::Unlock() | |
64 | { | |
65 | #ifdef WIN32 | |
66 | LeaveCriticalSection(&m_mutexObj); | |
67 | #else | |
68 | pthread_mutex_unlock(&m_mutexObj); | |
69 | #endif | |
70 | } | |
71 | 26 | |
72 | 27 | |
73 | 28 | void Thread::Init() |
93 | 48 | |
94 | 49 | m_running = true; |
95 | 50 | |
96 | // NOTE: we must guarantee, that in a time we set m_running | |
97 | // to value returned from pthread_create, the thread-object still exists. | |
98 | // This is not obvious! | |
99 | // pthread_create could wait long enough before returning result | |
100 | // back to allow the started thread to complete its job and terminate. | |
101 | // We lock mutex m_threadMutex on calling pthread_create; the started thread | |
102 | // then also try to lock the mutex (see thread_handler) and therefore | |
103 | // must wait until we unlock it | |
51 | // NOTE: "m_threadMutex" ensures that "t" lives until the very end of the function | |
104 | 52 | Guard guard(m_threadMutex); |
105 | 53 | |
106 | #ifdef WIN32 | |
107 | m_threadObj = (HANDLE)_beginthread(Thread::thread_handler, 0, (void*)this); | |
108 | m_running = m_threadObj != 0; | |
109 | #else | |
110 | pthread_attr_t m_attr; | |
111 | pthread_attr_init(&m_attr); | |
112 | pthread_attr_setdetachstate(&m_attr, PTHREAD_CREATE_DETACHED); | |
113 | pthread_attr_setinheritsched(&m_attr, PTHREAD_INHERIT_SCHED); | |
114 | m_running = !pthread_create(&m_threadObj, &m_attr, Thread::thread_handler, (void *) this); | |
115 | pthread_attr_destroy(&m_attr); | |
116 | #endif | |
54 | // start the new thread | |
55 | std::thread t([&]{ | |
56 | { | |
57 | // trying to lock "m_threadMutex", this will wait until function "Start()" is completed | |
58 | // and "t" is detached. | |
59 | Guard guard(m_threadMutex); | |
60 | } | |
61 | ||
62 | thread_handler(); | |
63 | }); | |
64 | ||
65 | // save the native handle to be able to cancel (Kill) the thread and then detach | |
66 | m_threadObj = t.native_handle(); | |
67 | t.detach(); | |
117 | 68 | } |
118 | 69 | |
119 | 70 | void Thread::Stop() |
154 | 105 | return terminated; |
155 | 106 | } |
156 | 107 | |
157 | #ifdef WIN32 | |
158 | void __cdecl Thread::thread_handler(void* object) | |
159 | #else | |
160 | void* Thread::thread_handler(void* object) | |
161 | #endif | |
108 | void Thread::thread_handler() | |
162 | 109 | { |
163 | { | |
164 | Guard guard(m_threadMutex); | |
165 | m_threadCount++; | |
166 | } | |
110 | m_threadCount++; | |
167 | 111 | |
168 | 112 | debug("Entering Thread-func"); |
169 | 113 | |
170 | Thread* thread = (Thread*)object; | |
171 | ||
172 | thread->Run(); | |
114 | Run(); | |
173 | 115 | |
174 | 116 | debug("Thread-func exited"); |
175 | 117 | |
176 | if (thread->m_autoDestroy) | |
118 | m_running = false; | |
119 | ||
120 | m_threadCount--; | |
121 | ||
122 | if (m_autoDestroy) | |
177 | 123 | { |
178 | 124 | debug("Autodestroying Thread-object"); |
179 | delete thread; | |
125 | delete this; | |
180 | 126 | } |
181 | else | |
182 | { | |
183 | thread->m_running = false; | |
184 | } | |
185 | ||
186 | { | |
187 | Guard guard(m_threadMutex); | |
188 | m_threadCount--; | |
189 | } | |
190 | ||
191 | #ifndef WIN32 | |
192 | return nullptr; | |
193 | #endif | |
194 | 127 | } |
195 | 128 | |
196 | 129 | int Thread::GetThreadCount() |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | 3 | * Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net> |
4 | * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
24 | 24 | class Mutex |
25 | 25 | { |
26 | 26 | public: |
27 | Mutex(); | |
27 | Mutex() {}; | |
28 | 28 | Mutex(const Mutex&) = delete; |
29 | ~Mutex(); | |
30 | void Lock(); | |
31 | void Unlock(); | |
29 | void Lock() { m_mutexObj.lock(); } | |
30 | void Unlock() { m_mutexObj.unlock(); } | |
32 | 31 | |
33 | 32 | private: |
34 | #ifdef WIN32 | |
35 | CRITICAL_SECTION m_mutexObj; | |
36 | #else | |
37 | pthread_mutex_t m_mutexObj; | |
38 | #endif | |
33 | std::mutex m_mutexObj; | |
34 | ||
35 | friend class ConditionVar; | |
39 | 36 | }; |
40 | 37 | |
41 | 38 | class Guard |
79 | 76 | void Unlock() { if (m_mutex) { m_mutex->Unlock(); m_mutex = nullptr; } } |
80 | 77 | }; |
81 | 78 | |
79 | class ConditionVar | |
80 | { | |
81 | public: | |
82 | ConditionVar() {} | |
83 | ConditionVar(const ConditionVar& other) = delete; | |
84 | void Wait(Mutex& mutex) { Lock l(mutex); m_condObj.wait(l); } | |
85 | template <typename Pred> void Wait(Mutex& mutex, Pred pred) { Lock l(mutex); m_condObj.wait(l, pred); } | |
86 | void WaitFor(Mutex& mutex, int msec) { Lock l(mutex); m_condObj.wait_for(l, std::chrono::milliseconds(msec)); } | |
87 | template <typename Pred> void WaitFor(Mutex& mutex, int msec, Pred pred) | |
88 | { Lock l(mutex); m_condObj.wait_for(l, std::chrono::milliseconds(msec), pred); } | |
89 | void NotifyOne() { m_condObj.notify_one(); } | |
90 | void NotifyAll() { m_condObj.notify_all(); } | |
91 | ||
92 | private: | |
93 | std::condition_variable m_condObj; | |
94 | ||
95 | struct Lock : public std::unique_lock<std::mutex> | |
96 | { | |
97 | Lock(Mutex& mutex) : std::unique_lock<std::mutex>(mutex.m_mutexObj, std::adopt_lock) {} | |
98 | ~Lock() { release(); } | |
99 | }; | |
100 | }; | |
101 | ||
82 | 102 | class Thread |
83 | 103 | { |
84 | 104 | public: |
104 | 124 | private: |
105 | 125 | static std::unique_ptr<Mutex> m_threadMutex; |
106 | 126 | static int m_threadCount; |
107 | #ifdef WIN32 | |
108 | HANDLE m_threadObj = 0; | |
109 | #else | |
110 | pthread_t m_threadObj = 0; | |
111 | #endif | |
127 | std::thread::native_handle_type m_threadObj = 0; | |
112 | 128 | bool m_running = false; |
113 | 129 | bool m_stopped = false; |
114 | 130 | bool m_autoDestroy = false; |
115 | 131 | |
116 | #ifdef WIN32 | |
117 | static void __cdecl thread_handler(void* object); | |
118 | #else | |
119 | static void *thread_handler(void* object); | |
120 | #endif | |
132 | void thread_handler(); | |
121 | 133 | }; |
122 | 134 | |
123 | 135 | #endif |
121 | 121 | } |
122 | 122 | |
123 | 123 | // init static vars there |
124 | GetCurrentTicks(); | |
124 | CurrentTicks(); | |
125 | 125 | } |
126 | 126 | |
127 | 127 | int64 Util::JoinInt64(uint32 Hi, uint32 Lo) |
492 | 492 | c -= a; c -= b; c ^= (b>>15); \ |
493 | 493 | } |
494 | 494 | |
495 | uint32 hash(register uint8 *k, register uint32 length, register uint32 initval) | |
495 | uint32 hash(uint8 *k, uint32 length, uint32 initval) | |
496 | 496 | // register uint8 *k; /* the key */ |
497 | 497 | // register uint32 length; /* the length of the key */ |
498 | 498 | // register uint32 initval; /* the previous hash, or an arbitrary value */ |
662 | 662 | return -1; |
663 | 663 | } |
664 | 664 | |
665 | int64 Util::GetCurrentTicks() | |
665 | int64 Util::CurrentTicks() | |
666 | 666 | { |
667 | 667 | #ifdef WIN32 |
668 | 668 | static int64 hz=0, hzo=0; |
678 | 678 | timeval t; |
679 | 679 | gettimeofday(&t, nullptr); |
680 | 680 | return (int64)(t.tv_sec) * 1000000ll + (int64)(t.tv_usec); |
681 | #endif | |
682 | } | |
683 | ||
684 | void Util::Sleep(int milliseconds) | |
685 | { | |
686 | #ifdef WIN32 | |
687 | ::Sleep(milliseconds); | |
688 | #else | |
689 | usleep(milliseconds * 1000); | |
681 | 690 | #endif |
682 | 691 | } |
683 | 692 |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
32 | 32 | { |
33 | 33 | public: |
34 | 34 | static bool MatchFileExt(const char* filename, const char* extensionList, const char* listSeparator); |
35 | static int64 GetCurrentTicks(); | |
36 | 35 | |
37 | 36 | /* |
38 | 37 | * Split command line into arguments. |
64 | 63 | static void SetStandByMode(bool standBy); |
65 | 64 | |
66 | 65 | static time_t CurrentTime(); |
66 | static int64 CurrentTicks(); | |
67 | static void Sleep(int milliseconds); | |
67 | 68 | |
68 | 69 | /* cross platform version of GNU timegm, which is similar to mktime but takes an UTC time as parameter */ |
69 | 70 | static time_t Timegm(tm const *t); |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2014-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2014-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
20 | 20 | #include "nzbget.h" |
21 | 21 | #include "Log.h" |
22 | 22 | #include "Options.h" |
23 | #include "WorkState.h" | |
23 | 24 | #include "FeedCoordinator.h" |
24 | 25 | #include "StatMeter.h" |
25 | 26 | #include "WinConsole.h" |
28 | 29 | #include "Util.h" |
29 | 30 | #include "resource.h" |
30 | 31 | |
31 | extern Options* g_Options; | |
32 | 32 | extern char* (*g_Arguments)[]; |
33 | 33 | extern int g_ArgumentCount; |
34 | 34 | extern void ExitProc(); |
35 | 35 | extern void Reload(); |
36 | 36 | extern WinConsole* g_WinConsole; |
37 | extern FeedCoordinator* g_FeedCoordinator; | |
38 | extern StatMeter* g_StatMeter; | |
39 | 37 | |
40 | 38 | #define UM_TRAYICON (WM_USER + 1) |
41 | 39 | #define UM_QUIT (WM_USER + 2) |
61 | 59 | ExitProc(); |
62 | 60 | while (g_WinConsole) |
63 | 61 | { |
64 | usleep(20 * 1000); | |
62 | Util::Sleep(20); | |
65 | 63 | } |
66 | 64 | return TRUE; |
67 | 65 | |
197 | 195 | } |
198 | 196 | else |
199 | 197 | { |
200 | usleep(20 * 1000); | |
198 | Util::Sleep(20); | |
201 | 199 | counter += 20; |
202 | 200 | if (counter >= 200) |
203 | 201 | { |
289 | 287 | case UM_TRAYICON: |
290 | 288 | if (lParam == WM_LBUTTONUP && !m_doubleClick) |
291 | 289 | { |
292 | g_Options->SetPauseDownload(!g_Options->GetPauseDownload()); | |
293 | g_Options->SetPausePostProcess(g_Options->GetPauseDownload()); | |
294 | g_Options->SetPauseScan(g_Options->GetPauseDownload()); | |
295 | g_Options->SetResumeTime(0); | |
290 | g_WorkState->SetPauseDownload(!g_WorkState->GetPauseDownload()); | |
291 | g_WorkState->SetPausePostProcess(g_WorkState->GetPauseDownload()); | |
292 | g_WorkState->SetPauseScan(g_WorkState->GetPauseDownload()); | |
293 | g_WorkState->SetResumeTime(0); | |
296 | 294 | UpdateTrayIcon(); |
297 | 295 | } |
298 | 296 | else if (lParam == WM_LBUTTONDBLCLK && m_doubleClick) |
661 | 659 | void WinConsole::ApplyPrefs() |
662 | 660 | { |
663 | 661 | ShowWindow(GetConsoleWindow(), m_showConsole ? SW_SHOW : SW_HIDE); |
662 | g_WorkState->SetPauseFrontend(!m_showConsole); | |
664 | 663 | if (m_showTrayIcon) |
665 | 664 | { |
666 | 665 | UpdateTrayIcon(); |
760 | 759 | strncpy(oldTip, m_iconData->szTip, sizeof(m_iconData->szTip)); |
761 | 760 | oldTip[200-1] = '\0'; |
762 | 761 | |
763 | if (g_Options->GetPauseDownload()) | |
762 | if (g_WorkState->GetPauseDownload()) | |
764 | 763 | { |
765 | 764 | m_iconData->hIcon = m_pausedIcon; |
766 | 765 | strncpy(m_iconData->szTip, "NZBGet - paused", sizeof(m_iconData->szTip)); |
767 | 766 | } |
768 | else if (!g_StatMeter->GetStandBy()) | |
767 | else if (g_WorkState->GetDownloading()) | |
769 | 768 | { |
770 | 769 | m_iconData->hIcon = m_workingIcon; |
771 | 770 | BString<100> tip("NZBGet - downloading at %s", *Util::FormatSpeed(g_StatMeter->CalcCurrentDownloadSpeed())); |
955 | 954 | BString<1024> path; |
956 | 955 | CString errmsg; |
957 | 956 | |
958 | g_Options->SetPauseDownload(true); | |
959 | g_Options->SetPausePostProcess(true); | |
957 | g_WorkState->SetPauseDownload(true); | |
958 | g_WorkState->SetPausePostProcess(true); | |
960 | 959 | |
961 | 960 | char commonAppDataPath[MAX_PATH]; |
962 | 961 | SHGetFolderPath(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, commonAppDataPath); |
972 | 971 | while (retry > 0 && FileSystem::DirectoryExists(path) && |
973 | 972 | !FileSystem::DeleteDirectoryWithContent(path, errmsg)) |
974 | 973 | { |
975 | usleep(200 * 1000); | |
974 | Util::Sleep(200); | |
976 | 975 | retry--; |
977 | 976 | } |
978 | 977 |
2912 | 2912 | for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) |
2913 | 2913 | if( !(*it)->matches( testCase ) ) |
2914 | 2914 | return false; |
2915 | return true; | |
2915 | return true; | |
2916 | 2916 | } |
2917 | 2917 | }; |
2918 | 2918 |
140 | 140 | virtual bool RepairData(u32 inputindex, size_t blocklength) { return false; } |
141 | 141 | |
142 | 142 | protected: |
143 | std::ostream& cout; | |
144 | std::ostream& cerr; | |
145 | ||
143 | 146 | ParHeaders* headers; // Headers |
144 | 147 | bool alreadyloaded; // Already loaded ? |
145 | 148 | CommandLine::NoiseLevel noiselevel; // OnScreen display |
195 | 198 | u64 totalsize; // Total data size |
196 | 199 | |
197 | 200 | bool cancelled; // repair cancelled |
198 | ||
199 | std::ostream& cout; | |
200 | std::ostream& cerr; | |
201 | 201 | }; |
202 | 202 | |
203 | 203 | } // end namespace Par2 |
229 | 229 | |
230 | 230 | // Allocate the left hand matrix |
231 | 231 | |
232 | leftmatrix = new G[outcount * incount]; | |
233 | memset(leftmatrix, 0, outcount * incount * sizeof(G)); | |
232 | leftmatrix = new G[outcount * incount](); | |
234 | 233 | |
235 | 234 | // Allocate the right hand matrix only if we are recovering |
236 | 235 | |
237 | 236 | G *rightmatrix = 0; |
238 | 237 | if (datamissing > 0) |
239 | 238 | { |
240 | rightmatrix = new G[outcount * outcount]; | |
241 | memset(rightmatrix, 0, outcount *outcount * sizeof(G)); | |
239 | rightmatrix = new G[outcount * outcount](); | |
242 | 240 | } |
243 | 241 | |
244 | 242 | // Fill in the two matrices: |
303 | 303 | buildroot-debug|buildroot-debug-strip) |
304 | 304 | LDFLAGS="-static $STRIP" \ |
305 | 305 | CXXFLAGS="-std=c++14 -g -fasynchronous-unwind-tables" \ |
306 | LIBS="-lcrypto -ldl -lz $LUBACKTRACE" \ | |
306 | LIBS="-lcrypto -ldl -lz -Wl,--whole-archive -lpthread -Wl,--no-whole-archive $LUBACKTRACE" \ | |
307 | 307 | ./configure --disable-dependency-tracking --host=$ARCH --enable-debug |
308 | 308 | ;; |
309 | 309 | buildroot-release|buildroot-release-nostrip) |
310 | 310 | LDFLAGS="-static $STRIP" \ |
311 | 311 | CXXFLAGS="-std=c++14 -O2 $DEBUG" \ |
312 | LIBS="-lcrypto -ldl -lz" \ | |
312 | LIBS="-lcrypto -ldl -lz -Wl,--whole-archive -lpthread -Wl,--no-whole-archive" \ | |
313 | 313 | ./configure --disable-dependency-tracking --host=$ARCH |
314 | 314 | ;; |
315 | 315 | ndk-debug|ndk-debug-strip) |
202 | 202 | <ClCompile Include="daemon\main\Maintenance.cpp" /> |
203 | 203 | <ClCompile Include="daemon\main\nzbget.cpp" /> |
204 | 204 | <ClCompile Include="daemon\main\Options.cpp" /> |
205 | <ClCompile Include="daemon\main\WorkState.cpp" /> | |
205 | 206 | <ClCompile Include="daemon\main\Scheduler.cpp" /> |
206 | 207 | <ClCompile Include="daemon\main\StackTrace.cpp" /> |
207 | 208 | <ClCompile Include="daemon\nntp\ArticleDownloader.cpp" /> |
307 | 308 | <ClInclude Include="daemon\main\Maintenance.h" /> |
308 | 309 | <ClInclude Include="daemon\main\nzbget.h" /> |
309 | 310 | <ClInclude Include="daemon\main\Options.h" /> |
311 | <ClInclude Include="daemon\main\WorkState.h" /> | |
310 | 312 | <ClInclude Include="daemon\main\Scheduler.h" /> |
311 | 313 | <ClInclude Include="daemon\main\StackTrace.h" /> |
312 | 314 | <ClInclude Include="daemon\nntp\ArticleDownloader.h" /> |
90 | 90 | import sys |
91 | 91 | import datetime |
92 | 92 | import smtplib |
93 | from urllib2 import quote | |
94 | 93 | |
95 | 94 | from email.mime.text import MIMEText |
96 | try: | |
97 | from xmlrpclib import ServerProxy # python 2 | |
98 | except ImportError: | |
99 | from xmlrpc.client import ServerProxy # python 3 | |
95 | from email.header import Header | |
96 | try: # python 2 | |
97 | from urllib2 import quote | |
98 | from xmlrpclib import ServerProxy | |
99 | except ImportError: # python 3 | |
100 | from urllib.parse import quote | |
101 | from xmlrpc.client import ServerProxy | |
100 | 102 | |
101 | 103 | # Exit codes used by NZBGet |
102 | 104 | POSTPROCESS_SUCCESS=93 |
253 | 255 | text += '\n%s\t%s\t%s' % (entry['Kind'], datetime.datetime.fromtimestamp(int(entry['Time'])), entry['Text']) |
254 | 256 | |
255 | 257 | # Create message |
256 | msg = MIMEText(text) | |
257 | msg['Subject'] = subject | |
258 | print('[DETAIL] Creating Email') | |
259 | msg = MIMEText(text.encode('utf-8'), 'plain', 'utf-8') | |
260 | msg['Subject'] = Header(subject, 'utf-8') | |
258 | 261 | msg['From'] = os.environ['NZBPO_FROM'] |
259 | 262 | msg['To'] = os.environ['NZBPO_TO'] |
260 | 263 | msg['Date'] = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000") |
35 | 35 | import os |
36 | 36 | import sys |
37 | 37 | import datetime |
38 | from urllib2 import quote # python 2/3 | |
39 | 38 | |
40 | 39 | try: |
41 | 40 | from xmlrpclib import ServerProxy # python 2 |
41 | from urllib2 import quote | |
42 | 42 | except ImportError: |
43 | 43 | from xmlrpc.client import ServerProxy # python 3 |
44 | from urllib.parse import quote | |
44 | 45 | |
45 | 46 | # Exit codes used by NZBGet |
46 | 47 | POSTPROCESS_SUCCESS=93 |
0 | 0 | import pytest |
1 | 1 | import subprocess |
2 | 2 | import os |
3 | import sys | |
4 | 3 | import time |
5 | 4 | import shutil |
6 | 5 | import base64 |
21 | 20 | nserv_datadir = nzbget_srcdir + '/tests/testdata/nserv.temp' |
22 | 21 | |
23 | 22 | sevenzip_bin = distutils.spawn.find_executable('7z') |
24 | if sevenzip_bin == None: | |
23 | if sevenzip_bin is None: | |
25 | 24 | sevenzip_bin = nzbget_srcdir + '/7z' + exe_ext |
26 | 25 | |
27 | 26 | par2_bin = distutils.spawn.find_executable('par2') |
28 | if par2_bin == None: | |
27 | if par2_bin is None: | |
29 | 28 | par2_bin = nzbget_srcdir + '/par2' + exe_ext |
30 | 29 | |
31 | 30 | has_failures = False |
109 | 108 | os.rename(nzbget_maindir, nzbget_maindir + '.old') |
110 | 109 | shutil.rmtree(nzbget_maindir + '.old') |
111 | 110 | completed = True |
112 | except: | |
111 | except Exception: | |
113 | 112 | if attempt > 20: |
114 | 113 | raise |
115 | 114 | attempt += 1 |
164 | 163 | for x in range(0, 3): |
165 | 164 | try: |
166 | 165 | stat = self.api.status() |
167 | except: | |
166 | except Exception: | |
168 | 167 | time.sleep(0.5) |
169 | 168 | |
170 | if stat == None: | |
169 | if stat is None: | |
171 | 170 | raise Exception('Could not start nzbget') |
172 | 171 | print('Started') |
173 | 172 | |
174 | 173 | def append_nzb(self, nzb_name, nzb_content, unpack = None, dupekey = '', dupescore = 0, dupemode = 'FORCE', params = None): |
175 | 174 | nzbcontent64 = base64.standard_b64encode(nzb_content) |
176 | if params == None: | |
175 | if params is None: | |
177 | 176 | params = [] |
178 | 177 | if unpack == True: |
179 | 178 | params.append(('*unpack:', 'yes')) |
0 | 0 | import os |
1 | 1 | import shutil |
2 | 2 | import subprocess |
3 | import random | |
4 | import array | |
5 | 3 | import pytest |
6 | 4 | |
7 | 5 | |
57 | 55 | os.makedirs(bigdir) |
58 | 56 | |
59 | 57 | f = open(bigdir + '/' + str(sizemb) + 'mb.dat', 'wb') |
60 | for n in xrange(sizemb / partmb): | |
61 | print('Writing block %i from %i' % (n + 1, sizemb / partmb)) | |
58 | for n in xrange(sizemb // partmb): | |
59 | print('Writing block %i from %i' % (n + 1, sizemb // partmb)) | |
62 | 60 | f.write(os.urandom(partmb * 1024 * 1024)) |
63 | 61 | f.close() |
64 | 62 |
0 | 0 | nzbget_options = ['SaveQueue=no'] |
1 | 1 | |
2 | 2 | import os |
3 | import time | |
4 | 3 | |
5 | 4 | nzbget = None |
6 | 5 | |
18 | 17 | nzbget.api.pausedownload() |
19 | 18 | |
20 | 19 | nzbget_srcdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) |
21 | testdata_dir = nzbget_srcdir + '/tests/testdata' | |
22 | 20 | fullfilename = nzbget_srcdir + '/tests/testdata/nzbfile/plain.nzb' |
23 | 21 | in_file = open(fullfilename, 'r') |
24 | 22 | nzb_content = in_file.read() |
9 | 9 | |
10 | 10 | nserv_datadir = pytest.config.getini('nserv_datadir') |
11 | 11 | nzbget_bin = pytest.config.getini('nzbget_bin') |
12 | sevenzip_bin = pytest.config.getini('sevenzip_bin') | |
13 | 12 | |
14 | 13 | if not os.path.exists(nserv_datadir): |
15 | 14 | print('Creating nserv datadir') |
81 | 81 | shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part02.rar', nserv_datadir + '/rar3ignoreext/testfile3-2.cbr') |
82 | 82 | shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part03.rar', nserv_datadir + '/rar3ignoreext/testfile3-3.cbr') |
83 | 83 | |
84 | if not os.path.exists(nserv_datadir + '/parjoin1.nzb'): | |
85 | os.makedirs(nserv_datadir + '/parjoin1') | |
86 | shutil.copyfile(testdata_dir + '/parchecker/testfile.dat', nserv_datadir + '/parjoin1/testfile.dat') | |
87 | shutil.copyfile(testdata_dir + '/parchecker/testfile.nfo', nserv_datadir + '/parjoin1/testfile.nfo') | |
88 | shutil.copyfile(testdata_dir + '/parchecker/testfile.par2', nserv_datadir + '/parjoin1/testfile.par2') | |
89 | shutil.copyfile(testdata_dir + '/parchecker/testfile.vol00+1.PAR2', nserv_datadir + '/parjoin1/testfile.vol00+1.PAR2') | |
90 | split_test_file(nserv_datadir + '/parjoin1', 'testfile.dat', 50244); | |
91 | ||
92 | if not os.path.exists(nserv_datadir + '/parjoin2.nzb'): | |
93 | os.makedirs(nserv_datadir + '/parjoin2') | |
94 | shutil.copyfile(testdata_dir + '/parchecker/testfile.dat', nserv_datadir + '/parjoin2/testfile.dat') | |
95 | shutil.copyfile(testdata_dir + '/parchecker/testfile.nfo', nserv_datadir + '/parjoin2/testfile.nfo') | |
96 | shutil.copyfile(testdata_dir + '/parchecker/testfile.par2', nserv_datadir + '/parjoin2/testfile.par2') | |
97 | shutil.copyfile(testdata_dir + '/parchecker/testfile.vol00+1.PAR2', nserv_datadir + '/parjoin2/testfile.vol00+1.PAR2') | |
98 | split_test_file(nserv_datadir + '/parjoin2', 'testfile.dat', 50244); | |
99 | os.rename(nserv_datadir + '/parjoin2/testfile.dat.001', nserv_datadir + '/parjoin2/renamed.001') | |
100 | os.rename(nserv_datadir + '/parjoin2/testfile.dat.002', nserv_datadir + '/parjoin2/renamed.002') | |
101 | os.rename(nserv_datadir + '/parjoin2/testfile.dat.003', nserv_datadir + '/parjoin2/renamed.003') | |
102 | ||
84 | 103 | if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '3000', '-q']): |
85 | 104 | pytest.exit('Test file generation failed') |
105 | ||
106 | if not os.path.exists(nserv_datadir + '/parjoin3.nzb'): | |
107 | os.makedirs(nserv_datadir + '/parjoin3') | |
108 | create_test_file(nserv_datadir + '/parjoin3', None, 20, 1) | |
109 | os.chdir(nserv_datadir + '/parjoin3') | |
110 | if 0 != subprocess.call([par2_bin, 'c', '-b100', 'parrename.par2', '*']): | |
111 | pytest.exit('Test file generation failed') | |
112 | split_test_file(nserv_datadir + '/parjoin3', '20mb.dat', 7*1024*1024); | |
113 | os.rename(nserv_datadir + '/parjoin3/20mb.dat.001', nserv_datadir + '/parjoin3/renamed.001') | |
114 | os.rename(nserv_datadir + '/parjoin3/20mb.dat.002', nserv_datadir + '/parjoin3/renamed.002') | |
115 | os.rename(nserv_datadir + '/parjoin3/20mb.dat.003', nserv_datadir + '/parjoin3/renamed.003') | |
116 | if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '100000', '-q']): | |
117 | pytest.exit('Test file generation failed') | |
86 | 118 | |
87 | 119 | if not os.path.exists(nserv_datadir + '/rarrename3sm'): |
88 | 120 | os.makedirs(nserv_datadir + '/rarrename3sm') |
92 | 124 | os.chdir(nserv_datadir + '/rarrename3sm') |
93 | 125 | if 0 != subprocess.call([par2_bin, 'c', '-b100', 'parrename.par2', '*']): |
94 | 126 | pytest.exit('Test file generation failed') |
95 | if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '500', '-q']): | |
96 | pytest.exit('Test file generation failed') | |
127 | if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '500', '-q']): | |
128 | pytest.exit('Test file generation failed') | |
97 | 129 | |
98 | 130 | if not os.path.exists(nserv_datadir + '/obfuscated1.nzb'): |
99 | 131 | create_test_file(nserv_datadir + '/obfuscated1', sevenzip_bin, 5, 1) |
162 | 194 | f.write(os.urandom(partmb * 1024 * 1024)) |
163 | 195 | f.close() |
164 | 196 | |
165 | if 0 != subprocess.call([sevenzip_bin, 'a', bigdir + '/' + str(sizemb) + 'mb.7z', '-mx=0', '-v' + str(partmb) + 'm', bigdir + '/' + str(sizemb) + 'mb.dat']): | |
166 | pytest.exit('Test file generation failed') | |
167 | ||
168 | os.remove(bigdir + '/' + str(sizemb) + 'mb.dat') | |
197 | if sevenzip_bin != None: | |
198 | if 0 != subprocess.call([sevenzip_bin, 'a', bigdir + '/' + str(sizemb) + 'mb.7z', '-mx=0', '-v' + str(partmb) + 'm', bigdir + '/' + str(sizemb) + 'mb.dat']): | |
199 | pytest.exit('Test file generation failed') | |
200 | ||
201 | os.remove(bigdir + '/' + str(sizemb) + 'mb.dat') | |
202 | ||
203 | def split_test_file(filedir, filename, partsize): | |
204 | print('Splitting test file ' + filename) | |
205 | ||
206 | inp = open(filedir + '/' + filename, 'rb') | |
207 | inp.seek(0,2) # move the cursor to the end of the file | |
208 | size = inp.tell() | |
209 | inp.seek(0,0) # move the cursor to the start of the file | |
210 | ||
211 | written = 0 | |
212 | part = 1 | |
213 | while (written < size): | |
214 | block = inp.read(partsize) | |
215 | written += partsize | |
216 | f = open(filedir + '/' + filename + '.' + str(part).zfill(3), 'wb') | |
217 | f.write(block) | |
218 | f.close() | |
219 | part += 1 | |
220 | inp.close() | |
221 | ||
222 | os.remove(filedir + '/' + filename) |
82 | 82 | |
83 | 83 | def test_rename_obf2(nserv, nzbget): |
84 | 84 | hist = nzbget.download_nzb('obfuscated2.nzb', unpack=True) |
85 | assert hist['Status'] == 'SUCCESS/UNPACK'⏎ | |
85 | assert hist['Status'] == 'SUCCESS/UNPACK' | |
86 | ||
87 | def test_parjoin_1(nserv, nzbget): | |
88 | hist = nzbget.download_nzb('parjoin1.nzb', unpack=True) | |
89 | assert hist['Status'] == 'SUCCESS/PAR' | |
90 | ||
91 | def test_parjoin_2(nserv, nzbget): | |
92 | hist = nzbget.download_nzb('parjoin2.nzb', unpack=True) | |
93 | assert hist['Status'] == 'SUCCESS/PAR' | |
94 | ||
95 | def test_parjoin_3(nserv, nzbget): | |
96 | hist = nzbget.download_nzb('parjoin3.nzb', unpack=True) | |
97 | assert hist['Status'] == 'SUCCESS/PAR' |
14 | 14 | def test_rename_obf2(nserv, nzbget): |
15 | 15 | hist = nzbget.download_nzb('obfuscated2.nzb', unpack=True) |
16 | 16 | assert hist['Status'] == 'SUCCESS/HEALTH' |
17 | ||
18 | def test_parjoin_1(nserv, nzbget): | |
19 | hist = nzbget.download_nzb('parjoin1.nzb', unpack=True) | |
20 | assert hist['Status'] == 'SUCCESS/UNPACK' | |
21 | ||
22 | def test_parjoin_2(nserv, nzbget): | |
23 | hist = nzbget.download_nzb('parjoin2.nzb', unpack=True) | |
24 | assert hist['Status'] == 'WARNING/DAMAGED' | |
25 | ||
26 | def test_parjoin_3(nserv, nzbget): | |
27 | hist = nzbget.download_nzb('parjoin3.nzb', unpack=True) | |
28 | assert hist['Status'] == 'WARNING/DAMAGED' |
82 | 82 | assert hist['Status'] == 'SUCCESS/HEALTH' |
83 | 83 | for entry in nzbget.api.loadlog(hist['ID'], 0, 10000): |
84 | 84 | assert entry['Kind'] != 'ERROR', entry['Text'] |
85 | ||
86 | def test_parjoin_1(nserv, nzbget): | |
87 | hist = nzbget.download_nzb('parjoin1.nzb', unpack=True) | |
88 | assert hist['Status'] == 'SUCCESS/PAR' | |
89 | ||
90 | def test_parjoin_2(nserv, nzbget): | |
91 | hist = nzbget.download_nzb('parjoin2.nzb', unpack=True) | |
92 | assert hist['Status'] == 'SUCCESS/PAR' | |
93 | ||
94 | def test_parjoin_3(nserv, nzbget): | |
95 | hist = nzbget.download_nzb('parjoin3.nzb', unpack=True) | |
96 | assert hist['Status'] == 'SUCCESS/PAR' |
82 | 82 | assert hist['Status'] == 'SUCCESS/HEALTH' |
83 | 83 | for entry in nzbget.api.loadlog(hist['ID'], 0, 10000): |
84 | 84 | assert entry['Kind'] != 'ERROR', entry['Text'] |
85 | ||
86 | def test_parjoin_1(nserv, nzbget): | |
87 | hist = nzbget.download_nzb('parjoin1.nzb', unpack=True) | |
88 | assert hist['Status'] == 'SUCCESS/PAR' | |
89 | ||
90 | def test_parjoin_2(nserv, nzbget): | |
91 | hist = nzbget.download_nzb('parjoin2.nzb', unpack=True) | |
92 | assert hist['Status'] == 'SUCCESS/PAR' | |
93 | ||
94 | def test_parjoin_3(nserv, nzbget): | |
95 | hist = nzbget.download_nzb('parjoin3.nzb', unpack=True) | |
96 | assert hist['Status'] == 'SUCCESS/PAR' |
0 | nzbget_options = ['ParRename=yes', 'RarRename=yes', 'ParCheck=auto', 'DirectRename=yes', 'ParScan=full'] | |
1 | ||
2 | def test_parjoin_1(nserv, nzbget): | |
3 | hist = nzbget.download_nzb('parjoin1.nzb', unpack=True) | |
4 | assert hist['Status'] == 'SUCCESS/PAR' | |
5 | ||
6 | def test_parjoin_2(nserv, nzbget): | |
7 | hist = nzbget.download_nzb('parjoin2.nzb', unpack=True) | |
8 | assert hist['Status'] == 'SUCCESS/PAR' | |
9 | ||
10 | def test_parjoin_3(nserv, nzbget): | |
11 | hist = nzbget.download_nzb('parjoin3.nzb', unpack=True) | |
12 | assert hist['Status'] == 'SUCCESS/PAR' |
0 | nzbget_options = ['ParRename=yes', 'RarRename=yes', 'ParCheck=auto', 'DirectRename=no', 'ParScan=full'] | |
1 | ||
2 | def test_parjoin_1(nserv, nzbget): | |
3 | hist = nzbget.download_nzb('parjoin1.nzb', unpack=True) | |
4 | assert hist['Status'] == 'SUCCESS/PAR' | |
5 | ||
6 | def test_parjoin_2(nserv, nzbget): | |
7 | hist = nzbget.download_nzb('parjoin2.nzb', unpack=True) | |
8 | assert hist['Status'] == 'SUCCESS/PAR' | |
9 | ||
10 | def test_parjoin_3(nserv, nzbget): | |
11 | hist = nzbget.download_nzb('parjoin3.nzb', unpack=True) | |
12 | assert hist['Status'] == 'SUCCESS/PAR' |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2017-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
35 | 35 | EEditAction action, const char* args) { return false; } |
36 | 36 | virtual void HistoryChanged() {} |
37 | 37 | virtual void Save() {}; |
38 | virtual void SaveChanged() {} | |
38 | 39 | }; |
39 | 40 | |
40 | 41 | TEST_CASE("Direct-unpack simple", "[Rar][DirectUnpack][Unrar][Slow][TestData]") |
73 | 74 | ((DirectUnpack*)nzbPtr->GetUnpackThread())->NzbDownloaded(downloadQueue, nzbPtr); |
74 | 75 | break; |
75 | 76 | } |
76 | usleep(50*1000); | |
77 | Util::Sleep(50); | |
77 | 78 | } |
78 | 79 | |
79 | 80 | while (nzbPtr->GetDirectUnpackStatus() == NzbInfo::nsRunning) |
80 | 81 | { |
81 | usleep(20 * 1000); | |
82 | Util::Sleep(20); | |
82 | 83 | } |
83 | 84 | |
84 | 85 | REQUIRE(nzbPtr->GetDirectUnpackStatus() == NzbInfo::nsSuccess); |
128 | 129 | ((DirectUnpack*)nzbPtr->GetUnpackThread())->NzbDownloaded(downloadQueue, nzbPtr); |
129 | 130 | break; |
130 | 131 | } |
131 | usleep(50 * 1000); | |
132 | Util::Sleep(50); | |
132 | 133 | } |
133 | 134 | |
134 | 135 | while (nzbPtr->GetDirectUnpackStatus() == NzbInfo::nsRunning) |
135 | 136 | { |
136 | usleep(20 * 1000); | |
137 | Util::Sleep(20); | |
137 | 138 | } |
138 | 139 | |
139 | 140 | REQUIRE(nzbPtr->GetDirectUnpackStatus() == NzbInfo::nsSuccess); |
64 | 64 | void TestCleanup() |
65 | 65 | { |
66 | 66 | // If tests were run (via "TestMain") the Catch-framework does clean up automatically. |
67 | // Hoeweve if no tests were run the global objects remain alive and causing memory leak | |
67 | // However, if no tests were run, the global objects remain alive and causing memory leak | |
68 | 68 | // detection reports. Therefore we clean up the Catch-framework when we don't run any tests. |
69 | 69 | Catch::cleanUp(); |
70 | 70 | } |
21 | 21 | #include <iostream> |
22 | 22 | #include "catch.h" |
23 | 23 | |
24 | #include "Util.h" | |
24 | 25 | #include "FileSystem.h" |
25 | 26 | #include "TestUtil.h" |
26 | 27 | |
92 | 93 | FileSystem::DeleteDirectoryWithContent(workDir.c_str(), errmsg); |
93 | 94 | while (FileSystem::DirectoryExists(workDir.c_str()) && retries > 0) |
94 | 95 | { |
95 | usleep(1000 * 100); | |
96 | Util::Sleep(100); | |
96 | 97 | retries--; |
97 | 98 | FileSystem::DeleteDirectoryWithContent(workDir.c_str(), errmsg); |
98 | 99 | } |
46 | 46 | REQUIRE(!strcmp(str2, "0123456789 Hi, Worl")); |
47 | 47 | |
48 | 48 | BString<20> str3; |
49 | strncpy(str3, "Hello, 0123456789 world", str3.Capacity()); | |
49 | memcpy(str3, "Hello, 0123456789 world", str3.Capacity()); | |
50 | 50 | str3[str3.Capacity()] = '\0'; |
51 | 51 | REQUIRE(!strcmp(str3, "Hello, 0123456789 w")); |
52 | 52 |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
31 | 31 | |
32 | 32 | // Properties (public) |
33 | 33 | this.options; |
34 | this.postParamConfig; | |
34 | this.postParamConfig = []; | |
35 | 35 | this.categories = []; |
36 | 36 | this.restricted = false; |
37 | 37 | |
137 | 137 | |
138 | 138 | readWebSettings(config); |
139 | 139 | |
140 | var serverConfig = readConfigTemplate(serverTemplateData[0].Template, undefined, HIDDEN_SECTIONS, '', ''); | |
140 | var serverConfig = readConfigTemplate(serverTemplateData[0].Template, undefined, HIDDEN_SECTIONS, ''); | |
141 | 141 | mergeValues(serverConfig.sections, serverValues); |
142 | 142 | config.push(serverConfig); |
143 | 143 | |
147 | 147 | var scriptName = serverTemplateData[i].Name; |
148 | 148 | var scriptConfig = readConfigTemplate(serverTemplateData[i].Template, undefined, HIDDEN_SECTIONS, scriptName + ':'); |
149 | 149 | scriptConfig.scriptName = scriptName; |
150 | scriptConfig.id = scriptName.replace(/ |\/|\\|[\.|$|\:|\*]/g, '_'); | |
150 | scriptConfig.id = Util.makeId(scriptName); | |
151 | 151 | scriptConfig.name = scriptName.substr(0, scriptName.lastIndexOf('.')) || scriptName; // remove file extension |
152 | 152 | scriptConfig.name = scriptConfig.name.replace(/\\/, ' \\ ').replace(/\//, ' / '); |
153 | 153 | scriptConfig.shortName = shortScriptName(scriptName); |
185 | 185 | webValues.push({Name: optname, Value: value.toString()}); |
186 | 186 | } |
187 | 187 | |
188 | var webConfig = readConfigTemplate(webTemplate, undefined, '', '', ''); | |
188 | var webConfig = readConfigTemplate(webTemplate, undefined, '', ''); | |
189 | 189 | mergeValues(webConfig.sections, webValues); |
190 | 190 | config.push(webConfig); |
191 | 191 | } |
215 | 215 | { |
216 | 216 | var section = {}; |
217 | 217 | section.name = line.substr(4, line.length - 8).trim(); |
218 | section.id = (nameprefix + section.name).replace(/ |\/|\\|[\.|$|\:|\*]/g, '_'); | |
218 | section.id = Util.makeId(nameprefix + section.name); | |
219 | 219 | section.options = []; |
220 | 220 | description = ''; |
221 | 221 | section.hidden = !(hiddensections === undefined || (hiddensections.indexOf(section.name) == -1)) || |
252 | 252 | // bad template file; create default section. |
253 | 253 | section = {}; |
254 | 254 | section.name = 'OPTIONS'; |
255 | section.id = (nameprefix + section.name).replace(/ |\/|[\.|$|\:|\*]/g, '_'); | |
255 | section.id = Util.makeId(nameprefix + section.name); | |
256 | 256 | section.options = []; |
257 | 257 | description = ''; |
258 | 258 | config.sections.push(section); |
456 | 456 | if (data[i].PostScript || data[i].QueueScript) |
457 | 457 | { |
458 | 458 | var scriptName = data[i].Name; |
459 | var sectionId = (scriptName + ':').replace(/ |\/|[\.|$|\:|\*]/g, '_'); | |
459 | var sectionId = Util.makeId(scriptName + ':'); | |
460 | 460 | var option = {}; |
461 | 461 | option.name = scriptName + ':'; |
462 | 462 | option.caption = shortScriptName(scriptName); |
512 | 512 | |
513 | 513 | // State |
514 | 514 | var config = null; |
515 | var values; | |
516 | 515 | var filterText = ''; |
517 | 516 | var lastSection; |
518 | 517 | var reloadTime; |
769 | 768 | value = option.defvalue; |
770 | 769 | } |
771 | 770 | |
772 | option.formId = (option.name.indexOf(':') == -1 ? 'S_' : '') + option.name.replace(/ |\/|\\|[\.|$|\:|\*]/g, '_'); | |
771 | option.formId = (option.name.indexOf(':') == -1 ? 'S_' : '') + Util.makeId(option.name); | |
773 | 772 | |
774 | 773 | var caption = option.caption; |
775 | 774 | if (section.multi) |
959 | 958 | |
960 | 959 | if (!hasmore) |
961 | 960 | { |
962 | var nextid = hasoptions ? multiid + 1 : 1; | |
963 | 961 | html += '<div class="' + section.id + '">'; |
964 | 962 | html += '<button type="button" class="btn config-add ' + section.id + ' multiset" onclick="Config.addSet(\'' + setname + '\',\'' + section.id + |
965 | 963 | '\')">Add ' + (hasoptions ? 'another ' : '') + setname + '</button>'; |
1160 | 1158 | |
1161 | 1159 | this.switchClick = function(control) |
1162 | 1160 | { |
1163 | var state = $(control).val().toLowerCase(); | |
1164 | 1161 | $('.btn', $(control).parent()).removeClass('btn-primary'); |
1165 | 1162 | $(control).addClass('btn-primary'); |
1166 | 1163 | |
2667 | 2664 | { |
2668 | 2665 | e.preventDefault(); |
2669 | 2666 | |
2670 | var selectedSections = []; | |
2671 | 2667 | var checkedRows = $SectionTable.fasttable('checkedRows'); |
2672 | 2668 | var checkedCount = $SectionTable.fasttable('checkedCount'); |
2673 | 2669 | if (checkedCount === 0) |
3001 | 2997 | e.preventDefault(); |
3002 | 2998 | var kind = $(this).attr('data-kind'); |
3003 | 2999 | var script = PackageInfo['install-script']; |
3004 | var info = PackageInfo['install-' + kind + '-info']; | |
3005 | 3000 | |
3006 | 3001 | if (!script) |
3007 | 3002 | { |
3137 | 3132 | var $ExecScriptDialog_Status; |
3138 | 3133 | |
3139 | 3134 | // State |
3140 | var logReceived = false; | |
3141 | 3135 | var visible = false; |
3142 | 3136 | |
3143 | 3137 | this.init = function() |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
43 | 43 | var notification = null; |
44 | 44 | var updateTabInfo; |
45 | 45 | var groups; |
46 | var urls; | |
47 | 46 | var nameColumnWidth = null; |
48 | 47 | var cached = false; |
49 | 48 | var lastDownloadRate; |
396 | 395 | { |
397 | 396 | var checkedRows = $DownloadsTable.fasttable('checkedRows'); |
398 | 397 | |
399 | var hasIDs = false; | |
400 | 398 | var checkedEditIDs = []; |
401 | 399 | for (var i = 0; i < groups.length; i++) |
402 | 400 | { |
895 | 893 | |
896 | 894 | this.buildPriority = function(group) |
897 | 895 | { |
898 | var priority = group.MaxPriority | |
896 | var priority = group.MaxPriority; | |
899 | 897 | var text; |
900 | 898 | |
901 | 899 | if (priority >= 900) text = ' <div class="icon-circle-red" title="Force priority"></div>'; |
1121 | 1119 | var deletePark = $('#DownloadsDeleteConfirmDialog_DeletePark', dialog).is(':checked'); |
1122 | 1120 | var deleteDirect = $('#DownloadsDeleteConfirmDialog_DeleteDirect', dialog).is(':checked'); |
1123 | 1121 | var deleteDupe = $('#DownloadsDeleteConfirmDialog_DeleteDupe', dialog).is(':checked'); |
1124 | var deleteFinal = $('#DownloadsDeleteConfirmDialog_DeleteFinal', dialog).is(':checked'); | |
1122 | //var deleteFinal = $('#DownloadsDeleteConfirmDialog_DeleteFinal', dialog).is(':checked'); | |
1125 | 1123 | var command = deletePark ? "GroupParkDelete" : (deleteDirect ? 'GroupDelete' : (deleteDupe ? 'GroupDupeDelete' : 'GroupFinalDelete')); |
1126 | 1124 | actionCallback(command); |
1127 | 1125 | } |
1139 | 1137 | |
1140 | 1138 | /*** DOWNLOADS ACTION MENU *************************************************************************/ |
1141 | 1139 | |
1142 | var DownloadsActionsMenu = (new function() | |
1140 | var DownloadsActionsMenu = (new function($) | |
1143 | 1141 | { |
1144 | 1142 | 'use strict' |
1145 | 1143 |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
130 | 130 | |
131 | 131 | curGroup = group; |
132 | 132 | |
133 | var status = DownloadsUI.buildStatus(group); | |
134 | var age = Util.formatAge(group.MinPostTime + UISettings.timeZoneCorrection*60*60); | |
135 | 133 | var size = Util.formatSizeMB(group.FileSizeMB, group.FileSizeLo); |
136 | 134 | var remaining = Util.formatSizeMB(group.RemainingSizeMB-group.PausedSizeMB, group.RemainingSizeLo-group.PausedSizeLo); |
137 | 135 | var pausedSize = Util.formatSizeMB(group.PausedSizeMB, group.PausedSizeLo); |
138 | var estimated = group.Status === 'PAUSED' ? '' : (Status.status.DownloadRate > 0 ? Util.formatTimeHMS((group.RemainingSizeMB-group.PausedSizeMB)*1024/(Status.status.DownloadRate/1024)) : ''); | |
139 | 136 | var completion = group.SuccessArticles + group.FailedArticles > 0 ? Util.round0(group.SuccessArticles * 100.0 / (group.SuccessArticles + group.FailedArticles)) + '%' : '--'; |
140 | 137 | if (group.FailedArticles > 0 && completion === '100%') |
141 | 138 | { |
1467 | 1464 | |
1468 | 1465 | /*** EDIT HISTORY DIALOG *************************************************************************/ |
1469 | 1466 | |
1470 | var HistoryEditDialog = (new function() | |
1467 | var HistoryEditDialog = (new function($) | |
1471 | 1468 | { |
1472 | 1469 | 'use strict' |
1473 | 1470 | |
1619 | 1616 | { |
1620 | 1617 | completion = '99.9%'; |
1621 | 1618 | } |
1622 | var time = Util.formatTimeHMS(hist.DownloadTimeSec + hist.PostTotalTimeSec); | |
1623 | 1619 | |
1624 | 1620 | var table = ''; |
1625 | 1621 | table += '<tr><td><a href="#" id="HistoryEdit_TimeStats" data-tab="HistoryEdit_TimeStatsTab" title="Size and time statistics">Total '+ |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
199 | 199 | return this.each(function() |
200 | 200 | { |
201 | 201 | var $this = $(this); |
202 | var data = $this.data('fasttable'); | |
203 | 202 | |
204 | 203 | // Namespacing FTW |
205 | 204 | $(window).unbind('.fasttable'); |
737 | 736 | function toggleCheck(data, id) |
738 | 737 | { |
739 | 738 | var checkedRows = data.checkedRows; |
740 | var index = checkedRows[id]; | |
741 | 739 | if (checkedRows[id]) |
742 | 740 | { |
743 | 741 | checkedRows[id] = undefined; |
819 | 817 | |
820 | 818 | function validateChecks(data) |
821 | 819 | { |
822 | var filteredContent = data.filteredContent; | |
823 | 820 | var checkedRows = data.checkedRows; |
824 | 821 | data.checkedRows = {} |
825 | 822 | data.checkedCount = 0; |
1261 | 1258 | 'use strict'; |
1262 | 1259 | |
1263 | 1260 | this.source; |
1264 | this.len; | |
1265 | this.p; | |
1261 | this.len = 0; | |
1262 | this.p = 0; | |
1266 | 1263 | |
1267 | 1264 | this.initLexer = function(source) |
1268 | 1265 | { |
1510 | 1507 | return value; |
1511 | 1508 | } |
1512 | 1509 | |
1513 | this.nameMap; | |
1510 | this.nameMap = undefined; | |
1514 | 1511 | this.buildNameMap = function(data) |
1515 | 1512 | { |
1516 | 1513 | this.nameMap = {}; |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2013-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2013-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
409 | 409 | var $Splitter; |
410 | 410 | var $FilterInput; |
411 | 411 | var $FilterBlock; |
412 | var $FilterLines; | |
413 | 412 | var $FilterNumbers; |
414 | 413 | var $PreviewBlock; |
415 | 414 | var $ModalBody; |
453 | 452 | $('#FeedFilterDialog_Save').click(save); |
454 | 453 | $FilterInput = $('#FeedFilterDialog_FilterInput'); |
455 | 454 | $FilterBlock = $('#FeedFilterDialog_FilterBlock'); |
456 | $FilterLines = $('#FeedFilterDialog_FilterLines'); | |
457 | 455 | $FilterNumbers = $('#FeedFilterDialog_FilterNumbers'); |
458 | 456 | $PreviewBlock = $('#FeedFilterDialog_PreviewBlock'); |
459 | 457 | $ModalBody = $('.modal-body', $FeedFilterDialog); |
895 | 893 | var lines = tarea.value.split("\n"); |
896 | 894 | |
897 | 895 | // calculate start/end |
898 | var startPos = 0, endPos = tarea.value.length; | |
896 | var startPos = 0; | |
899 | 897 | for (var x = 0; x < lines.length; x++) |
900 | 898 | { |
901 | 899 | if (x == lineNum) |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
653 | 653 | |
654 | 654 | /*** HISTORY ACTION MENU *************************************************************************/ |
655 | 655 | |
656 | var HistoryActionsMenu = (new function() | |
656 | var HistoryActionsMenu = (new function($) | |
657 | 657 | { |
658 | 658 | 'use strict' |
659 | 659 |
1 | 1 | <!-- |
2 | 2 | * This file is part of nzbget. See <http://nzbget.net>. |
3 | 3 | * |
4 | * Copyright (C) 2012-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License as published by |
77 | 77 | // prevent Android browsers from using of icon designed for iOS |
78 | 78 | if (window.navigator.userAgent.match(/iPhone/i) || window.navigator.userAgent.match(/iPad/i)) |
79 | 79 | { |
80 | document.write('<link rel="apple-touch-icon" href="img/favicon-256x256-opaque.png">'); | |
80 | document.write('<link rel="apple-touch-icon" href="img/favicon-256x256-opaque.png">'); // lgtm [js/eval-like-call] | |
81 | 81 | } |
82 | 82 | </script> |
83 | 83 | <!-- android --> |
319 | 319 | <th width="102px">Status</th> |
320 | 320 | <th class="dropafter-cell" id="DownloadsTable_Name"><a href="#" onclick="Downloads.sort('name', event)">Name</a></th> |
321 | 321 | <th id="DownloadsTable_Category"><a href="#" onclick="Downloads.sort('category', event)">Category</a></th> |
322 | <th class="dropafter-cell" width="30px" class="text-right"><a href="#" onclick="Downloads.sort('age', event)">Age</a></th> | |
322 | <th class="dropafter-cell text-right" width="30px"><a href="#" onclick="Downloads.sort('age', event)">Age</a></th> | |
323 | 323 | <th width="120px"><div style="float:left; position:relative; width:50%; text-align:left;"><a href="#"onclick="Downloads.sort('size', event)">Size</a></div><div style="float:right; position:relative; width:50%; text-align:right;"><a href="#" onclick="Downloads.sort('left', event)">Left</a></div></th> |
324 | 324 | <th width="60px" class="text-right">Est. Time</th> |
325 | 325 | </tr> |
2935 | 2935 | <strong>Please select records first</strong> |
2936 | 2936 | </div> |
2937 | 2937 | |
2938 | <div id="Notif_History_Deleted" data-duration="1000" class="alert alert-inverse alert-center alert-center-small hide"> | |
2939 | <strong>Deleted</strong> | |
2940 | </div> | |
2941 | ||
2942 | 2938 | <div id="Notif_History_Cleared" data-duration="1000" class="alert alert-inverse alert-center alert-center-small hide"> |
2943 | 2939 | <strong>Cleared</strong> |
2944 | 2940 | </div> |
0 | /*! | |
1 | * Bootstrap v2.0.3 | |
2 | * | |
3 | * Copyright 2012 Twitter, Inc | |
4 | * Licensed under the Apache License v2.0 | |
5 | * http://www.apache.org/licenses/LICENSE-2.0 | |
6 | * | |
7 | * Designed and built with all the love in the world @twitter by @mdo and @fat. | |
8 | */ | |
9 | ||
10 | article, | |
11 | aside, | |
12 | details, | |
13 | figcaption, | |
14 | figure, | |
15 | footer, | |
16 | header, | |
17 | hgroup, | |
18 | nav, | |
19 | section { | |
20 | display: block; | |
21 | } | |
22 | ||
23 | audio, | |
24 | canvas, | |
25 | video { | |
26 | display: inline-block; | |
27 | *display: inline; | |
28 | *zoom: 1; | |
29 | } | |
30 | ||
31 | audio:not([controls]) { | |
32 | display: none; | |
33 | } | |
34 | ||
35 | html { | |
36 | font-size: 100%; | |
37 | -webkit-text-size-adjust: 100%; | |
38 | -ms-text-size-adjust: 100%; | |
39 | } | |
40 | ||
41 | a:focus { | |
42 | outline: thin dotted #333; | |
43 | outline: 5px auto -webkit-focus-ring-color; | |
44 | outline-offset: -2px; | |
45 | } | |
46 | ||
47 | a:hover, | |
48 | a:active { | |
49 | outline: 0; | |
50 | } | |
51 | ||
52 | sub, | |
53 | sup { | |
54 | position: relative; | |
55 | font-size: 75%; | |
56 | line-height: 0; | |
57 | vertical-align: baseline; | |
58 | } | |
59 | ||
60 | sup { | |
61 | top: -0.5em; | |
62 | } | |
63 | ||
64 | sub { | |
65 | bottom: -0.25em; | |
66 | } | |
67 | ||
68 | img { | |
69 | max-width: 100%; | |
70 | vertical-align: middle; | |
71 | border: 0; | |
72 | -ms-interpolation-mode: bicubic; | |
73 | } | |
74 | ||
75 | button, | |
76 | input, | |
77 | select, | |
78 | textarea { | |
79 | margin: 0; | |
80 | font-size: 100%; | |
81 | vertical-align: middle; | |
82 | } | |
83 | ||
84 | button, | |
85 | input { | |
86 | *overflow: visible; | |
87 | line-height: normal; | |
88 | } | |
89 | ||
90 | button::-moz-focus-inner, | |
91 | input::-moz-focus-inner { | |
92 | padding: 0; | |
93 | border: 0; | |
94 | } | |
95 | ||
96 | button, | |
97 | input[type="button"], | |
98 | input[type="reset"], | |
99 | input[type="submit"] { | |
100 | cursor: pointer; | |
101 | -webkit-appearance: button; | |
102 | } | |
103 | ||
104 | input[type="search"] { | |
105 | -webkit-box-sizing: content-box; | |
106 | -moz-box-sizing: content-box; | |
107 | box-sizing: content-box; | |
108 | -webkit-appearance: textfield; | |
109 | } | |
110 | ||
111 | input[type="search"]::-webkit-search-decoration, | |
112 | input[type="search"]::-webkit-search-cancel-button { | |
113 | -webkit-appearance: none; | |
114 | } | |
115 | ||
116 | textarea { | |
117 | overflow: auto; | |
118 | vertical-align: top; | |
119 | } | |
120 | ||
121 | .clearfix { | |
122 | *zoom: 1; | |
123 | } | |
124 | ||
125 | .clearfix:before, | |
126 | .clearfix:after { | |
127 | display: table; | |
128 | content: ""; | |
129 | } | |
130 | ||
131 | .clearfix:after { | |
132 | clear: both; | |
133 | } | |
134 | ||
135 | .hide-text { | |
136 | font: 0/0 a; | |
137 | color: transparent; | |
138 | text-shadow: none; | |
139 | background-color: transparent; | |
140 | border: 0; | |
141 | } | |
142 | ||
143 | .input-block-level { | |
144 | display: block; | |
145 | width: 100%; | |
146 | min-height: 28px; | |
147 | -webkit-box-sizing: border-box; | |
148 | -moz-box-sizing: border-box; | |
149 | -ms-box-sizing: border-box; | |
150 | box-sizing: border-box; | |
151 | } | |
152 | ||
153 | body { | |
154 | margin: 0; | |
155 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
156 | font-size: 13px; | |
157 | line-height: 18px; | |
158 | color: #333333; | |
159 | background-color: #ffffff; | |
160 | } | |
161 | ||
162 | a { | |
163 | color: #0088cc; | |
164 | text-decoration: none; | |
165 | } | |
166 | ||
167 | a:hover { | |
168 | color: #005580; | |
169 | text-decoration: underline; | |
170 | } | |
171 | ||
172 | .row { | |
173 | margin-left: -20px; | |
174 | *zoom: 1; | |
175 | } | |
176 | ||
177 | .row:before, | |
178 | .row:after { | |
179 | display: table; | |
180 | content: ""; | |
181 | } | |
182 | ||
183 | .row:after { | |
184 | clear: both; | |
185 | } | |
186 | ||
187 | [class*="span"] { | |
188 | float: left; | |
189 | margin-left: 20px; | |
190 | } | |
191 | ||
192 | .container, | |
193 | .navbar-fixed-top .container, | |
194 | .navbar-fixed-bottom .container { | |
195 | width: 940px; | |
196 | } | |
197 | ||
198 | .span12 { | |
199 | width: 940px; | |
200 | } | |
201 | ||
202 | .span11 { | |
203 | width: 860px; | |
204 | } | |
205 | ||
206 | .span10 { | |
207 | width: 780px; | |
208 | } | |
209 | ||
210 | .span9 { | |
211 | width: 700px; | |
212 | } | |
213 | ||
214 | .span8 { | |
215 | width: 620px; | |
216 | } | |
217 | ||
218 | .span7 { | |
219 | width: 540px; | |
220 | } | |
221 | ||
222 | .span6 { | |
223 | width: 460px; | |
224 | } | |
225 | ||
226 | .span5 { | |
227 | width: 380px; | |
228 | } | |
229 | ||
230 | .span4 { | |
231 | width: 300px; | |
232 | } | |
233 | ||
234 | .span3 { | |
235 | width: 220px; | |
236 | } | |
237 | ||
238 | .span2 { | |
239 | width: 140px; | |
240 | } | |
241 | ||
242 | .span1 { | |
243 | width: 60px; | |
244 | } | |
245 | ||
246 | .offset12 { | |
247 | margin-left: 980px; | |
248 | } | |
249 | ||
250 | .offset11 { | |
251 | margin-left: 900px; | |
252 | } | |
253 | ||
254 | .offset10 { | |
255 | margin-left: 820px; | |
256 | } | |
257 | ||
258 | .offset9 { | |
259 | margin-left: 740px; | |
260 | } | |
261 | ||
262 | .offset8 { | |
263 | margin-left: 660px; | |
264 | } | |
265 | ||
266 | .offset7 { | |
267 | margin-left: 580px; | |
268 | } | |
269 | ||
270 | .offset6 { | |
271 | margin-left: 500px; | |
272 | } | |
273 | ||
274 | .offset5 { | |
275 | margin-left: 420px; | |
276 | } | |
277 | ||
278 | .offset4 { | |
279 | margin-left: 340px; | |
280 | } | |
281 | ||
282 | .offset3 { | |
283 | margin-left: 260px; | |
284 | } | |
285 | ||
286 | .offset2 { | |
287 | margin-left: 180px; | |
288 | } | |
289 | ||
290 | .offset1 { | |
291 | margin-left: 100px; | |
292 | } | |
293 | ||
294 | .row-fluid { | |
295 | width: 100%; | |
296 | *zoom: 1; | |
297 | } | |
298 | ||
299 | .row-fluid:before, | |
300 | .row-fluid:after { | |
301 | display: table; | |
302 | content: ""; | |
303 | } | |
304 | ||
305 | .row-fluid:after { | |
306 | clear: both; | |
307 | } | |
308 | ||
309 | .row-fluid [class*="span"] { | |
310 | display: block; | |
311 | float: left; | |
312 | width: 100%; | |
313 | min-height: 28px; | |
314 | margin-left: 2.127659574%; | |
315 | *margin-left: 2.0744680846382977%; | |
316 | -webkit-box-sizing: border-box; | |
317 | -moz-box-sizing: border-box; | |
318 | -ms-box-sizing: border-box; | |
319 | box-sizing: border-box; | |
320 | } | |
321 | ||
322 | .row-fluid [class*="span"]:first-child { | |
323 | margin-left: 0; | |
324 | } | |
325 | ||
326 | .row-fluid .span12 { | |
327 | width: 99.99999998999999%; | |
328 | *width: 99.94680850063828%; | |
329 | } | |
330 | ||
331 | .row-fluid .span11 { | |
332 | width: 91.489361693%; | |
333 | *width: 91.4361702036383%; | |
334 | } | |
335 | ||
336 | .row-fluid .span10 { | |
337 | width: 82.97872339599999%; | |
338 | *width: 82.92553190663828%; | |
339 | } | |
340 | ||
341 | .row-fluid .span9 { | |
342 | width: 74.468085099%; | |
343 | *width: 74.4148936096383%; | |
344 | } | |
345 | ||
346 | .row-fluid .span8 { | |
347 | width: 65.95744680199999%; | |
348 | *width: 65.90425531263828%; | |
349 | } | |
350 | ||
351 | .row-fluid .span7 { | |
352 | width: 57.446808505%; | |
353 | *width: 57.3936170156383%; | |
354 | } | |
355 | ||
356 | .row-fluid .span6 { | |
357 | width: 48.93617020799999%; | |
358 | *width: 48.88297871863829%; | |
359 | } | |
360 | ||
361 | .row-fluid .span5 { | |
362 | width: 40.425531911%; | |
363 | *width: 40.3723404216383%; | |
364 | } | |
365 | ||
366 | .row-fluid .span4 { | |
367 | width: 31.914893614%; | |
368 | *width: 31.8617021246383%; | |
369 | } | |
370 | ||
371 | .row-fluid .span3 { | |
372 | width: 23.404255317%; | |
373 | *width: 23.3510638276383%; | |
374 | } | |
375 | ||
376 | .row-fluid .span2 { | |
377 | width: 14.89361702%; | |
378 | *width: 14.8404255306383%; | |
379 | } | |
380 | ||
381 | .row-fluid .span1 { | |
382 | width: 6.382978723%; | |
383 | *width: 6.329787233638298%; | |
384 | } | |
385 | ||
386 | .container { | |
387 | margin-right: auto; | |
388 | margin-left: auto; | |
389 | *zoom: 1; | |
390 | } | |
391 | ||
392 | .container:before, | |
393 | .container:after { | |
394 | display: table; | |
395 | content: ""; | |
396 | } | |
397 | ||
398 | .container:after { | |
399 | clear: both; | |
400 | } | |
401 | ||
402 | .container-fluid { | |
403 | padding-right: 20px; | |
404 | padding-left: 20px; | |
405 | *zoom: 1; | |
406 | } | |
407 | ||
408 | .container-fluid:before, | |
409 | .container-fluid:after { | |
410 | display: table; | |
411 | content: ""; | |
412 | } | |
413 | ||
414 | .container-fluid:after { | |
415 | clear: both; | |
416 | } | |
417 | ||
418 | p { | |
419 | margin: 0 0 9px; | |
420 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
421 | font-size: 13px; | |
422 | line-height: 18px; | |
423 | } | |
424 | ||
425 | p small { | |
426 | font-size: 11px; | |
427 | color: #999999; | |
428 | } | |
429 | ||
430 | .lead { | |
431 | margin-bottom: 18px; | |
432 | font-size: 20px; | |
433 | font-weight: 200; | |
434 | line-height: 27px; | |
435 | } | |
436 | ||
437 | h1, | |
438 | h2, | |
439 | h3, | |
440 | h4, | |
441 | h5, | |
442 | h6 { | |
443 | margin: 0; | |
444 | font-family: inherit; | |
445 | font-weight: bold; | |
446 | color: inherit; | |
447 | text-rendering: optimizelegibility; | |
448 | } | |
449 | ||
450 | h1 small, | |
451 | h2 small, | |
452 | h3 small, | |
453 | h4 small, | |
454 | h5 small, | |
455 | h6 small { | |
456 | font-weight: normal; | |
457 | color: #999999; | |
458 | } | |
459 | ||
460 | h1 { | |
461 | font-size: 30px; | |
462 | line-height: 36px; | |
463 | } | |
464 | ||
465 | h1 small { | |
466 | font-size: 18px; | |
467 | } | |
468 | ||
469 | h2 { | |
470 | font-size: 24px; | |
471 | line-height: 36px; | |
472 | } | |
473 | ||
474 | h2 small { | |
475 | font-size: 18px; | |
476 | } | |
477 | ||
478 | h3 { | |
479 | font-size: 18px; | |
480 | line-height: 27px; | |
481 | } | |
482 | ||
483 | h3 small { | |
484 | font-size: 14px; | |
485 | } | |
486 | ||
487 | h4, | |
488 | h5, | |
489 | h6 { | |
490 | line-height: 18px; | |
491 | } | |
492 | ||
493 | h4 { | |
494 | font-size: 14px; | |
495 | } | |
496 | ||
497 | h4 small { | |
498 | font-size: 12px; | |
499 | } | |
500 | ||
501 | h5 { | |
502 | font-size: 12px; | |
503 | } | |
504 | ||
505 | h6 { | |
506 | font-size: 11px; | |
507 | color: #999999; | |
508 | text-transform: uppercase; | |
509 | } | |
510 | ||
511 | .page-header { | |
512 | padding-bottom: 17px; | |
513 | margin: 18px 0; | |
514 | border-bottom: 1px solid #eeeeee; | |
515 | } | |
516 | ||
517 | .page-header h1 { | |
518 | line-height: 1; | |
519 | } | |
520 | ||
521 | ul, | |
522 | ol { | |
523 | padding: 0; | |
524 | margin: 0 0 9px 25px; | |
525 | } | |
526 | ||
527 | ul ul, | |
528 | ul ol, | |
529 | ol ol, | |
530 | ol ul { | |
531 | margin-bottom: 0; | |
532 | } | |
533 | ||
534 | ul { | |
535 | list-style: disc; | |
536 | } | |
537 | ||
538 | ol { | |
539 | list-style: decimal; | |
540 | } | |
541 | ||
542 | li { | |
543 | line-height: 18px; | |
544 | } | |
545 | ||
546 | ul.unstyled, | |
547 | ol.unstyled { | |
548 | margin-left: 0; | |
549 | list-style: none; | |
550 | } | |
551 | ||
552 | dl { | |
553 | margin-bottom: 18px; | |
554 | } | |
555 | ||
556 | dt, | |
557 | dd { | |
558 | line-height: 18px; | |
559 | } | |
560 | ||
561 | dt { | |
562 | font-weight: bold; | |
563 | line-height: 17px; | |
564 | } | |
565 | ||
566 | dd { | |
567 | margin-left: 9px; | |
568 | } | |
569 | ||
570 | .dl-horizontal dt { | |
571 | float: left; | |
572 | width: 120px; | |
573 | overflow: hidden; | |
574 | clear: left; | |
575 | text-align: right; | |
576 | text-overflow: ellipsis; | |
577 | white-space: nowrap; | |
578 | } | |
579 | ||
580 | .dl-horizontal dd { | |
581 | margin-left: 130px; | |
582 | } | |
583 | ||
584 | hr { | |
585 | margin: 18px 0; | |
586 | border: 0; | |
587 | border-top: 1px solid #eeeeee; | |
588 | border-bottom: 1px solid #ffffff; | |
589 | } | |
590 | ||
591 | strong { | |
592 | font-weight: bold; | |
593 | } | |
594 | ||
595 | em { | |
596 | font-style: italic; | |
597 | } | |
598 | ||
599 | .muted { | |
600 | color: #999999; | |
601 | } | |
602 | ||
603 | abbr[title] { | |
604 | cursor: help; | |
605 | border-bottom: 1px dotted #ddd; | |
606 | } | |
607 | ||
608 | abbr.initialism { | |
609 | font-size: 90%; | |
610 | text-transform: uppercase; | |
611 | } | |
612 | ||
613 | blockquote { | |
614 | padding: 0 0 0 15px; | |
615 | margin: 0 0 18px; | |
616 | border-left: 5px solid #eeeeee; | |
617 | } | |
618 | ||
619 | blockquote p { | |
620 | margin-bottom: 0; | |
621 | font-size: 16px; | |
622 | font-weight: 300; | |
623 | line-height: 22.5px; | |
624 | } | |
625 | ||
626 | blockquote small { | |
627 | display: block; | |
628 | line-height: 18px; | |
629 | color: #999999; | |
630 | } | |
631 | ||
632 | blockquote small:before { | |
633 | content: '\2014 \00A0'; | |
634 | } | |
635 | ||
636 | blockquote.pull-right { | |
637 | float: right; | |
638 | padding-right: 15px; | |
639 | padding-left: 0; | |
640 | border-right: 5px solid #eeeeee; | |
641 | border-left: 0; | |
642 | } | |
643 | ||
644 | blockquote.pull-right p, | |
645 | blockquote.pull-right small { | |
646 | text-align: right; | |
647 | } | |
648 | ||
649 | q:before, | |
650 | q:after, | |
651 | blockquote:before, | |
652 | blockquote:after { | |
653 | content: ""; | |
654 | } | |
655 | ||
656 | address { | |
657 | display: block; | |
658 | margin-bottom: 18px; | |
659 | font-style: normal; | |
660 | line-height: 18px; | |
661 | } | |
662 | ||
663 | small { | |
664 | font-size: 100%; | |
665 | } | |
666 | ||
667 | cite { | |
668 | font-style: normal; | |
669 | } | |
670 | ||
671 | code, | |
672 | pre { | |
673 | padding: 0 3px 2px; | |
674 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; | |
675 | font-size: 12px; | |
676 | color: #333333; | |
677 | -webkit-border-radius: 3px; | |
678 | -moz-border-radius: 3px; | |
679 | border-radius: 3px; | |
680 | } | |
681 | ||
682 | code { | |
683 | padding: 2px 4px; | |
684 | color: #d14; | |
685 | background-color: #f7f7f9; | |
686 | border: 1px solid #e1e1e8; | |
687 | } | |
688 | ||
689 | pre { | |
690 | display: block; | |
691 | padding: 8.5px; | |
692 | margin: 0 0 9px; | |
693 | font-size: 12.025px; | |
694 | line-height: 18px; | |
695 | word-break: break-all; | |
696 | word-wrap: break-word; | |
697 | white-space: pre; | |
698 | white-space: pre-wrap; | |
699 | background-color: #f5f5f5; | |
700 | border: 1px solid #ccc; | |
701 | border: 1px solid rgba(0, 0, 0, 0.15); | |
702 | -webkit-border-radius: 4px; | |
703 | -moz-border-radius: 4px; | |
704 | border-radius: 4px; | |
705 | } | |
706 | ||
707 | pre.prettyprint { | |
708 | margin-bottom: 18px; | |
709 | } | |
710 | ||
711 | pre code { | |
712 | padding: 0; | |
713 | color: inherit; | |
714 | background-color: transparent; | |
715 | border: 0; | |
716 | } | |
717 | ||
718 | .pre-scrollable { | |
719 | max-height: 340px; | |
720 | overflow-y: scroll; | |
721 | } | |
722 | ||
723 | form { | |
724 | margin: 0 0 18px; | |
725 | } | |
726 | ||
727 | fieldset { | |
728 | padding: 0; | |
729 | margin: 0; | |
730 | border: 0; | |
731 | } | |
732 | ||
733 | legend { | |
734 | display: block; | |
735 | width: 100%; | |
736 | padding: 0; | |
737 | margin-bottom: 27px; | |
738 | font-size: 19.5px; | |
739 | line-height: 36px; | |
740 | color: #333333; | |
741 | border: 0; | |
742 | border-bottom: 1px solid #eee; | |
743 | } | |
744 | ||
745 | legend small { | |
746 | font-size: 13.5px; | |
747 | color: #999999; | |
748 | } | |
749 | ||
750 | label, | |
751 | input, | |
752 | button, | |
753 | select, | |
754 | textarea { | |
755 | font-size: 13px; | |
756 | font-weight: normal; | |
757 | line-height: 18px; | |
758 | } | |
759 | ||
760 | input, | |
761 | button, | |
762 | select, | |
763 | textarea { | |
764 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
765 | } | |
766 | ||
767 | label { | |
768 | display: block; | |
769 | margin-bottom: 5px; | |
770 | color: #333333; | |
771 | } | |
772 | ||
773 | input, | |
774 | textarea, | |
775 | select, | |
776 | .uneditable-input { | |
777 | display: inline-block; | |
778 | width: 210px; | |
779 | height: 18px; | |
780 | padding: 4px; | |
781 | margin-bottom: 9px; | |
782 | font-size: 13px; | |
783 | line-height: 18px; | |
784 | color: #555555; | |
785 | background-color: #ffffff; | |
786 | border: 1px solid #cccccc; | |
787 | -webkit-border-radius: 3px; | |
788 | -moz-border-radius: 3px; | |
789 | border-radius: 3px; | |
790 | } | |
791 | ||
792 | .uneditable-textarea { | |
793 | width: auto; | |
794 | height: auto; | |
795 | } | |
796 | ||
797 | label input, | |
798 | label textarea, | |
799 | label select { | |
800 | display: block; | |
801 | } | |
802 | ||
803 | input[type="image"], | |
804 | input[type="checkbox"], | |
805 | input[type="radio"] { | |
806 | width: auto; | |
807 | height: auto; | |
808 | padding: 0; | |
809 | margin: 3px 0; | |
810 | *margin-top: 0; | |
811 | /* IE7 */ | |
812 | ||
813 | line-height: normal; | |
814 | cursor: pointer; | |
815 | background-color: transparent; | |
816 | border: 0 \9; | |
817 | /* IE9 and down */ | |
818 | ||
819 | -webkit-border-radius: 0; | |
820 | -moz-border-radius: 0; | |
821 | border-radius: 0; | |
822 | } | |
823 | ||
824 | input[type="image"] { | |
825 | border: 0; | |
826 | } | |
827 | ||
828 | input[type="file"] { | |
829 | width: auto; | |
830 | padding: initial; | |
831 | line-height: initial; | |
832 | background-color: #ffffff; | |
833 | background-color: initial; | |
834 | border: initial; | |
835 | -webkit-box-shadow: none; | |
836 | -moz-box-shadow: none; | |
837 | box-shadow: none; | |
838 | } | |
839 | ||
840 | input[type="button"], | |
841 | input[type="reset"], | |
842 | input[type="submit"] { | |
843 | width: auto; | |
844 | height: auto; | |
845 | } | |
846 | ||
847 | select, | |
848 | input[type="file"] { | |
849 | height: 28px; | |
850 | /* In IE7, the height of the select element cannot be changed by height, only font-size */ | |
851 | ||
852 | *margin-top: 4px; | |
853 | /* For IE7, add top margin to align select with labels */ | |
854 | ||
855 | line-height: 28px; | |
856 | } | |
857 | ||
858 | input[type="file"] { | |
859 | line-height: 18px \9; | |
860 | } | |
861 | ||
862 | select { | |
863 | width: 220px; | |
864 | background-color: #ffffff; | |
865 | } | |
866 | ||
867 | select[multiple], | |
868 | select[size] { | |
869 | height: auto; | |
870 | } | |
871 | ||
872 | input[type="image"] { | |
873 | -webkit-box-shadow: none; | |
874 | -moz-box-shadow: none; | |
875 | box-shadow: none; | |
876 | } | |
877 | ||
878 | textarea { | |
879 | height: auto; | |
880 | } | |
881 | ||
882 | input[type="hidden"] { | |
883 | display: none; | |
884 | } | |
885 | ||
886 | .radio, | |
887 | .checkbox { | |
888 | min-height: 18px; | |
889 | padding-left: 18px; | |
890 | } | |
891 | ||
892 | .radio input[type="radio"], | |
893 | .checkbox input[type="checkbox"] { | |
894 | float: left; | |
895 | margin-left: -18px; | |
896 | } | |
897 | ||
898 | .controls > .radio:first-child, | |
899 | .controls > .checkbox:first-child { | |
900 | padding-top: 5px; | |
901 | } | |
902 | ||
903 | .radio.inline, | |
904 | .checkbox.inline { | |
905 | display: inline-block; | |
906 | padding-top: 5px; | |
907 | margin-bottom: 0; | |
908 | vertical-align: middle; | |
909 | } | |
910 | ||
911 | .radio.inline + .radio.inline, | |
912 | .checkbox.inline + .checkbox.inline { | |
913 | margin-left: 10px; | |
914 | } | |
915 | ||
916 | input, | |
917 | textarea { | |
918 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); | |
919 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); | |
920 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); | |
921 | -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; | |
922 | -moz-transition: border linear 0.2s, box-shadow linear 0.2s; | |
923 | -ms-transition: border linear 0.2s, box-shadow linear 0.2s; | |
924 | -o-transition: border linear 0.2s, box-shadow linear 0.2s; | |
925 | transition: border linear 0.2s, box-shadow linear 0.2s; | |
926 | } | |
927 | ||
928 | input:focus, | |
929 | textarea:focus { | |
930 | border-color: rgba(82, 168, 236, 0.8); | |
931 | outline: 0; | |
932 | outline: thin dotted \9; | |
933 | /* IE6-9 */ | |
934 | ||
935 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); | |
936 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); | |
937 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); | |
938 | } | |
939 | ||
940 | input[type="file"]:focus, | |
941 | input[type="radio"]:focus, | |
942 | input[type="checkbox"]:focus, | |
943 | select:focus { | |
944 | outline: thin dotted #333; | |
945 | outline: 5px auto -webkit-focus-ring-color; | |
946 | outline-offset: -2px; | |
947 | -webkit-box-shadow: none; | |
948 | -moz-box-shadow: none; | |
949 | box-shadow: none; | |
950 | } | |
951 | ||
952 | .input-mini { | |
953 | width: 60px; | |
954 | } | |
955 | ||
956 | .input-small { | |
957 | width: 90px; | |
958 | } | |
959 | ||
960 | .input-medium { | |
961 | width: 150px; | |
962 | } | |
963 | ||
964 | .input-large { | |
965 | width: 210px; | |
966 | } | |
967 | ||
968 | .input-xlarge { | |
969 | width: 270px; | |
970 | } | |
971 | ||
972 | .input-xxlarge { | |
973 | width: 530px; | |
974 | } | |
975 | ||
976 | input[class*="span"], | |
977 | select[class*="span"], | |
978 | textarea[class*="span"], | |
979 | .uneditable-input[class*="span"], | |
980 | .row-fluid input[class*="span"], | |
981 | .row-fluid select[class*="span"], | |
982 | .row-fluid textarea[class*="span"], | |
983 | .row-fluid .uneditable-input[class*="span"] { | |
984 | float: none; | |
985 | margin-left: 0; | |
986 | } | |
987 | ||
988 | input, | |
989 | textarea, | |
990 | .uneditable-input { | |
991 | margin-left: 0; | |
992 | } | |
993 | ||
994 | input.span12, | |
995 | textarea.span12, | |
996 | .uneditable-input.span12 { | |
997 | width: 930px; | |
998 | } | |
999 | ||
1000 | input.span11, | |
1001 | textarea.span11, | |
1002 | .uneditable-input.span11 { | |
1003 | width: 850px; | |
1004 | } | |
1005 | ||
1006 | input.span10, | |
1007 | textarea.span10, | |
1008 | .uneditable-input.span10 { | |
1009 | width: 770px; | |
1010 | } | |
1011 | ||
1012 | input.span9, | |
1013 | textarea.span9, | |
1014 | .uneditable-input.span9 { | |
1015 | width: 690px; | |
1016 | } | |
1017 | ||
1018 | input.span8, | |
1019 | textarea.span8, | |
1020 | .uneditable-input.span8 { | |
1021 | width: 610px; | |
1022 | } | |
1023 | ||
1024 | input.span7, | |
1025 | textarea.span7, | |
1026 | .uneditable-input.span7 { | |
1027 | width: 530px; | |
1028 | } | |
1029 | ||
1030 | input.span6, | |
1031 | textarea.span6, | |
1032 | .uneditable-input.span6 { | |
1033 | width: 450px; | |
1034 | } | |
1035 | ||
1036 | input.span5, | |
1037 | textarea.span5, | |
1038 | .uneditable-input.span5 { | |
1039 | width: 370px; | |
1040 | } | |
1041 | ||
1042 | input.span4, | |
1043 | textarea.span4, | |
1044 | .uneditable-input.span4 { | |
1045 | width: 290px; | |
1046 | } | |
1047 | ||
1048 | input.span3, | |
1049 | textarea.span3, | |
1050 | .uneditable-input.span3 { | |
1051 | width: 210px; | |
1052 | } | |
1053 | ||
1054 | input.span2, | |
1055 | textarea.span2, | |
1056 | .uneditable-input.span2 { | |
1057 | width: 130px; | |
1058 | } | |
1059 | ||
1060 | input.span1, | |
1061 | textarea.span1, | |
1062 | .uneditable-input.span1 { | |
1063 | width: 50px; | |
1064 | } | |
1065 | ||
1066 | input[disabled], | |
1067 | select[disabled], | |
1068 | textarea[disabled], | |
1069 | input[readonly], | |
1070 | select[readonly], | |
1071 | textarea[readonly] { | |
1072 | cursor: not-allowed; | |
1073 | background-color: #eeeeee; | |
1074 | border-color: #ddd; | |
1075 | } | |
1076 | ||
1077 | input[type="radio"][disabled], | |
1078 | input[type="checkbox"][disabled], | |
1079 | input[type="radio"][readonly], | |
1080 | input[type="checkbox"][readonly] { | |
1081 | background-color: transparent; | |
1082 | } | |
1083 | ||
1084 | .control-group.warning > label, | |
1085 | .control-group.warning .help-block, | |
1086 | .control-group.warning .help-inline { | |
1087 | color: #c09853; | |
1088 | } | |
1089 | ||
1090 | .control-group.warning input, | |
1091 | .control-group.warning select, | |
1092 | .control-group.warning textarea { | |
1093 | color: #c09853; | |
1094 | border-color: #c09853; | |
1095 | } | |
1096 | ||
1097 | .control-group.warning input:focus, | |
1098 | .control-group.warning select:focus, | |
1099 | .control-group.warning textarea:focus { | |
1100 | border-color: #a47e3c; | |
1101 | -webkit-box-shadow: 0 0 6px #dbc59e; | |
1102 | -moz-box-shadow: 0 0 6px #dbc59e; | |
1103 | box-shadow: 0 0 6px #dbc59e; | |
1104 | } | |
1105 | ||
1106 | .control-group.warning .input-prepend .add-on, | |
1107 | .control-group.warning .input-append .add-on { | |
1108 | color: #c09853; | |
1109 | background-color: #fcf8e3; | |
1110 | border-color: #c09853; | |
1111 | } | |
1112 | ||
1113 | .control-group.error > label, | |
1114 | .control-group.error .help-block, | |
1115 | .control-group.error .help-inline { | |
1116 | color: #b94a48; | |
1117 | } | |
1118 | ||
1119 | .control-group.error input, | |
1120 | .control-group.error select, | |
1121 | .control-group.error textarea { | |
1122 | color: #b94a48; | |
1123 | border-color: #b94a48; | |
1124 | } | |
1125 | ||
1126 | .control-group.error input:focus, | |
1127 | .control-group.error select:focus, | |
1128 | .control-group.error textarea:focus { | |
1129 | border-color: #953b39; | |
1130 | -webkit-box-shadow: 0 0 6px #d59392; | |
1131 | -moz-box-shadow: 0 0 6px #d59392; | |
1132 | box-shadow: 0 0 6px #d59392; | |
1133 | } | |
1134 | ||
1135 | .control-group.error .input-prepend .add-on, | |
1136 | .control-group.error .input-append .add-on { | |
1137 | color: #b94a48; | |
1138 | background-color: #f2dede; | |
1139 | border-color: #b94a48; | |
1140 | } | |
1141 | ||
1142 | .control-group.success > label, | |
1143 | .control-group.success .help-block, | |
1144 | .control-group.success .help-inline { | |
1145 | color: #468847; | |
1146 | } | |
1147 | ||
1148 | .control-group.success input, | |
1149 | .control-group.success select, | |
1150 | .control-group.success textarea { | |
1151 | color: #468847; | |
1152 | border-color: #468847; | |
1153 | } | |
1154 | ||
1155 | .control-group.success input:focus, | |
1156 | .control-group.success select:focus, | |
1157 | .control-group.success textarea:focus { | |
1158 | border-color: #356635; | |
1159 | -webkit-box-shadow: 0 0 6px #7aba7b; | |
1160 | -moz-box-shadow: 0 0 6px #7aba7b; | |
1161 | box-shadow: 0 0 6px #7aba7b; | |
1162 | } | |
1163 | ||
1164 | .control-group.success .input-prepend .add-on, | |
1165 | .control-group.success .input-append .add-on { | |
1166 | color: #468847; | |
1167 | background-color: #dff0d8; | |
1168 | border-color: #468847; | |
1169 | } | |
1170 | ||
1171 | input:focus:required:invalid, | |
1172 | textarea:focus:required:invalid, | |
1173 | select:focus:required:invalid { | |
1174 | color: #b94a48; | |
1175 | border-color: #ee5f5b; | |
1176 | } | |
1177 | ||
1178 | input:focus:required:invalid:focus, | |
1179 | textarea:focus:required:invalid:focus, | |
1180 | select:focus:required:invalid:focus { | |
1181 | border-color: #e9322d; | |
1182 | -webkit-box-shadow: 0 0 6px #f8b9b7; | |
1183 | -moz-box-shadow: 0 0 6px #f8b9b7; | |
1184 | box-shadow: 0 0 6px #f8b9b7; | |
1185 | } | |
1186 | ||
1187 | .form-actions { | |
1188 | padding: 17px 20px 18px; | |
1189 | margin-top: 18px; | |
1190 | margin-bottom: 18px; | |
1191 | background-color: #f5f5f5; | |
1192 | border-top: 1px solid #ddd; | |
1193 | *zoom: 1; | |
1194 | } | |
1195 | ||
1196 | .form-actions:before, | |
1197 | .form-actions:after { | |
1198 | display: table; | |
1199 | content: ""; | |
1200 | } | |
1201 | ||
1202 | .form-actions:after { | |
1203 | clear: both; | |
1204 | } | |
1205 | ||
1206 | .uneditable-input { | |
1207 | overflow: hidden; | |
1208 | white-space: nowrap; | |
1209 | cursor: not-allowed; | |
1210 | background-color: #ffffff; | |
1211 | border-color: #eee; | |
1212 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); | |
1213 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); | |
1214 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); | |
1215 | } | |
1216 | ||
1217 | :-moz-placeholder { | |
1218 | color: #999999; | |
1219 | } | |
1220 | ||
1221 | ::-webkit-input-placeholder { | |
1222 | color: #999999; | |
1223 | } | |
1224 | ||
1225 | .help-block, | |
1226 | .help-inline { | |
1227 | color: #555555; | |
1228 | } | |
1229 | ||
1230 | .help-block { | |
1231 | display: block; | |
1232 | margin-bottom: 9px; | |
1233 | } | |
1234 | ||
1235 | .help-inline { | |
1236 | display: inline-block; | |
1237 | *display: inline; | |
1238 | padding-left: 5px; | |
1239 | vertical-align: middle; | |
1240 | *zoom: 1; | |
1241 | } | |
1242 | ||
1243 | .input-prepend, | |
1244 | .input-append { | |
1245 | margin-bottom: 5px; | |
1246 | } | |
1247 | ||
1248 | .input-prepend input, | |
1249 | .input-append input, | |
1250 | .input-prepend select, | |
1251 | .input-append select, | |
1252 | .input-prepend .uneditable-input, | |
1253 | .input-append .uneditable-input { | |
1254 | position: relative; | |
1255 | margin-bottom: 0; | |
1256 | *margin-left: 0; | |
1257 | vertical-align: middle; | |
1258 | -webkit-border-radius: 0 3px 3px 0; | |
1259 | -moz-border-radius: 0 3px 3px 0; | |
1260 | border-radius: 0 3px 3px 0; | |
1261 | } | |
1262 | ||
1263 | .input-prepend input:focus, | |
1264 | .input-append input:focus, | |
1265 | .input-prepend select:focus, | |
1266 | .input-append select:focus, | |
1267 | .input-prepend .uneditable-input:focus, | |
1268 | .input-append .uneditable-input:focus { | |
1269 | z-index: 2; | |
1270 | } | |
1271 | ||
1272 | .input-prepend .uneditable-input, | |
1273 | .input-append .uneditable-input { | |
1274 | border-left-color: #ccc; | |
1275 | } | |
1276 | ||
1277 | .input-prepend .add-on, | |
1278 | .input-append .add-on { | |
1279 | display: inline-block; | |
1280 | width: auto; | |
1281 | height: 18px; | |
1282 | min-width: 16px; | |
1283 | padding: 4px 5px; | |
1284 | font-weight: normal; | |
1285 | line-height: 18px; | |
1286 | text-align: center; | |
1287 | text-shadow: 0 1px 0 #ffffff; | |
1288 | vertical-align: middle; | |
1289 | background-color: #eeeeee; | |
1290 | border: 1px solid #ccc; | |
1291 | } | |
1292 | ||
1293 | .input-prepend .add-on, | |
1294 | .input-append .add-on, | |
1295 | .input-prepend .btn, | |
1296 | .input-append .btn { | |
1297 | margin-left: -1px; | |
1298 | -webkit-border-radius: 0; | |
1299 | -moz-border-radius: 0; | |
1300 | border-radius: 0; | |
1301 | } | |
1302 | ||
1303 | .input-prepend .active, | |
1304 | .input-append .active { | |
1305 | background-color: #a9dba9; | |
1306 | border-color: #46a546; | |
1307 | } | |
1308 | ||
1309 | .input-prepend .add-on, | |
1310 | .input-prepend .btn { | |
1311 | margin-right: -1px; | |
1312 | } | |
1313 | ||
1314 | .input-prepend .add-on:first-child, | |
1315 | .input-prepend .btn:first-child { | |
1316 | -webkit-border-radius: 3px 0 0 3px; | |
1317 | -moz-border-radius: 3px 0 0 3px; | |
1318 | border-radius: 3px 0 0 3px; | |
1319 | } | |
1320 | ||
1321 | .input-append input, | |
1322 | .input-append select, | |
1323 | .input-append .uneditable-input { | |
1324 | -webkit-border-radius: 3px 0 0 3px; | |
1325 | -moz-border-radius: 3px 0 0 3px; | |
1326 | border-radius: 3px 0 0 3px; | |
1327 | } | |
1328 | ||
1329 | .input-append .uneditable-input { | |
1330 | border-right-color: #ccc; | |
1331 | border-left-color: #eee; | |
1332 | } | |
1333 | ||
1334 | .input-append .add-on:last-child, | |
1335 | .input-append .btn:last-child { | |
1336 | -webkit-border-radius: 0 3px 3px 0; | |
1337 | -moz-border-radius: 0 3px 3px 0; | |
1338 | border-radius: 0 3px 3px 0; | |
1339 | } | |
1340 | ||
1341 | .input-prepend.input-append input, | |
1342 | .input-prepend.input-append select, | |
1343 | .input-prepend.input-append .uneditable-input { | |
1344 | -webkit-border-radius: 0; | |
1345 | -moz-border-radius: 0; | |
1346 | border-radius: 0; | |
1347 | } | |
1348 | ||
1349 | .input-prepend.input-append .add-on:first-child, | |
1350 | .input-prepend.input-append .btn:first-child { | |
1351 | margin-right: -1px; | |
1352 | -webkit-border-radius: 3px 0 0 3px; | |
1353 | -moz-border-radius: 3px 0 0 3px; | |
1354 | border-radius: 3px 0 0 3px; | |
1355 | } | |
1356 | ||
1357 | .input-prepend.input-append .add-on:last-child, | |
1358 | .input-prepend.input-append .btn:last-child { | |
1359 | margin-left: -1px; | |
1360 | -webkit-border-radius: 0 3px 3px 0; | |
1361 | -moz-border-radius: 0 3px 3px 0; | |
1362 | border-radius: 0 3px 3px 0; | |
1363 | } | |
1364 | ||
1365 | .search-query { | |
1366 | padding-right: 14px; | |
1367 | padding-right: 4px \9; | |
1368 | padding-left: 14px; | |
1369 | padding-left: 4px \9; | |
1370 | /* IE7-8 doesn't have border-radius, so don't indent the padding */ | |
1371 | ||
1372 | margin-bottom: 0; | |
1373 | -webkit-border-radius: 14px; | |
1374 | -moz-border-radius: 14px; | |
1375 | border-radius: 14px; | |
1376 | } | |
1377 | ||
1378 | .form-search input, | |
1379 | .form-inline input, | |
1380 | .form-horizontal input, | |
1381 | .form-search textarea, | |
1382 | .form-inline textarea, | |
1383 | .form-horizontal textarea, | |
1384 | .form-search select, | |
1385 | .form-inline select, | |
1386 | .form-horizontal select, | |
1387 | .form-search .help-inline, | |
1388 | .form-inline .help-inline, | |
1389 | .form-horizontal .help-inline, | |
1390 | .form-search .uneditable-input, | |
1391 | .form-inline .uneditable-input, | |
1392 | .form-horizontal .uneditable-input, | |
1393 | .form-search .input-prepend, | |
1394 | .form-inline .input-prepend, | |
1395 | .form-horizontal .input-prepend, | |
1396 | .form-search .input-append, | |
1397 | .form-inline .input-append, | |
1398 | .form-horizontal .input-append { | |
1399 | display: inline-block; | |
1400 | *display: inline; | |
1401 | margin-bottom: 0; | |
1402 | *zoom: 1; | |
1403 | } | |
1404 | ||
1405 | .form-search .hide, | |
1406 | .form-inline .hide, | |
1407 | .form-horizontal .hide { | |
1408 | display: none; | |
1409 | } | |
1410 | ||
1411 | .form-search label, | |
1412 | .form-inline label { | |
1413 | display: inline-block; | |
1414 | } | |
1415 | ||
1416 | .form-search .input-append, | |
1417 | .form-inline .input-append, | |
1418 | .form-search .input-prepend, | |
1419 | .form-inline .input-prepend { | |
1420 | margin-bottom: 0; | |
1421 | } | |
1422 | ||
1423 | .form-search .radio, | |
1424 | .form-search .checkbox, | |
1425 | .form-inline .radio, | |
1426 | .form-inline .checkbox { | |
1427 | padding-left: 0; | |
1428 | margin-bottom: 0; | |
1429 | vertical-align: middle; | |
1430 | } | |
1431 | ||
1432 | .form-search .radio input[type="radio"], | |
1433 | .form-search .checkbox input[type="checkbox"], | |
1434 | .form-inline .radio input[type="radio"], | |
1435 | .form-inline .checkbox input[type="checkbox"] { | |
1436 | float: left; | |
1437 | margin-right: 3px; | |
1438 | margin-left: 0; | |
1439 | } | |
1440 | ||
1441 | .control-group { | |
1442 | margin-bottom: 9px; | |
1443 | } | |
1444 | ||
1445 | legend + .control-group { | |
1446 | margin-top: 18px; | |
1447 | -webkit-margin-top-collapse: separate; | |
1448 | } | |
1449 | ||
1450 | .form-horizontal .control-group { | |
1451 | margin-bottom: 18px; | |
1452 | *zoom: 1; | |
1453 | } | |
1454 | ||
1455 | .form-horizontal .control-group:before, | |
1456 | .form-horizontal .control-group:after { | |
1457 | display: table; | |
1458 | content: ""; | |
1459 | } | |
1460 | ||
1461 | .form-horizontal .control-group:after { | |
1462 | clear: both; | |
1463 | } | |
1464 | ||
1465 | .form-horizontal .control-label { | |
1466 | float: left; | |
1467 | width: 140px; | |
1468 | padding-top: 5px; | |
1469 | text-align: right; | |
1470 | } | |
1471 | ||
1472 | .form-horizontal .controls { | |
1473 | *display: inline-block; | |
1474 | *padding-left: 20px; | |
1475 | margin-left: 160px; | |
1476 | *margin-left: 0; | |
1477 | } | |
1478 | ||
1479 | .form-horizontal .controls:first-child { | |
1480 | *padding-left: 160px; | |
1481 | } | |
1482 | ||
1483 | .form-horizontal .help-block { | |
1484 | margin-top: 9px; | |
1485 | margin-bottom: 0; | |
1486 | } | |
1487 | ||
1488 | .form-horizontal .form-actions { | |
1489 | padding-left: 160px; | |
1490 | } | |
1491 | ||
1492 | table { | |
1493 | max-width: 100%; | |
1494 | background-color: transparent; | |
1495 | border-collapse: collapse; | |
1496 | border-spacing: 0; | |
1497 | } | |
1498 | ||
1499 | .table { | |
1500 | width: 100%; | |
1501 | margin-bottom: 18px; | |
1502 | } | |
1503 | ||
1504 | .table th, | |
1505 | .table td { | |
1506 | padding: 8px; | |
1507 | line-height: 18px; | |
1508 | text-align: left; | |
1509 | vertical-align: top; | |
1510 | border-top: 1px solid #dddddd; | |
1511 | } | |
1512 | ||
1513 | .table th { | |
1514 | font-weight: bold; | |
1515 | } | |
1516 | ||
1517 | .table thead th { | |
1518 | vertical-align: bottom; | |
1519 | } | |
1520 | ||
1521 | .table caption + thead tr:first-child th, | |
1522 | .table caption + thead tr:first-child td, | |
1523 | .table colgroup + thead tr:first-child th, | |
1524 | .table colgroup + thead tr:first-child td, | |
1525 | .table thead:first-child tr:first-child th, | |
1526 | .table thead:first-child tr:first-child td { | |
1527 | border-top: 0; | |
1528 | } | |
1529 | ||
1530 | .table tbody + tbody { | |
1531 | border-top: 2px solid #dddddd; | |
1532 | } | |
1533 | ||
1534 | .table-condensed th, | |
1535 | .table-condensed td { | |
1536 | padding: 4px 5px; | |
1537 | } | |
1538 | ||
1539 | .table-bordered { | |
1540 | border: 1px solid #dddddd; | |
1541 | border-collapse: separate; | |
1542 | *border-collapse: collapsed; | |
1543 | border-left: 0; | |
1544 | -webkit-border-radius: 4px; | |
1545 | -moz-border-radius: 4px; | |
1546 | border-radius: 4px; | |
1547 | } | |
1548 | ||
1549 | .table-bordered th, | |
1550 | .table-bordered td { | |
1551 | border-left: 1px solid #dddddd; | |
1552 | } | |
1553 | ||
1554 | .table-bordered caption + thead tr:first-child th, | |
1555 | .table-bordered caption + tbody tr:first-child th, | |
1556 | .table-bordered caption + tbody tr:first-child td, | |
1557 | .table-bordered colgroup + thead tr:first-child th, | |
1558 | .table-bordered colgroup + tbody tr:first-child th, | |
1559 | .table-bordered colgroup + tbody tr:first-child td, | |
1560 | .table-bordered thead:first-child tr:first-child th, | |
1561 | .table-bordered tbody:first-child tr:first-child th, | |
1562 | .table-bordered tbody:first-child tr:first-child td { | |
1563 | border-top: 0; | |
1564 | } | |
1565 | ||
1566 | .table-bordered thead:first-child tr:first-child th:first-child, | |
1567 | .table-bordered tbody:first-child tr:first-child td:first-child { | |
1568 | -webkit-border-top-left-radius: 4px; | |
1569 | border-top-left-radius: 4px; | |
1570 | -moz-border-radius-topleft: 4px; | |
1571 | } | |
1572 | ||
1573 | .table-bordered thead:first-child tr:first-child th:last-child, | |
1574 | .table-bordered tbody:first-child tr:first-child td:last-child { | |
1575 | -webkit-border-top-right-radius: 4px; | |
1576 | border-top-right-radius: 4px; | |
1577 | -moz-border-radius-topright: 4px; | |
1578 | } | |
1579 | ||
1580 | .table-bordered thead:last-child tr:last-child th:first-child, | |
1581 | .table-bordered tbody:last-child tr:last-child td:first-child { | |
1582 | -webkit-border-radius: 0 0 0 4px; | |
1583 | -moz-border-radius: 0 0 0 4px; | |
1584 | border-radius: 0 0 0 4px; | |
1585 | -webkit-border-bottom-left-radius: 4px; | |
1586 | border-bottom-left-radius: 4px; | |
1587 | -moz-border-radius-bottomleft: 4px; | |
1588 | } | |
1589 | ||
1590 | .table-bordered thead:last-child tr:last-child th:last-child, | |
1591 | .table-bordered tbody:last-child tr:last-child td:last-child { | |
1592 | -webkit-border-bottom-right-radius: 4px; | |
1593 | border-bottom-right-radius: 4px; | |
1594 | -moz-border-radius-bottomright: 4px; | |
1595 | } | |
1596 | ||
1597 | .table-striped tbody tr:nth-child(odd) td, | |
1598 | .table-striped tbody tr:nth-child(odd) th { | |
1599 | background-color: #f9f9f9; | |
1600 | } | |
1601 | ||
1602 | .table tbody tr:hover td, | |
1603 | .table tbody tr:hover th { | |
1604 | background-color: #f5f5f5; | |
1605 | } | |
1606 | ||
1607 | table .span1 { | |
1608 | float: none; | |
1609 | width: 44px; | |
1610 | margin-left: 0; | |
1611 | } | |
1612 | ||
1613 | table .span2 { | |
1614 | float: none; | |
1615 | width: 124px; | |
1616 | margin-left: 0; | |
1617 | } | |
1618 | ||
1619 | table .span3 { | |
1620 | float: none; | |
1621 | width: 204px; | |
1622 | margin-left: 0; | |
1623 | } | |
1624 | ||
1625 | table .span4 { | |
1626 | float: none; | |
1627 | width: 284px; | |
1628 | margin-left: 0; | |
1629 | } | |
1630 | ||
1631 | table .span5 { | |
1632 | float: none; | |
1633 | width: 364px; | |
1634 | margin-left: 0; | |
1635 | } | |
1636 | ||
1637 | table .span6 { | |
1638 | float: none; | |
1639 | width: 444px; | |
1640 | margin-left: 0; | |
1641 | } | |
1642 | ||
1643 | table .span7 { | |
1644 | float: none; | |
1645 | width: 524px; | |
1646 | margin-left: 0; | |
1647 | } | |
1648 | ||
1649 | table .span8 { | |
1650 | float: none; | |
1651 | width: 604px; | |
1652 | margin-left: 0; | |
1653 | } | |
1654 | ||
1655 | table .span9 { | |
1656 | float: none; | |
1657 | width: 684px; | |
1658 | margin-left: 0; | |
1659 | } | |
1660 | ||
1661 | table .span10 { | |
1662 | float: none; | |
1663 | width: 764px; | |
1664 | margin-left: 0; | |
1665 | } | |
1666 | ||
1667 | table .span11 { | |
1668 | float: none; | |
1669 | width: 844px; | |
1670 | margin-left: 0; | |
1671 | } | |
1672 | ||
1673 | table .span12 { | |
1674 | float: none; | |
1675 | width: 924px; | |
1676 | margin-left: 0; | |
1677 | } | |
1678 | ||
1679 | table .span13 { | |
1680 | float: none; | |
1681 | width: 1004px; | |
1682 | margin-left: 0; | |
1683 | } | |
1684 | ||
1685 | table .span14 { | |
1686 | float: none; | |
1687 | width: 1084px; | |
1688 | margin-left: 0; | |
1689 | } | |
1690 | ||
1691 | table .span15 { | |
1692 | float: none; | |
1693 | width: 1164px; | |
1694 | margin-left: 0; | |
1695 | } | |
1696 | ||
1697 | table .span16 { | |
1698 | float: none; | |
1699 | width: 1244px; | |
1700 | margin-left: 0; | |
1701 | } | |
1702 | ||
1703 | table .span17 { | |
1704 | float: none; | |
1705 | width: 1324px; | |
1706 | margin-left: 0; | |
1707 | } | |
1708 | ||
1709 | table .span18 { | |
1710 | float: none; | |
1711 | width: 1404px; | |
1712 | margin-left: 0; | |
1713 | } | |
1714 | ||
1715 | table .span19 { | |
1716 | float: none; | |
1717 | width: 1484px; | |
1718 | margin-left: 0; | |
1719 | } | |
1720 | ||
1721 | table .span20 { | |
1722 | float: none; | |
1723 | width: 1564px; | |
1724 | margin-left: 0; | |
1725 | } | |
1726 | ||
1727 | table .span21 { | |
1728 | float: none; | |
1729 | width: 1644px; | |
1730 | margin-left: 0; | |
1731 | } | |
1732 | ||
1733 | table .span22 { | |
1734 | float: none; | |
1735 | width: 1724px; | |
1736 | margin-left: 0; | |
1737 | } | |
1738 | ||
1739 | table .span23 { | |
1740 | float: none; | |
1741 | width: 1804px; | |
1742 | margin-left: 0; | |
1743 | } | |
1744 | ||
1745 | table .span24 { | |
1746 | float: none; | |
1747 | width: 1884px; | |
1748 | margin-left: 0; | |
1749 | } | |
1750 | ||
1751 | [class^="icon-"], | |
1752 | [class*=" icon-"] { | |
1753 | display: inline-block; | |
1754 | width: 14px; | |
1755 | height: 14px; | |
1756 | *margin-right: .3em; | |
1757 | line-height: 14px; | |
1758 | vertical-align: text-top; | |
1759 | /* background-image: url("../img/glyphicons-halflings.png"); */ | |
1760 | background-position: 14px 14px; | |
1761 | background-repeat: no-repeat; | |
1762 | } | |
1763 | ||
1764 | [class^="icon-"]:last-child, | |
1765 | [class*=" icon-"]:last-child { | |
1766 | *margin-left: 0; | |
1767 | } | |
1768 | ||
1769 | .icon-white { | |
1770 | /* background-image: url("../img/glyphicons-halflings-white.png"); */ | |
1771 | } | |
1772 | ||
1773 | .icon-glass { | |
1774 | background-position: 0 0; | |
1775 | } | |
1776 | ||
1777 | .icon-music { | |
1778 | background-position: -24px 0; | |
1779 | } | |
1780 | ||
1781 | .icon-search { | |
1782 | background-position: -48px 0; | |
1783 | } | |
1784 | ||
1785 | .icon-envelope { | |
1786 | background-position: -72px 0; | |
1787 | } | |
1788 | ||
1789 | .icon-heart { | |
1790 | background-position: -96px 0; | |
1791 | } | |
1792 | ||
1793 | .icon-star { | |
1794 | background-position: -120px 0; | |
1795 | } | |
1796 | ||
1797 | .icon-star-empty { | |
1798 | background-position: -144px 0; | |
1799 | } | |
1800 | ||
1801 | .icon-user { | |
1802 | background-position: -168px 0; | |
1803 | } | |
1804 | ||
1805 | .icon-film { | |
1806 | background-position: -192px 0; | |
1807 | } | |
1808 | ||
1809 | .icon-th-large { | |
1810 | background-position: -216px 0; | |
1811 | } | |
1812 | ||
1813 | .icon-th { | |
1814 | background-position: -240px 0; | |
1815 | } | |
1816 | ||
1817 | .icon-th-list { | |
1818 | background-position: -264px 0; | |
1819 | } | |
1820 | ||
1821 | .icon-ok { | |
1822 | background-position: -288px 0; | |
1823 | } | |
1824 | ||
1825 | .icon-remove { | |
1826 | background-position: -312px 0; | |
1827 | } | |
1828 | ||
1829 | .icon-zoom-in { | |
1830 | background-position: -336px 0; | |
1831 | } | |
1832 | ||
1833 | .icon-zoom-out { | |
1834 | background-position: -360px 0; | |
1835 | } | |
1836 | ||
1837 | .icon-off { | |
1838 | background-position: -384px 0; | |
1839 | } | |
1840 | ||
1841 | .icon-signal { | |
1842 | background-position: -408px 0; | |
1843 | } | |
1844 | ||
1845 | .icon-cog { | |
1846 | background-position: -432px 0; | |
1847 | } | |
1848 | ||
1849 | .icon-trash { | |
1850 | background-position: -456px 0; | |
1851 | } | |
1852 | ||
1853 | .icon-home { | |
1854 | background-position: 0 -24px; | |
1855 | } | |
1856 | ||
1857 | .icon-file { | |
1858 | background-position: -24px -24px; | |
1859 | } | |
1860 | ||
1861 | .icon-time { | |
1862 | background-position: -48px -24px; | |
1863 | } | |
1864 | ||
1865 | .icon-road { | |
1866 | background-position: -72px -24px; | |
1867 | } | |
1868 | ||
1869 | .icon-download-alt { | |
1870 | background-position: -96px -24px; | |
1871 | } | |
1872 | ||
1873 | .icon-download { | |
1874 | background-position: -120px -24px; | |
1875 | } | |
1876 | ||
1877 | .icon-upload { | |
1878 | background-position: -144px -24px; | |
1879 | } | |
1880 | ||
1881 | .icon-inbox { | |
1882 | background-position: -168px -24px; | |
1883 | } | |
1884 | ||
1885 | .icon-play-circle { | |
1886 | background-position: -192px -24px; | |
1887 | } | |
1888 | ||
1889 | .icon-repeat { | |
1890 | background-position: -216px -24px; | |
1891 | } | |
1892 | ||
1893 | .icon-refresh { | |
1894 | background-position: -240px -24px; | |
1895 | } | |
1896 | ||
1897 | .icon-list-alt { | |
1898 | background-position: -264px -24px; | |
1899 | } | |
1900 | ||
1901 | .icon-lock { | |
1902 | background-position: -287px -24px; | |
1903 | } | |
1904 | ||
1905 | .icon-flag { | |
1906 | background-position: -312px -24px; | |
1907 | } | |
1908 | ||
1909 | .icon-headphones { | |
1910 | background-position: -336px -24px; | |
1911 | } | |
1912 | ||
1913 | .icon-volume-off { | |
1914 | background-position: -360px -24px; | |
1915 | } | |
1916 | ||
1917 | .icon-volume-down { | |
1918 | background-position: -384px -24px; | |
1919 | } | |
1920 | ||
1921 | .icon-volume-up { | |
1922 | background-position: -408px -24px; | |
1923 | } | |
1924 | ||
1925 | .icon-qrcode { | |
1926 | background-position: -432px -24px; | |
1927 | } | |
1928 | ||
1929 | .icon-barcode { | |
1930 | background-position: -456px -24px; | |
1931 | } | |
1932 | ||
1933 | .icon-tag { | |
1934 | background-position: 0 -48px; | |
1935 | } | |
1936 | ||
1937 | .icon-tags { | |
1938 | background-position: -25px -48px; | |
1939 | } | |
1940 | ||
1941 | .icon-book { | |
1942 | background-position: -48px -48px; | |
1943 | } | |
1944 | ||
1945 | .icon-bookmark { | |
1946 | background-position: -72px -48px; | |
1947 | } | |
1948 | ||
1949 | .icon-print { | |
1950 | background-position: -96px -48px; | |
1951 | } | |
1952 | ||
1953 | .icon-camera { | |
1954 | background-position: -120px -48px; | |
1955 | } | |
1956 | ||
1957 | .icon-font { | |
1958 | background-position: -144px -48px; | |
1959 | } | |
1960 | ||
1961 | .icon-bold { | |
1962 | background-position: -167px -48px; | |
1963 | } | |
1964 | ||
1965 | .icon-italic { | |
1966 | background-position: -192px -48px; | |
1967 | } | |
1968 | ||
1969 | .icon-text-height { | |
1970 | background-position: -216px -48px; | |
1971 | } | |
1972 | ||
1973 | .icon-text-width { | |
1974 | background-position: -240px -48px; | |
1975 | } | |
1976 | ||
1977 | .icon-align-left { | |
1978 | background-position: -264px -48px; | |
1979 | } | |
1980 | ||
1981 | .icon-align-center { | |
1982 | background-position: -288px -48px; | |
1983 | } | |
1984 | ||
1985 | .icon-align-right { | |
1986 | background-position: -312px -48px; | |
1987 | } | |
1988 | ||
1989 | .icon-align-justify { | |
1990 | background-position: -336px -48px; | |
1991 | } | |
1992 | ||
1993 | .icon-list { | |
1994 | background-position: -360px -48px; | |
1995 | } | |
1996 | ||
1997 | .icon-indent-left { | |
1998 | background-position: -384px -48px; | |
1999 | } | |
2000 | ||
2001 | .icon-indent-right { | |
2002 | background-position: -408px -48px; | |
2003 | } | |
2004 | ||
2005 | .icon-facetime-video { | |
2006 | background-position: -432px -48px; | |
2007 | } | |
2008 | ||
2009 | .icon-picture { | |
2010 | background-position: -456px -48px; | |
2011 | } | |
2012 | ||
2013 | .icon-pencil { | |
2014 | background-position: 0 -72px; | |
2015 | } | |
2016 | ||
2017 | .icon-map-marker { | |
2018 | background-position: -24px -72px; | |
2019 | } | |
2020 | ||
2021 | .icon-adjust { | |
2022 | background-position: -48px -72px; | |
2023 | } | |
2024 | ||
2025 | .icon-tint { | |
2026 | background-position: -72px -72px; | |
2027 | } | |
2028 | ||
2029 | .icon-edit { | |
2030 | background-position: -96px -72px; | |
2031 | } | |
2032 | ||
2033 | .icon-share { | |
2034 | background-position: -120px -72px; | |
2035 | } | |
2036 | ||
2037 | .icon-check { | |
2038 | background-position: -144px -72px; | |
2039 | } | |
2040 | ||
2041 | .icon-move { | |
2042 | background-position: -168px -72px; | |
2043 | } | |
2044 | ||
2045 | .icon-step-backward { | |
2046 | background-position: -192px -72px; | |
2047 | } | |
2048 | ||
2049 | .icon-fast-backward { | |
2050 | background-position: -216px -72px; | |
2051 | } | |
2052 | ||
2053 | .icon-backward { | |
2054 | background-position: -240px -72px; | |
2055 | } | |
2056 | ||
2057 | .icon-play { | |
2058 | background-position: -264px -72px; | |
2059 | } | |
2060 | ||
2061 | .icon-pause { | |
2062 | background-position: -288px -72px; | |
2063 | } | |
2064 | ||
2065 | .icon-stop { | |
2066 | background-position: -312px -72px; | |
2067 | } | |
2068 | ||
2069 | .icon-forward { | |
2070 | background-position: -336px -72px; | |
2071 | } | |
2072 | ||
2073 | .icon-fast-forward { | |
2074 | background-position: -360px -72px; | |
2075 | } | |
2076 | ||
2077 | .icon-step-forward { | |
2078 | background-position: -384px -72px; | |
2079 | } | |
2080 | ||
2081 | .icon-eject { | |
2082 | background-position: -408px -72px; | |
2083 | } | |
2084 | ||
2085 | .icon-chevron-left { | |
2086 | background-position: -432px -72px; | |
2087 | } | |
2088 | ||
2089 | .icon-chevron-right { | |
2090 | background-position: -456px -72px; | |
2091 | } | |
2092 | ||
2093 | .icon-plus-sign { | |
2094 | background-position: 0 -96px; | |
2095 | } | |
2096 | ||
2097 | .icon-minus-sign { | |
2098 | background-position: -24px -96px; | |
2099 | } | |
2100 | ||
2101 | .icon-remove-sign { | |
2102 | background-position: -48px -96px; | |
2103 | } | |
2104 | ||
2105 | .icon-ok-sign { | |
2106 | background-position: -72px -96px; | |
2107 | } | |
2108 | ||
2109 | .icon-question-sign { | |
2110 | background-position: -96px -96px; | |
2111 | } | |
2112 | ||
2113 | .icon-info-sign { | |
2114 | background-position: -120px -96px; | |
2115 | } | |
2116 | ||
2117 | .icon-screenshot { | |
2118 | background-position: -144px -96px; | |
2119 | } | |
2120 | ||
2121 | .icon-remove-circle { | |
2122 | background-position: -168px -96px; | |
2123 | } | |
2124 | ||
2125 | .icon-ok-circle { | |
2126 | background-position: -192px -96px; | |
2127 | } | |
2128 | ||
2129 | .icon-ban-circle { | |
2130 | background-position: -216px -96px; | |
2131 | } | |
2132 | ||
2133 | .icon-arrow-left { | |
2134 | background-position: -240px -96px; | |
2135 | } | |
2136 | ||
2137 | .icon-arrow-right { | |
2138 | background-position: -264px -96px; | |
2139 | } | |
2140 | ||
2141 | .icon-arrow-up { | |
2142 | background-position: -289px -96px; | |
2143 | } | |
2144 | ||
2145 | .icon-arrow-down { | |
2146 | background-position: -312px -96px; | |
2147 | } | |
2148 | ||
2149 | .icon-share-alt { | |
2150 | background-position: -336px -96px; | |
2151 | } | |
2152 | ||
2153 | .icon-resize-full { | |
2154 | background-position: -360px -96px; | |
2155 | } | |
2156 | ||
2157 | .icon-resize-small { | |
2158 | background-position: -384px -96px; | |
2159 | } | |
2160 | ||
2161 | .icon-plus { | |
2162 | background-position: -408px -96px; | |
2163 | } | |
2164 | ||
2165 | .icon-minus { | |
2166 | background-position: -433px -96px; | |
2167 | } | |
2168 | ||
2169 | .icon-asterisk { | |
2170 | background-position: -456px -96px; | |
2171 | } | |
2172 | ||
2173 | .icon-exclamation-sign { | |
2174 | background-position: 0 -120px; | |
2175 | } | |
2176 | ||
2177 | .icon-gift { | |
2178 | background-position: -24px -120px; | |
2179 | } | |
2180 | ||
2181 | .icon-leaf { | |
2182 | background-position: -48px -120px; | |
2183 | } | |
2184 | ||
2185 | .icon-fire { | |
2186 | background-position: -72px -120px; | |
2187 | } | |
2188 | ||
2189 | .icon-eye-open { | |
2190 | background-position: -96px -120px; | |
2191 | } | |
2192 | ||
2193 | .icon-eye-close { | |
2194 | background-position: -120px -120px; | |
2195 | } | |
2196 | ||
2197 | .icon-warning-sign { | |
2198 | background-position: -144px -120px; | |
2199 | } | |
2200 | ||
2201 | .icon-plane { | |
2202 | background-position: -168px -120px; | |
2203 | } | |
2204 | ||
2205 | .icon-calendar { | |
2206 | background-position: -192px -120px; | |
2207 | } | |
2208 | ||
2209 | .icon-random { | |
2210 | background-position: -216px -120px; | |
2211 | } | |
2212 | ||
2213 | .icon-comment { | |
2214 | background-position: -240px -120px; | |
2215 | } | |
2216 | ||
2217 | .icon-magnet { | |
2218 | background-position: -264px -120px; | |
2219 | } | |
2220 | ||
2221 | .icon-chevron-up { | |
2222 | background-position: -288px -120px; | |
2223 | } | |
2224 | ||
2225 | .icon-chevron-down { | |
2226 | background-position: -313px -119px; | |
2227 | } | |
2228 | ||
2229 | .icon-retweet { | |
2230 | background-position: -336px -120px; | |
2231 | } | |
2232 | ||
2233 | .icon-shopping-cart { | |
2234 | background-position: -360px -120px; | |
2235 | } | |
2236 | ||
2237 | .icon-folder-close { | |
2238 | background-position: -384px -120px; | |
2239 | } | |
2240 | ||
2241 | .icon-folder-open { | |
2242 | background-position: -408px -120px; | |
2243 | } | |
2244 | ||
2245 | .icon-resize-vertical { | |
2246 | background-position: -432px -119px; | |
2247 | } | |
2248 | ||
2249 | .icon-resize-horizontal { | |
2250 | background-position: -456px -118px; | |
2251 | } | |
2252 | ||
2253 | .icon-hdd { | |
2254 | background-position: 0 -144px; | |
2255 | } | |
2256 | ||
2257 | .icon-bullhorn { | |
2258 | background-position: -24px -144px; | |
2259 | } | |
2260 | ||
2261 | .icon-bell { | |
2262 | background-position: -48px -144px; | |
2263 | } | |
2264 | ||
2265 | .icon-certificate { | |
2266 | background-position: -72px -144px; | |
2267 | } | |
2268 | ||
2269 | .icon-thumbs-up { | |
2270 | background-position: -96px -144px; | |
2271 | } | |
2272 | ||
2273 | .icon-thumbs-down { | |
2274 | background-position: -120px -144px; | |
2275 | } | |
2276 | ||
2277 | .icon-hand-right { | |
2278 | background-position: -144px -144px; | |
2279 | } | |
2280 | ||
2281 | .icon-hand-left { | |
2282 | background-position: -168px -144px; | |
2283 | } | |
2284 | ||
2285 | .icon-hand-up { | |
2286 | background-position: -192px -144px; | |
2287 | } | |
2288 | ||
2289 | .icon-hand-down { | |
2290 | background-position: -216px -144px; | |
2291 | } | |
2292 | ||
2293 | .icon-circle-arrow-right { | |
2294 | background-position: -240px -144px; | |
2295 | } | |
2296 | ||
2297 | .icon-circle-arrow-left { | |
2298 | background-position: -264px -144px; | |
2299 | } | |
2300 | ||
2301 | .icon-circle-arrow-up { | |
2302 | background-position: -288px -144px; | |
2303 | } | |
2304 | ||
2305 | .icon-circle-arrow-down { | |
2306 | background-position: -312px -144px; | |
2307 | } | |
2308 | ||
2309 | .icon-globe { | |
2310 | background-position: -336px -144px; | |
2311 | } | |
2312 | ||
2313 | .icon-wrench { | |
2314 | background-position: -360px -144px; | |
2315 | } | |
2316 | ||
2317 | .icon-tasks { | |
2318 | background-position: -384px -144px; | |
2319 | } | |
2320 | ||
2321 | .icon-filter { | |
2322 | background-position: -408px -144px; | |
2323 | } | |
2324 | ||
2325 | .icon-briefcase { | |
2326 | background-position: -432px -144px; | |
2327 | } | |
2328 | ||
2329 | .icon-fullscreen { | |
2330 | background-position: -456px -144px; | |
2331 | } | |
2332 | ||
2333 | .dropup, | |
2334 | .dropdown { | |
2335 | position: relative; | |
2336 | } | |
2337 | ||
2338 | .dropdown-toggle { | |
2339 | *margin-bottom: -3px; | |
2340 | } | |
2341 | ||
2342 | .dropdown-toggle:active, | |
2343 | .open .dropdown-toggle { | |
2344 | outline: 0; | |
2345 | } | |
2346 | ||
2347 | .caret { | |
2348 | display: inline-block; | |
2349 | width: 0; | |
2350 | height: 0; | |
2351 | vertical-align: top; | |
2352 | border-top: 4px solid #000000; | |
2353 | border-right: 4px solid transparent; | |
2354 | border-left: 4px solid transparent; | |
2355 | content: ""; | |
2356 | opacity: 0.3; | |
2357 | filter: alpha(opacity=30); | |
2358 | } | |
2359 | ||
2360 | .dropdown .caret { | |
2361 | margin-top: 8px; | |
2362 | margin-left: 2px; | |
2363 | } | |
2364 | ||
2365 | .dropdown:hover .caret, | |
2366 | .open .caret { | |
2367 | opacity: 1; | |
2368 | filter: alpha(opacity=100); | |
2369 | } | |
2370 | ||
2371 | .dropdown-menu { | |
2372 | position: absolute; | |
2373 | top: 100%; | |
2374 | left: 0; | |
2375 | z-index: 1000; | |
2376 | display: none; | |
2377 | float: left; | |
2378 | min-width: 160px; | |
2379 | padding: 4px 0; | |
2380 | margin: 1px 0 0; | |
2381 | list-style: none; | |
2382 | background-color: #ffffff; | |
2383 | border: 1px solid #ccc; | |
2384 | border: 1px solid rgba(0, 0, 0, 0.2); | |
2385 | *border-right-width: 2px; | |
2386 | *border-bottom-width: 2px; | |
2387 | -webkit-border-radius: 5px; | |
2388 | -moz-border-radius: 5px; | |
2389 | border-radius: 5px; | |
2390 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); | |
2391 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); | |
2392 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); | |
2393 | -webkit-background-clip: padding-box; | |
2394 | -moz-background-clip: padding; | |
2395 | background-clip: padding-box; | |
2396 | } | |
2397 | ||
2398 | .dropdown-menu.pull-right { | |
2399 | right: 0; | |
2400 | left: auto; | |
2401 | } | |
2402 | ||
2403 | .dropdown-menu .divider { | |
2404 | *width: 100%; | |
2405 | height: 1px; | |
2406 | margin: 8px 1px; | |
2407 | *margin: -5px 0 5px; | |
2408 | overflow: hidden; | |
2409 | background-color: #e5e5e5; | |
2410 | border-bottom: 1px solid #ffffff; | |
2411 | } | |
2412 | ||
2413 | .dropdown-menu a { | |
2414 | display: block; | |
2415 | padding: 3px 15px; | |
2416 | clear: both; | |
2417 | font-weight: normal; | |
2418 | line-height: 18px; | |
2419 | color: #333333; | |
2420 | white-space: nowrap; | |
2421 | } | |
2422 | ||
2423 | .dropdown-menu li > a:hover, | |
2424 | .dropdown-menu .active > a, | |
2425 | .dropdown-menu .active > a:hover { | |
2426 | color: #ffffff; | |
2427 | text-decoration: none; | |
2428 | background-color: #0088cc; | |
2429 | } | |
2430 | ||
2431 | .open { | |
2432 | *z-index: 1000; | |
2433 | } | |
2434 | ||
2435 | .open .dropdown-menu { | |
2436 | display: block; | |
2437 | } | |
2438 | ||
2439 | .pull-right .dropdown-menu { | |
2440 | right: 0; | |
2441 | left: auto; | |
2442 | } | |
2443 | ||
2444 | .dropup .caret, | |
2445 | .navbar-fixed-bottom .dropdown .caret { | |
2446 | border-top: 0; | |
2447 | border-bottom: 4px solid #000000; | |
2448 | content: "\2191"; | |
2449 | } | |
2450 | ||
2451 | .dropup .dropdown-menu, | |
2452 | .navbar-fixed-bottom .dropdown .dropdown-menu { | |
2453 | top: auto; | |
2454 | bottom: 100%; | |
2455 | margin-bottom: 1px; | |
2456 | } | |
2457 | ||
2458 | .typeahead { | |
2459 | margin-top: 2px; | |
2460 | -webkit-border-radius: 4px; | |
2461 | -moz-border-radius: 4px; | |
2462 | border-radius: 4px; | |
2463 | } | |
2464 | ||
2465 | .well { | |
2466 | min-height: 20px; | |
2467 | padding: 19px; | |
2468 | margin-bottom: 20px; | |
2469 | background-color: #f5f5f5; | |
2470 | border: 1px solid #eee; | |
2471 | border: 1px solid rgba(0, 0, 0, 0.05); | |
2472 | -webkit-border-radius: 4px; | |
2473 | -moz-border-radius: 4px; | |
2474 | border-radius: 4px; | |
2475 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); | |
2476 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); | |
2477 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); | |
2478 | } | |
2479 | ||
2480 | .well blockquote { | |
2481 | border-color: #ddd; | |
2482 | border-color: rgba(0, 0, 0, 0.15); | |
2483 | } | |
2484 | ||
2485 | .well-large { | |
2486 | padding: 24px; | |
2487 | -webkit-border-radius: 6px; | |
2488 | -moz-border-radius: 6px; | |
2489 | border-radius: 6px; | |
2490 | } | |
2491 | ||
2492 | .well-small { | |
2493 | padding: 9px; | |
2494 | -webkit-border-radius: 3px; | |
2495 | -moz-border-radius: 3px; | |
2496 | border-radius: 3px; | |
2497 | } | |
2498 | ||
2499 | .fade { | |
2500 | opacity: 0; | |
2501 | filter: alpha(opacity=0); | |
2502 | -webkit-transition: opacity 0.15s linear; | |
2503 | -moz-transition: opacity 0.15s linear; | |
2504 | -ms-transition: opacity 0.15s linear; | |
2505 | -o-transition: opacity 0.15s linear; | |
2506 | transition: opacity 0.15s linear; | |
2507 | } | |
2508 | ||
2509 | .fade.in { | |
2510 | opacity: 1; | |
2511 | filter: alpha(opacity=100); | |
2512 | } | |
2513 | ||
2514 | .collapse { | |
2515 | position: relative; | |
2516 | height: 0; | |
2517 | overflow: hidden; | |
2518 | -webkit-transition: height 0.35s ease; | |
2519 | -moz-transition: height 0.35s ease; | |
2520 | -ms-transition: height 0.35s ease; | |
2521 | -o-transition: height 0.35s ease; | |
2522 | transition: height 0.35s ease; | |
2523 | } | |
2524 | ||
2525 | .collapse.in { | |
2526 | height: auto; | |
2527 | } | |
2528 | ||
2529 | .close { | |
2530 | float: right; | |
2531 | font-size: 20px; | |
2532 | font-weight: bold; | |
2533 | line-height: 18px; | |
2534 | color: #000000; | |
2535 | text-shadow: 0 1px 0 #ffffff; | |
2536 | opacity: 0.2; | |
2537 | filter: alpha(opacity=20); | |
2538 | } | |
2539 | ||
2540 | .close:hover { | |
2541 | color: #000000; | |
2542 | text-decoration: none; | |
2543 | cursor: pointer; | |
2544 | opacity: 0.4; | |
2545 | filter: alpha(opacity=40); | |
2546 | } | |
2547 | ||
2548 | button.close { | |
2549 | padding: 0; | |
2550 | cursor: pointer; | |
2551 | background: transparent; | |
2552 | border: 0; | |
2553 | -webkit-appearance: none; | |
2554 | } | |
2555 | ||
2556 | .btn { | |
2557 | display: inline-block; | |
2558 | *display: inline; | |
2559 | padding: 4px 10px 4px; | |
2560 | margin-bottom: 0; | |
2561 | *margin-left: .3em; | |
2562 | font-size: 13px; | |
2563 | line-height: 18px; | |
2564 | *line-height: 20px; | |
2565 | color: #333333; | |
2566 | text-align: center; | |
2567 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); | |
2568 | vertical-align: middle; | |
2569 | cursor: pointer; | |
2570 | background-color: #f5f5f5; | |
2571 | *background-color: #e6e6e6; | |
2572 | background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); | |
2573 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); | |
2574 | background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); | |
2575 | background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); | |
2576 | background-image: linear-gradient(top, #ffffff, #e6e6e6); | |
2577 | background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); | |
2578 | background-repeat: repeat-x; | |
2579 | border: 1px solid #cccccc; | |
2580 | *border: 0; | |
2581 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |
2582 | border-color: #e6e6e6 #e6e6e6 #bfbfbf; | |
2583 | border-bottom-color: #b3b3b3; | |
2584 | -webkit-border-radius: 4px; | |
2585 | -moz-border-radius: 4px; | |
2586 | border-radius: 4px; | |
2587 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); | |
2588 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); | |
2589 | *zoom: 1; | |
2590 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); | |
2591 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); | |
2592 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); | |
2593 | } | |
2594 | ||
2595 | .btn:hover, | |
2596 | .btn:active, | |
2597 | .btn.active, | |
2598 | .btn.disabled, | |
2599 | .btn[disabled] { | |
2600 | background-color: #e6e6e6; | |
2601 | *background-color: #d9d9d9; | |
2602 | } | |
2603 | ||
2604 | .btn:active, | |
2605 | .btn.active { | |
2606 | background-color: #cccccc \9; | |
2607 | } | |
2608 | ||
2609 | .btn:first-child { | |
2610 | *margin-left: 0; | |
2611 | } | |
2612 | ||
2613 | .btn:hover { | |
2614 | color: #333333; | |
2615 | text-decoration: none; | |
2616 | background-color: #e6e6e6; | |
2617 | *background-color: #d9d9d9; | |
2618 | /* Buttons in IE7 don't get borders, so darken on hover */ | |
2619 | ||
2620 | background-position: 0 -15px; | |
2621 | -webkit-transition: background-position 0.1s linear; | |
2622 | -moz-transition: background-position 0.1s linear; | |
2623 | -ms-transition: background-position 0.1s linear; | |
2624 | -o-transition: background-position 0.1s linear; | |
2625 | transition: background-position 0.1s linear; | |
2626 | } | |
2627 | ||
2628 | .btn:focus { | |
2629 | outline: thin dotted #333; | |
2630 | outline: 5px auto -webkit-focus-ring-color; | |
2631 | outline-offset: -2px; | |
2632 | } | |
2633 | ||
2634 | .btn.active, | |
2635 | .btn:active { | |
2636 | background-color: #e6e6e6; | |
2637 | background-color: #d9d9d9 \9; | |
2638 | background-image: none; | |
2639 | outline: 0; | |
2640 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); | |
2641 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); | |
2642 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); | |
2643 | } | |
2644 | ||
2645 | .btn.disabled, | |
2646 | .btn[disabled] { | |
2647 | cursor: default; | |
2648 | background-color: #e6e6e6; | |
2649 | background-image: none; | |
2650 | opacity: 0.65; | |
2651 | filter: alpha(opacity=65); | |
2652 | -webkit-box-shadow: none; | |
2653 | -moz-box-shadow: none; | |
2654 | box-shadow: none; | |
2655 | } | |
2656 | ||
2657 | .btn-large { | |
2658 | padding: 9px 14px; | |
2659 | font-size: 15px; | |
2660 | line-height: normal; | |
2661 | -webkit-border-radius: 5px; | |
2662 | -moz-border-radius: 5px; | |
2663 | border-radius: 5px; | |
2664 | } | |
2665 | ||
2666 | .btn-large [class^="icon-"] { | |
2667 | margin-top: 1px; | |
2668 | } | |
2669 | ||
2670 | .btn-small { | |
2671 | padding: 5px 9px; | |
2672 | font-size: 11px; | |
2673 | line-height: 16px; | |
2674 | } | |
2675 | ||
2676 | .btn-small [class^="icon-"] { | |
2677 | margin-top: -1px; | |
2678 | } | |
2679 | ||
2680 | .btn-mini { | |
2681 | padding: 2px 6px; | |
2682 | font-size: 11px; | |
2683 | line-height: 14px; | |
2684 | } | |
2685 | ||
2686 | .btn-primary, | |
2687 | .btn-primary:hover, | |
2688 | .btn-warning, | |
2689 | .btn-warning:hover, | |
2690 | .btn-danger, | |
2691 | .btn-danger:hover, | |
2692 | .btn-success, | |
2693 | .btn-success:hover, | |
2694 | .btn-info, | |
2695 | .btn-info:hover, | |
2696 | .btn-inverse, | |
2697 | .btn-inverse:hover { | |
2698 | color: #ffffff; | |
2699 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | |
2700 | } | |
2701 | ||
2702 | .btn-primary.active, | |
2703 | .btn-warning.active, | |
2704 | .btn-danger.active, | |
2705 | .btn-success.active, | |
2706 | .btn-info.active, | |
2707 | .btn-inverse.active { | |
2708 | color: rgba(255, 255, 255, 0.75); | |
2709 | } | |
2710 | ||
2711 | .btn { | |
2712 | border-color: #ccc; | |
2713 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |
2714 | } | |
2715 | ||
2716 | .btn-primary { | |
2717 | background-color: #0074cc; | |
2718 | *background-color: #0055cc; | |
2719 | background-image: -ms-linear-gradient(top, #0088cc, #0055cc); | |
2720 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc)); | |
2721 | background-image: -webkit-linear-gradient(top, #0088cc, #0055cc); | |
2722 | background-image: -o-linear-gradient(top, #0088cc, #0055cc); | |
2723 | background-image: -moz-linear-gradient(top, #0088cc, #0055cc); | |
2724 | background-image: linear-gradient(top, #0088cc, #0055cc); | |
2725 | background-repeat: repeat-x; | |
2726 | border-color: #0055cc #0055cc #003580; | |
2727 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |
2728 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0); | |
2729 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); | |
2730 | } | |
2731 | ||
2732 | .btn-primary:hover, | |
2733 | .btn-primary:active, | |
2734 | .btn-primary.active, | |
2735 | .btn-primary.disabled, | |
2736 | .btn-primary[disabled] { | |
2737 | background-color: #0055cc; | |
2738 | *background-color: #004ab3; | |
2739 | } | |
2740 | ||
2741 | .btn-primary:active, | |
2742 | .btn-primary.active { | |
2743 | background-color: #004099 \9; | |
2744 | } | |
2745 | ||
2746 | .btn-warning { | |
2747 | background-color: #faa732; | |
2748 | *background-color: #f89406; | |
2749 | background-image: -ms-linear-gradient(top, #fbb450, #f89406); | |
2750 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); | |
2751 | background-image: -webkit-linear-gradient(top, #fbb450, #f89406); | |
2752 | background-image: -o-linear-gradient(top, #fbb450, #f89406); | |
2753 | background-image: -moz-linear-gradient(top, #fbb450, #f89406); | |
2754 | background-image: linear-gradient(top, #fbb450, #f89406); | |
2755 | background-repeat: repeat-x; | |
2756 | border-color: #f89406 #f89406 #ad6704; | |
2757 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |
2758 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); | |
2759 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); | |
2760 | } | |
2761 | ||
2762 | .btn-warning:hover, | |
2763 | .btn-warning:active, | |
2764 | .btn-warning.active, | |
2765 | .btn-warning.disabled, | |
2766 | .btn-warning[disabled] { | |
2767 | background-color: #f89406; | |
2768 | *background-color: #df8505; | |
2769 | } | |
2770 | ||
2771 | .btn-warning:active, | |
2772 | .btn-warning.active { | |
2773 | background-color: #c67605 \9; | |
2774 | } | |
2775 | ||
2776 | .btn-danger { | |
2777 | background-color: #da4f49; | |
2778 | *background-color: #bd362f; | |
2779 | background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); | |
2780 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); | |
2781 | background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); | |
2782 | background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); | |
2783 | background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); | |
2784 | background-image: linear-gradient(top, #ee5f5b, #bd362f); | |
2785 | background-repeat: repeat-x; | |
2786 | border-color: #bd362f #bd362f #802420; | |
2787 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |
2788 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); | |
2789 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); | |
2790 | } | |
2791 | ||
2792 | .btn-danger:hover, | |
2793 | .btn-danger:active, | |
2794 | .btn-danger.active, | |
2795 | .btn-danger.disabled, | |
2796 | .btn-danger[disabled] { | |
2797 | background-color: #bd362f; | |
2798 | *background-color: #a9302a; | |
2799 | } | |
2800 | ||
2801 | .btn-danger:active, | |
2802 | .btn-danger.active { | |
2803 | background-color: #942a25 \9; | |
2804 | } | |
2805 | ||
2806 | .btn-success { | |
2807 | background-color: #5bb75b; | |
2808 | *background-color: #51a351; | |
2809 | background-image: -ms-linear-gradient(top, #62c462, #51a351); | |
2810 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); | |
2811 | background-image: -webkit-linear-gradient(top, #62c462, #51a351); | |
2812 | background-image: -o-linear-gradient(top, #62c462, #51a351); | |
2813 | background-image: -moz-linear-gradient(top, #62c462, #51a351); | |
2814 | background-image: linear-gradient(top, #62c462, #51a351); | |
2815 | background-repeat: repeat-x; | |
2816 | border-color: #51a351 #51a351 #387038; | |
2817 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |
2818 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); | |
2819 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); | |
2820 | } | |
2821 | ||
2822 | .btn-success:hover, | |
2823 | .btn-success:active, | |
2824 | .btn-success.active, | |
2825 | .btn-success.disabled, | |
2826 | .btn-success[disabled] { | |
2827 | background-color: #51a351; | |
2828 | *background-color: #499249; | |
2829 | } | |
2830 | ||
2831 | .btn-success:active, | |
2832 | .btn-success.active { | |
2833 | background-color: #408140 \9; | |
2834 | } | |
2835 | ||
2836 | .btn-info { | |
2837 | background-color: #49afcd; | |
2838 | *background-color: #2f96b4; | |
2839 | background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); | |
2840 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); | |
2841 | background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); | |
2842 | background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); | |
2843 | background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); | |
2844 | background-image: linear-gradient(top, #5bc0de, #2f96b4); | |
2845 | background-repeat: repeat-x; | |
2846 | border-color: #2f96b4 #2f96b4 #1f6377; | |
2847 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |
2848 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); | |
2849 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); | |
2850 | } | |
2851 | ||
2852 | .btn-info:hover, | |
2853 | .btn-info:active, | |
2854 | .btn-info.active, | |
2855 | .btn-info.disabled, | |
2856 | .btn-info[disabled] { | |
2857 | background-color: #2f96b4; | |
2858 | *background-color: #2a85a0; | |
2859 | } | |
2860 | ||
2861 | .btn-info:active, | |
2862 | .btn-info.active { | |
2863 | background-color: #24748c \9; | |
2864 | } | |
2865 | ||
2866 | .btn-inverse { | |
2867 | background-color: #414141; | |
2868 | *background-color: #222222; | |
2869 | background-image: -ms-linear-gradient(top, #555555, #222222); | |
2870 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222)); | |
2871 | background-image: -webkit-linear-gradient(top, #555555, #222222); | |
2872 | background-image: -o-linear-gradient(top, #555555, #222222); | |
2873 | background-image: -moz-linear-gradient(top, #555555, #222222); | |
2874 | background-image: linear-gradient(top, #555555, #222222); | |
2875 | background-repeat: repeat-x; | |
2876 | border-color: #222222 #222222 #000000; | |
2877 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |
2878 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0); | |
2879 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); | |
2880 | } | |
2881 | ||
2882 | .btn-inverse:hover, | |
2883 | .btn-inverse:active, | |
2884 | .btn-inverse.active, | |
2885 | .btn-inverse.disabled, | |
2886 | .btn-inverse[disabled] { | |
2887 | background-color: #222222; | |
2888 | *background-color: #151515; | |
2889 | } | |
2890 | ||
2891 | .btn-inverse:active, | |
2892 | .btn-inverse.active { | |
2893 | background-color: #080808 \9; | |
2894 | } | |
2895 | ||
2896 | button.btn, | |
2897 | input[type="submit"].btn { | |
2898 | *padding-top: 2px; | |
2899 | *padding-bottom: 2px; | |
2900 | } | |
2901 | ||
2902 | button.btn::-moz-focus-inner, | |
2903 | input[type="submit"].btn::-moz-focus-inner { | |
2904 | padding: 0; | |
2905 | border: 0; | |
2906 | } | |
2907 | ||
2908 | button.btn.btn-large, | |
2909 | input[type="submit"].btn.btn-large { | |
2910 | *padding-top: 7px; | |
2911 | *padding-bottom: 7px; | |
2912 | } | |
2913 | ||
2914 | button.btn.btn-small, | |
2915 | input[type="submit"].btn.btn-small { | |
2916 | *padding-top: 3px; | |
2917 | *padding-bottom: 3px; | |
2918 | } | |
2919 | ||
2920 | button.btn.btn-mini, | |
2921 | input[type="submit"].btn.btn-mini { | |
2922 | *padding-top: 1px; | |
2923 | *padding-bottom: 1px; | |
2924 | } | |
2925 | ||
2926 | .btn-group { | |
2927 | position: relative; | |
2928 | *margin-left: .3em; | |
2929 | *zoom: 1; | |
2930 | } | |
2931 | ||
2932 | .btn-group:before, | |
2933 | .btn-group:after { | |
2934 | display: table; | |
2935 | content: ""; | |
2936 | } | |
2937 | ||
2938 | .btn-group:after { | |
2939 | clear: both; | |
2940 | } | |
2941 | ||
2942 | .btn-group:first-child { | |
2943 | *margin-left: 0; | |
2944 | } | |
2945 | ||
2946 | .btn-group + .btn-group { | |
2947 | margin-left: 5px; | |
2948 | } | |
2949 | ||
2950 | .btn-toolbar { | |
2951 | margin-top: 9px; | |
2952 | margin-bottom: 9px; | |
2953 | } | |
2954 | ||
2955 | .btn-toolbar .btn-group { | |
2956 | display: inline-block; | |
2957 | *display: inline; | |
2958 | /* IE7 inline-block hack */ | |
2959 | ||
2960 | *zoom: 1; | |
2961 | } | |
2962 | ||
2963 | .btn-group > .btn { | |
2964 | position: relative; | |
2965 | float: left; | |
2966 | margin-left: -1px; | |
2967 | -webkit-border-radius: 0; | |
2968 | -moz-border-radius: 0; | |
2969 | border-radius: 0; | |
2970 | } | |
2971 | ||
2972 | .btn-group > .btn:first-child { | |
2973 | margin-left: 0; | |
2974 | -webkit-border-bottom-left-radius: 4px; | |
2975 | border-bottom-left-radius: 4px; | |
2976 | -webkit-border-top-left-radius: 4px; | |
2977 | border-top-left-radius: 4px; | |
2978 | -moz-border-radius-bottomleft: 4px; | |
2979 | -moz-border-radius-topleft: 4px; | |
2980 | } | |
2981 | ||
2982 | .btn-group > .btn:last-child, | |
2983 | .btn-group > .dropdown-toggle { | |
2984 | -webkit-border-top-right-radius: 4px; | |
2985 | border-top-right-radius: 4px; | |
2986 | -webkit-border-bottom-right-radius: 4px; | |
2987 | border-bottom-right-radius: 4px; | |
2988 | -moz-border-radius-topright: 4px; | |
2989 | -moz-border-radius-bottomright: 4px; | |
2990 | } | |
2991 | ||
2992 | .btn-group > .btn.large:first-child { | |
2993 | margin-left: 0; | |
2994 | -webkit-border-bottom-left-radius: 6px; | |
2995 | border-bottom-left-radius: 6px; | |
2996 | -webkit-border-top-left-radius: 6px; | |
2997 | border-top-left-radius: 6px; | |
2998 | -moz-border-radius-bottomleft: 6px; | |
2999 | -moz-border-radius-topleft: 6px; | |
3000 | } | |
3001 | ||
3002 | .btn-group > .btn.large:last-child, | |
3003 | .btn-group > .large.dropdown-toggle { | |
3004 | -webkit-border-top-right-radius: 6px; | |
3005 | border-top-right-radius: 6px; | |
3006 | -webkit-border-bottom-right-radius: 6px; | |
3007 | border-bottom-right-radius: 6px; | |
3008 | -moz-border-radius-topright: 6px; | |
3009 | -moz-border-radius-bottomright: 6px; | |
3010 | } | |
3011 | ||
3012 | .btn-group > .btn:hover, | |
3013 | .btn-group > .btn:focus, | |
3014 | .btn-group > .btn:active, | |
3015 | .btn-group > .btn.active { | |
3016 | z-index: 2; | |
3017 | } | |
3018 | ||
3019 | .btn-group .dropdown-toggle:active, | |
3020 | .btn-group.open .dropdown-toggle { | |
3021 | outline: 0; | |
3022 | } | |
3023 | ||
3024 | .btn-group > .dropdown-toggle { | |
3025 | *padding-top: 4px; | |
3026 | padding-right: 8px; | |
3027 | *padding-bottom: 4px; | |
3028 | padding-left: 8px; | |
3029 | -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); | |
3030 | -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); | |
3031 | box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); | |
3032 | } | |
3033 | ||
3034 | .btn-group > .btn-mini.dropdown-toggle { | |
3035 | padding-right: 5px; | |
3036 | padding-left: 5px; | |
3037 | } | |
3038 | ||
3039 | .btn-group > .btn-small.dropdown-toggle { | |
3040 | *padding-top: 4px; | |
3041 | *padding-bottom: 4px; | |
3042 | } | |
3043 | ||
3044 | .btn-group > .btn-large.dropdown-toggle { | |
3045 | padding-right: 12px; | |
3046 | padding-left: 12px; | |
3047 | } | |
3048 | ||
3049 | .btn-group.open .dropdown-toggle { | |
3050 | background-image: none; | |
3051 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); | |
3052 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); | |
3053 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); | |
3054 | } | |
3055 | ||
3056 | .btn-group.open .btn.dropdown-toggle { | |
3057 | background-color: #e6e6e6; | |
3058 | } | |
3059 | ||
3060 | .btn-group.open .btn-primary.dropdown-toggle { | |
3061 | background-color: #0055cc; | |
3062 | } | |
3063 | ||
3064 | .btn-group.open .btn-warning.dropdown-toggle { | |
3065 | background-color: #f89406; | |
3066 | } | |
3067 | ||
3068 | .btn-group.open .btn-danger.dropdown-toggle { | |
3069 | background-color: #bd362f; | |
3070 | } | |
3071 | ||
3072 | .btn-group.open .btn-success.dropdown-toggle { | |
3073 | background-color: #51a351; | |
3074 | } | |
3075 | ||
3076 | .btn-group.open .btn-info.dropdown-toggle { | |
3077 | background-color: #2f96b4; | |
3078 | } | |
3079 | ||
3080 | .btn-group.open .btn-inverse.dropdown-toggle { | |
3081 | background-color: #222222; | |
3082 | } | |
3083 | ||
3084 | .btn .caret { | |
3085 | margin-top: 7px; | |
3086 | margin-left: 0; | |
3087 | } | |
3088 | ||
3089 | .btn:hover .caret, | |
3090 | .open.btn-group .caret { | |
3091 | opacity: 1; | |
3092 | filter: alpha(opacity=100); | |
3093 | } | |
3094 | ||
3095 | .btn-mini .caret { | |
3096 | margin-top: 5px; | |
3097 | } | |
3098 | ||
3099 | .btn-small .caret { | |
3100 | margin-top: 6px; | |
3101 | } | |
3102 | ||
3103 | .btn-large .caret { | |
3104 | margin-top: 6px; | |
3105 | border-top-width: 5px; | |
3106 | border-right-width: 5px; | |
3107 | border-left-width: 5px; | |
3108 | } | |
3109 | ||
3110 | .dropup .btn-large .caret { | |
3111 | border-top: 0; | |
3112 | border-bottom: 5px solid #000000; | |
3113 | } | |
3114 | ||
3115 | .btn-primary .caret, | |
3116 | .btn-warning .caret, | |
3117 | .btn-danger .caret, | |
3118 | .btn-info .caret, | |
3119 | .btn-success .caret, | |
3120 | .btn-inverse .caret { | |
3121 | border-top-color: #ffffff; | |
3122 | border-bottom-color: #ffffff; | |
3123 | opacity: 0.75; | |
3124 | filter: alpha(opacity=75); | |
3125 | } | |
3126 | ||
3127 | .alert { | |
3128 | padding: 8px 35px 8px 14px; | |
3129 | margin-bottom: 18px; | |
3130 | color: #c09853; | |
3131 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); | |
3132 | background-color: #fcf8e3; | |
3133 | border: 1px solid #fbeed5; | |
3134 | -webkit-border-radius: 4px; | |
3135 | -moz-border-radius: 4px; | |
3136 | border-radius: 4px; | |
3137 | } | |
3138 | ||
3139 | .alert-heading { | |
3140 | color: inherit; | |
3141 | } | |
3142 | ||
3143 | .alert .close { | |
3144 | position: relative; | |
3145 | top: -2px; | |
3146 | right: -21px; | |
3147 | line-height: 18px; | |
3148 | } | |
3149 | ||
3150 | .alert-success { | |
3151 | color: #468847; | |
3152 | background-color: #dff0d8; | |
3153 | border-color: #d6e9c6; | |
3154 | } | |
3155 | ||
3156 | .alert-danger, | |
3157 | .alert-error { | |
3158 | color: #b94a48; | |
3159 | background-color: #f2dede; | |
3160 | border-color: #eed3d7; | |
3161 | } | |
3162 | ||
3163 | .alert-info { | |
3164 | color: #3a87ad; | |
3165 | background-color: #d9edf7; | |
3166 | border-color: #bce8f1; | |
3167 | } | |
3168 | ||
3169 | .alert-block { | |
3170 | padding-top: 14px; | |
3171 | padding-bottom: 14px; | |
3172 | } | |
3173 | ||
3174 | .alert-block > p, | |
3175 | .alert-block > ul { | |
3176 | margin-bottom: 0; | |
3177 | } | |
3178 | ||
3179 | .alert-block p + p { | |
3180 | margin-top: 5px; | |
3181 | } | |
3182 | ||
3183 | .nav { | |
3184 | margin-bottom: 18px; | |
3185 | margin-left: 0; | |
3186 | list-style: none; | |
3187 | } | |
3188 | ||
3189 | .nav > li > a { | |
3190 | display: block; | |
3191 | } | |
3192 | ||
3193 | .nav > li > a:hover { | |
3194 | text-decoration: none; | |
3195 | background-color: #eeeeee; | |
3196 | } | |
3197 | ||
3198 | .nav > .pull-right { | |
3199 | float: right; | |
3200 | } | |
3201 | ||
3202 | .nav .nav-header { | |
3203 | display: block; | |
3204 | padding: 3px 15px; | |
3205 | font-size: 11px; | |
3206 | font-weight: bold; | |
3207 | line-height: 18px; | |
3208 | color: #999999; | |
3209 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); | |
3210 | text-transform: uppercase; | |
3211 | } | |
3212 | ||
3213 | .nav li + .nav-header { | |
3214 | margin-top: 9px; | |
3215 | } | |
3216 | ||
3217 | .nav-list { | |
3218 | padding-right: 15px; | |
3219 | padding-left: 15px; | |
3220 | margin-bottom: 0; | |
3221 | } | |
3222 | ||
3223 | .nav-list > li > a, | |
3224 | .nav-list .nav-header { | |
3225 | margin-right: -15px; | |
3226 | margin-left: -15px; | |
3227 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); | |
3228 | } | |
3229 | ||
3230 | .nav-list > li > a { | |
3231 | padding: 3px 15px; | |
3232 | } | |
3233 | ||
3234 | .nav-list > .active > a, | |
3235 | .nav-list > .active > a:hover { | |
3236 | color: #ffffff; | |
3237 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); | |
3238 | background-color: #0088cc; | |
3239 | } | |
3240 | ||
3241 | .nav-list [class^="icon-"] { | |
3242 | margin-right: 2px; | |
3243 | } | |
3244 | ||
3245 | .nav-list .divider { | |
3246 | *width: 100%; | |
3247 | height: 1px; | |
3248 | margin: 8px 1px; | |
3249 | *margin: -5px 0 5px; | |
3250 | overflow: hidden; | |
3251 | background-color: #e5e5e5; | |
3252 | border-bottom: 1px solid #ffffff; | |
3253 | } | |
3254 | ||
3255 | .nav-tabs, | |
3256 | .nav-pills { | |
3257 | *zoom: 1; | |
3258 | } | |
3259 | ||
3260 | .nav-tabs:before, | |
3261 | .nav-pills:before, | |
3262 | .nav-tabs:after, | |
3263 | .nav-pills:after { | |
3264 | display: table; | |
3265 | content: ""; | |
3266 | } | |
3267 | ||
3268 | .nav-tabs:after, | |
3269 | .nav-pills:after { | |
3270 | clear: both; | |
3271 | } | |
3272 | ||
3273 | .nav-tabs > li, | |
3274 | .nav-pills > li { | |
3275 | float: left; | |
3276 | } | |
3277 | ||
3278 | .nav-tabs > li > a, | |
3279 | .nav-pills > li > a { | |
3280 | padding-right: 12px; | |
3281 | padding-left: 12px; | |
3282 | margin-right: 2px; | |
3283 | line-height: 14px; | |
3284 | } | |
3285 | ||
3286 | .nav-tabs { | |
3287 | border-bottom: 1px solid #ddd; | |
3288 | } | |
3289 | ||
3290 | .nav-tabs > li { | |
3291 | margin-bottom: -1px; | |
3292 | } | |
3293 | ||
3294 | .nav-tabs > li > a { | |
3295 | padding-top: 8px; | |
3296 | padding-bottom: 8px; | |
3297 | line-height: 18px; | |
3298 | border: 1px solid transparent; | |
3299 | -webkit-border-radius: 4px 4px 0 0; | |
3300 | -moz-border-radius: 4px 4px 0 0; | |
3301 | border-radius: 4px 4px 0 0; | |
3302 | } | |
3303 | ||
3304 | .nav-tabs > li > a:hover { | |
3305 | border-color: #eeeeee #eeeeee #dddddd; | |
3306 | } | |
3307 | ||
3308 | .nav-tabs > .active > a, | |
3309 | .nav-tabs > .active > a:hover { | |
3310 | color: #555555; | |
3311 | cursor: default; | |
3312 | background-color: #ffffff; | |
3313 | border: 1px solid #ddd; | |
3314 | border-bottom-color: transparent; | |
3315 | } | |
3316 | ||
3317 | .nav-pills > li > a { | |
3318 | padding-top: 8px; | |
3319 | padding-bottom: 8px; | |
3320 | margin-top: 2px; | |
3321 | margin-bottom: 2px; | |
3322 | -webkit-border-radius: 5px; | |
3323 | -moz-border-radius: 5px; | |
3324 | border-radius: 5px; | |
3325 | } | |
3326 | ||
3327 | .nav-pills > .active > a, | |
3328 | .nav-pills > .active > a:hover { | |
3329 | color: #ffffff; | |
3330 | background-color: #0088cc; | |
3331 | } | |
3332 | ||
3333 | .nav-stacked > li { | |
3334 | float: none; | |
3335 | } | |
3336 | ||
3337 | .nav-stacked > li > a { | |
3338 | margin-right: 0; | |
3339 | } | |
3340 | ||
3341 | .nav-tabs.nav-stacked { | |
3342 | border-bottom: 0; | |
3343 | } | |
3344 | ||
3345 | .nav-tabs.nav-stacked > li > a { | |
3346 | border: 1px solid #ddd; | |
3347 | -webkit-border-radius: 0; | |
3348 | -moz-border-radius: 0; | |
3349 | border-radius: 0; | |
3350 | } | |
3351 | ||
3352 | .nav-tabs.nav-stacked > li:first-child > a { | |
3353 | -webkit-border-radius: 4px 4px 0 0; | |
3354 | -moz-border-radius: 4px 4px 0 0; | |
3355 | border-radius: 4px 4px 0 0; | |
3356 | } | |
3357 | ||
3358 | .nav-tabs.nav-stacked > li:last-child > a { | |
3359 | -webkit-border-radius: 0 0 4px 4px; | |
3360 | -moz-border-radius: 0 0 4px 4px; | |
3361 | border-radius: 0 0 4px 4px; | |
3362 | } | |
3363 | ||
3364 | .nav-tabs.nav-stacked > li > a:hover { | |
3365 | z-index: 2; | |
3366 | border-color: #ddd; | |
3367 | } | |
3368 | ||
3369 | .nav-pills.nav-stacked > li > a { | |
3370 | margin-bottom: 3px; | |
3371 | } | |
3372 | ||
3373 | .nav-pills.nav-stacked > li:last-child > a { | |
3374 | margin-bottom: 1px; | |
3375 | } | |
3376 | ||
3377 | .nav-tabs .dropdown-menu { | |
3378 | -webkit-border-radius: 0 0 5px 5px; | |
3379 | -moz-border-radius: 0 0 5px 5px; | |
3380 | border-radius: 0 0 5px 5px; | |
3381 | } | |
3382 | ||
3383 | .nav-pills .dropdown-menu { | |
3384 | -webkit-border-radius: 4px; | |
3385 | -moz-border-radius: 4px; | |
3386 | border-radius: 4px; | |
3387 | } | |
3388 | ||
3389 | .nav-tabs .dropdown-toggle .caret, | |
3390 | .nav-pills .dropdown-toggle .caret { | |
3391 | margin-top: 6px; | |
3392 | border-top-color: #0088cc; | |
3393 | border-bottom-color: #0088cc; | |
3394 | } | |
3395 | ||
3396 | .nav-tabs .dropdown-toggle:hover .caret, | |
3397 | .nav-pills .dropdown-toggle:hover .caret { | |
3398 | border-top-color: #005580; | |
3399 | border-bottom-color: #005580; | |
3400 | } | |
3401 | ||
3402 | .nav-tabs .active .dropdown-toggle .caret, | |
3403 | .nav-pills .active .dropdown-toggle .caret { | |
3404 | border-top-color: #333333; | |
3405 | border-bottom-color: #333333; | |
3406 | } | |
3407 | ||
3408 | .nav > .dropdown.active > a:hover { | |
3409 | color: #000000; | |
3410 | cursor: pointer; | |
3411 | } | |
3412 | ||
3413 | .nav-tabs .open .dropdown-toggle, | |
3414 | .nav-pills .open .dropdown-toggle, | |
3415 | .nav > li.dropdown.open.active > a:hover { | |
3416 | color: #ffffff; | |
3417 | background-color: #999999; | |
3418 | border-color: #999999; | |
3419 | } | |
3420 | ||
3421 | .nav li.dropdown.open .caret, | |
3422 | .nav li.dropdown.open.active .caret, | |
3423 | .nav li.dropdown.open a:hover .caret { | |
3424 | border-top-color: #ffffff; | |
3425 | border-bottom-color: #ffffff; | |
3426 | opacity: 1; | |
3427 | filter: alpha(opacity=100); | |
3428 | } | |
3429 | ||
3430 | .tabs-stacked .open > a:hover { | |
3431 | border-color: #999999; | |
3432 | } | |
3433 | ||
3434 | .tabbable { | |
3435 | *zoom: 1; | |
3436 | } | |
3437 | ||
3438 | .tabbable:before, | |
3439 | .tabbable:after { | |
3440 | display: table; | |
3441 | content: ""; | |
3442 | } | |
3443 | ||
3444 | .tabbable:after { | |
3445 | clear: both; | |
3446 | } | |
3447 | ||
3448 | .tab-content { | |
3449 | overflow: auto; | |
3450 | } | |
3451 | ||
3452 | .tabs-below > .nav-tabs, | |
3453 | .tabs-right > .nav-tabs, | |
3454 | .tabs-left > .nav-tabs { | |
3455 | border-bottom: 0; | |
3456 | } | |
3457 | ||
3458 | .tab-content > .tab-pane, | |
3459 | .pill-content > .pill-pane { | |
3460 | display: none; | |
3461 | } | |
3462 | ||
3463 | .tab-content > .active, | |
3464 | .pill-content > .active { | |
3465 | display: block; | |
3466 | } | |
3467 | ||
3468 | .tabs-below > .nav-tabs { | |
3469 | border-top: 1px solid #ddd; | |
3470 | } | |
3471 | ||
3472 | .tabs-below > .nav-tabs > li { | |
3473 | margin-top: -1px; | |
3474 | margin-bottom: 0; | |
3475 | } | |
3476 | ||
3477 | .tabs-below > .nav-tabs > li > a { | |
3478 | -webkit-border-radius: 0 0 4px 4px; | |
3479 | -moz-border-radius: 0 0 4px 4px; | |
3480 | border-radius: 0 0 4px 4px; | |
3481 | } | |
3482 | ||
3483 | .tabs-below > .nav-tabs > li > a:hover { | |
3484 | border-top-color: #ddd; | |
3485 | border-bottom-color: transparent; | |
3486 | } | |
3487 | ||
3488 | .tabs-below > .nav-tabs > .active > a, | |
3489 | .tabs-below > .nav-tabs > .active > a:hover { | |
3490 | border-color: transparent #ddd #ddd #ddd; | |
3491 | } | |
3492 | ||
3493 | .tabs-left > .nav-tabs > li, | |
3494 | .tabs-right > .nav-tabs > li { | |
3495 | float: none; | |
3496 | } | |
3497 | ||
3498 | .tabs-left > .nav-tabs > li > a, | |
3499 | .tabs-right > .nav-tabs > li > a { | |
3500 | min-width: 74px; | |
3501 | margin-right: 0; | |
3502 | margin-bottom: 3px; | |
3503 | } | |
3504 | ||
3505 | .tabs-left > .nav-tabs { | |
3506 | float: left; | |
3507 | margin-right: 19px; | |
3508 | border-right: 1px solid #ddd; | |
3509 | } | |
3510 | ||
3511 | .tabs-left > .nav-tabs > li > a { | |
3512 | margin-right: -1px; | |
3513 | -webkit-border-radius: 4px 0 0 4px; | |
3514 | -moz-border-radius: 4px 0 0 4px; | |
3515 | border-radius: 4px 0 0 4px; | |
3516 | } | |
3517 | ||
3518 | .tabs-left > .nav-tabs > li > a:hover { | |
3519 | border-color: #eeeeee #dddddd #eeeeee #eeeeee; | |
3520 | } | |
3521 | ||
3522 | .tabs-left > .nav-tabs .active > a, | |
3523 | .tabs-left > .nav-tabs .active > a:hover { | |
3524 | border-color: #ddd transparent #ddd #ddd; | |
3525 | *border-right-color: #ffffff; | |
3526 | } | |
3527 | ||
3528 | .tabs-right > .nav-tabs { | |
3529 | float: right; | |
3530 | margin-left: 19px; | |
3531 | border-left: 1px solid #ddd; | |
3532 | } | |
3533 | ||
3534 | .tabs-right > .nav-tabs > li > a { | |
3535 | margin-left: -1px; | |
3536 | -webkit-border-radius: 0 4px 4px 0; | |
3537 | -moz-border-radius: 0 4px 4px 0; | |
3538 | border-radius: 0 4px 4px 0; | |
3539 | } | |
3540 | ||
3541 | .tabs-right > .nav-tabs > li > a:hover { | |
3542 | border-color: #eeeeee #eeeeee #eeeeee #dddddd; | |
3543 | } | |
3544 | ||
3545 | .tabs-right > .nav-tabs .active > a, | |
3546 | .tabs-right > .nav-tabs .active > a:hover { | |
3547 | border-color: #ddd #ddd #ddd transparent; | |
3548 | *border-left-color: #ffffff; | |
3549 | } | |
3550 | ||
3551 | .navbar { | |
3552 | *position: relative; | |
3553 | *z-index: 2; | |
3554 | margin-bottom: 18px; | |
3555 | overflow: visible; | |
3556 | } | |
3557 | ||
3558 | .navbar-inner { | |
3559 | min-height: 40px; | |
3560 | padding-right: 20px; | |
3561 | padding-left: 20px; | |
3562 | background-color: #2c2c2c; | |
3563 | background-image: -moz-linear-gradient(top, #333333, #222222); | |
3564 | background-image: -ms-linear-gradient(top, #333333, #222222); | |
3565 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); | |
3566 | background-image: -webkit-linear-gradient(top, #333333, #222222); | |
3567 | background-image: -o-linear-gradient(top, #333333, #222222); | |
3568 | background-image: linear-gradient(top, #333333, #222222); | |
3569 | background-repeat: repeat-x; | |
3570 | -webkit-border-radius: 4px; | |
3571 | -moz-border-radius: 4px; | |
3572 | border-radius: 4px; | |
3573 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); | |
3574 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); | |
3575 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); | |
3576 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); | |
3577 | } | |
3578 | ||
3579 | .navbar .container { | |
3580 | width: auto; | |
3581 | } | |
3582 | ||
3583 | .nav-collapse.collapse { | |
3584 | height: auto; | |
3585 | } | |
3586 | ||
3587 | .navbar { | |
3588 | color: #999999; | |
3589 | } | |
3590 | ||
3591 | .navbar .brand:hover { | |
3592 | text-decoration: none; | |
3593 | } | |
3594 | ||
3595 | .navbar .brand { | |
3596 | display: block; | |
3597 | float: left; | |
3598 | padding: 8px 20px 12px; | |
3599 | margin-left: -20px; | |
3600 | font-size: 20px; | |
3601 | font-weight: 200; | |
3602 | line-height: 1; | |
3603 | color: #999999; | |
3604 | } | |
3605 | ||
3606 | .navbar .navbar-text { | |
3607 | margin-bottom: 0; | |
3608 | line-height: 40px; | |
3609 | } | |
3610 | ||
3611 | .navbar .navbar-link { | |
3612 | color: #999999; | |
3613 | } | |
3614 | ||
3615 | .navbar .navbar-link:hover { | |
3616 | color: #ffffff; | |
3617 | } | |
3618 | ||
3619 | .navbar .btn, | |
3620 | .navbar .btn-group { | |
3621 | margin-top: 5px; | |
3622 | } | |
3623 | ||
3624 | .navbar .btn-group .btn { | |
3625 | margin: 0; | |
3626 | } | |
3627 | ||
3628 | .navbar-form { | |
3629 | margin-bottom: 0; | |
3630 | *zoom: 1; | |
3631 | } | |
3632 | ||
3633 | .navbar-form:before, | |
3634 | .navbar-form:after { | |
3635 | display: table; | |
3636 | content: ""; | |
3637 | } | |
3638 | ||
3639 | .navbar-form:after { | |
3640 | clear: both; | |
3641 | } | |
3642 | ||
3643 | .navbar-form input, | |
3644 | .navbar-form select, | |
3645 | .navbar-form .radio, | |
3646 | .navbar-form .checkbox { | |
3647 | margin-top: 5px; | |
3648 | } | |
3649 | ||
3650 | .navbar-form input, | |
3651 | .navbar-form select { | |
3652 | display: inline-block; | |
3653 | margin-bottom: 0; | |
3654 | } | |
3655 | ||
3656 | .navbar-form input[type="image"], | |
3657 | .navbar-form input[type="checkbox"], | |
3658 | .navbar-form input[type="radio"] { | |
3659 | margin-top: 3px; | |
3660 | } | |
3661 | ||
3662 | .navbar-form .input-append, | |
3663 | .navbar-form .input-prepend { | |
3664 | margin-top: 6px; | |
3665 | white-space: normal; | |
3666 | } | |
3667 | ||
3668 | .navbar-form .input-append input, | |
3669 | .navbar-form .input-prepend input { | |
3670 | margin-top: 0; | |
3671 | } | |
3672 | ||
3673 | .navbar-search { | |
3674 | position: relative; | |
3675 | float: left; | |
3676 | margin-top: 6px; | |
3677 | margin-bottom: 0; | |
3678 | } | |
3679 | ||
3680 | .navbar-search .search-query { | |
3681 | padding: 4px 9px; | |
3682 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
3683 | font-size: 13px; | |
3684 | font-weight: normal; | |
3685 | line-height: 1; | |
3686 | color: #ffffff; | |
3687 | background-color: #626262; | |
3688 | border: 1px solid #151515; | |
3689 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); | |
3690 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); | |
3691 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); | |
3692 | -webkit-transition: none; | |
3693 | -moz-transition: none; | |
3694 | -ms-transition: none; | |
3695 | -o-transition: none; | |
3696 | transition: none; | |
3697 | } | |
3698 | ||
3699 | .navbar-search .search-query:-moz-placeholder { | |
3700 | color: #cccccc; | |
3701 | } | |
3702 | ||
3703 | .navbar-search .search-query::-webkit-input-placeholder { | |
3704 | color: #cccccc; | |
3705 | } | |
3706 | ||
3707 | .navbar-search .search-query:focus, | |
3708 | .navbar-search .search-query.focused { | |
3709 | padding: 5px 10px; | |
3710 | color: #333333; | |
3711 | text-shadow: 0 1px 0 #ffffff; | |
3712 | background-color: #ffffff; | |
3713 | border: 0; | |
3714 | outline: 0; | |
3715 | -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); | |
3716 | -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); | |
3717 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); | |
3718 | } | |
3719 | ||
3720 | .navbar-fixed-top, | |
3721 | .navbar-fixed-bottom { | |
3722 | position: fixed; | |
3723 | right: 0; | |
3724 | left: 0; | |
3725 | z-index: 1030; | |
3726 | margin-bottom: 0; | |
3727 | } | |
3728 | ||
3729 | .navbar-fixed-top .navbar-inner, | |
3730 | .navbar-fixed-bottom .navbar-inner { | |
3731 | padding-right: 0; | |
3732 | padding-left: 0; | |
3733 | -webkit-border-radius: 0; | |
3734 | -moz-border-radius: 0; | |
3735 | border-radius: 0; | |
3736 | } | |
3737 | ||
3738 | .navbar-fixed-top .container, | |
3739 | .navbar-fixed-bottom .container { | |
3740 | width: 940px; | |
3741 | } | |
3742 | ||
3743 | .navbar-fixed-top { | |
3744 | top: 0; | |
3745 | } | |
3746 | ||
3747 | .navbar-fixed-bottom { | |
3748 | bottom: 0; | |
3749 | } | |
3750 | ||
3751 | .navbar .nav { | |
3752 | position: relative; | |
3753 | left: 0; | |
3754 | display: block; | |
3755 | float: left; | |
3756 | margin: 0 10px 0 0; | |
3757 | } | |
3758 | ||
3759 | .navbar .nav.pull-right { | |
3760 | float: right; | |
3761 | } | |
3762 | ||
3763 | .navbar .nav > li { | |
3764 | display: block; | |
3765 | float: left; | |
3766 | } | |
3767 | ||
3768 | .navbar .nav > li > a { | |
3769 | float: none; | |
3770 | padding: 9px 10px 11px; | |
3771 | line-height: 19px; | |
3772 | color: #999999; | |
3773 | text-decoration: none; | |
3774 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | |
3775 | } | |
3776 | ||
3777 | .navbar .btn { | |
3778 | display: inline-block; | |
3779 | padding: 4px 10px 4px; | |
3780 | margin: 5px 5px 6px; | |
3781 | line-height: 18px; | |
3782 | } | |
3783 | ||
3784 | .navbar .btn-group { | |
3785 | padding: 5px 5px 6px; | |
3786 | margin: 0; | |
3787 | } | |
3788 | ||
3789 | .navbar .nav > li > a:hover { | |
3790 | color: #ffffff; | |
3791 | text-decoration: none; | |
3792 | background-color: transparent; | |
3793 | } | |
3794 | ||
3795 | .navbar .nav .active > a, | |
3796 | .navbar .nav .active > a:hover { | |
3797 | color: #ffffff; | |
3798 | text-decoration: none; | |
3799 | background-color: #222222; | |
3800 | } | |
3801 | ||
3802 | .navbar .divider-vertical { | |
3803 | width: 1px; | |
3804 | height: 40px; | |
3805 | margin: 0 9px; | |
3806 | overflow: hidden; | |
3807 | background-color: #222222; | |
3808 | border-right: 1px solid #333333; | |
3809 | } | |
3810 | ||
3811 | .navbar .nav.pull-right { | |
3812 | margin-right: 0; | |
3813 | margin-left: 10px; | |
3814 | } | |
3815 | ||
3816 | .navbar .btn-navbar { | |
3817 | display: none; | |
3818 | float: right; | |
3819 | padding: 7px 10px; | |
3820 | margin-right: 5px; | |
3821 | margin-left: 5px; | |
3822 | background-color: #2c2c2c; | |
3823 | *background-color: #222222; | |
3824 | background-image: -ms-linear-gradient(top, #333333, #222222); | |
3825 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); | |
3826 | background-image: -webkit-linear-gradient(top, #333333, #222222); | |
3827 | background-image: -o-linear-gradient(top, #333333, #222222); | |
3828 | background-image: linear-gradient(top, #333333, #222222); | |
3829 | background-image: -moz-linear-gradient(top, #333333, #222222); | |
3830 | background-repeat: repeat-x; | |
3831 | border-color: #222222 #222222 #000000; | |
3832 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |
3833 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); | |
3834 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); | |
3835 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); | |
3836 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); | |
3837 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); | |
3838 | } | |
3839 | ||
3840 | .navbar .btn-navbar:hover, | |
3841 | .navbar .btn-navbar:active, | |
3842 | .navbar .btn-navbar.active, | |
3843 | .navbar .btn-navbar.disabled, | |
3844 | .navbar .btn-navbar[disabled] { | |
3845 | background-color: #222222; | |
3846 | *background-color: #151515; | |
3847 | } | |
3848 | ||
3849 | .navbar .btn-navbar:active, | |
3850 | .navbar .btn-navbar.active { | |
3851 | background-color: #080808 \9; | |
3852 | } | |
3853 | ||
3854 | .navbar .btn-navbar .icon-bar { | |
3855 | display: block; | |
3856 | width: 18px; | |
3857 | height: 2px; | |
3858 | background-color: #f5f5f5; | |
3859 | -webkit-border-radius: 1px; | |
3860 | -moz-border-radius: 1px; | |
3861 | border-radius: 1px; | |
3862 | -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); | |
3863 | -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); | |
3864 | box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); | |
3865 | } | |
3866 | ||
3867 | .btn-navbar .icon-bar + .icon-bar { | |
3868 | margin-top: 3px; | |
3869 | } | |
3870 | ||
3871 | .navbar .dropdown-menu:before { | |
3872 | position: absolute; | |
3873 | top: -7px; | |
3874 | left: 9px; | |
3875 | display: inline-block; | |
3876 | border-right: 7px solid transparent; | |
3877 | border-bottom: 7px solid #ccc; | |
3878 | border-left: 7px solid transparent; | |
3879 | border-bottom-color: rgba(0, 0, 0, 0.2); | |
3880 | content: ''; | |
3881 | } | |
3882 | ||
3883 | .navbar .dropdown-menu:after { | |
3884 | position: absolute; | |
3885 | top: -6px; | |
3886 | left: 10px; | |
3887 | display: inline-block; | |
3888 | border-right: 6px solid transparent; | |
3889 | border-bottom: 6px solid #ffffff; | |
3890 | border-left: 6px solid transparent; | |
3891 | content: ''; | |
3892 | } | |
3893 | ||
3894 | .navbar-fixed-bottom .dropdown-menu:before { | |
3895 | top: auto; | |
3896 | bottom: -7px; | |
3897 | border-top: 7px solid #ccc; | |
3898 | border-bottom: 0; | |
3899 | border-top-color: rgba(0, 0, 0, 0.2); | |
3900 | } | |
3901 | ||
3902 | .navbar-fixed-bottom .dropdown-menu:after { | |
3903 | top: auto; | |
3904 | bottom: -6px; | |
3905 | border-top: 6px solid #ffffff; | |
3906 | border-bottom: 0; | |
3907 | } | |
3908 | ||
3909 | .navbar .nav li.dropdown .dropdown-toggle .caret, | |
3910 | .navbar .nav li.dropdown.open .caret { | |
3911 | border-top-color: #ffffff; | |
3912 | border-bottom-color: #ffffff; | |
3913 | } | |
3914 | ||
3915 | .navbar .nav li.dropdown.active .caret { | |
3916 | opacity: 1; | |
3917 | filter: alpha(opacity=100); | |
3918 | } | |
3919 | ||
3920 | .navbar .nav li.dropdown.open > .dropdown-toggle, | |
3921 | .navbar .nav li.dropdown.active > .dropdown-toggle, | |
3922 | .navbar .nav li.dropdown.open.active > .dropdown-toggle { | |
3923 | background-color: transparent; | |
3924 | } | |
3925 | ||
3926 | .navbar .nav li.dropdown.active > .dropdown-toggle:hover { | |
3927 | color: #ffffff; | |
3928 | } | |
3929 | ||
3930 | .navbar .pull-right .dropdown-menu, | |
3931 | .navbar .dropdown-menu.pull-right { | |
3932 | right: 0; | |
3933 | left: auto; | |
3934 | } | |
3935 | ||
3936 | .navbar .pull-right .dropdown-menu:before, | |
3937 | .navbar .dropdown-menu.pull-right:before { | |
3938 | right: 12px; | |
3939 | left: auto; | |
3940 | } | |
3941 | ||
3942 | .navbar .pull-right .dropdown-menu:after, | |
3943 | .navbar .dropdown-menu.pull-right:after { | |
3944 | right: 13px; | |
3945 | left: auto; | |
3946 | } | |
3947 | ||
3948 | .breadcrumb { | |
3949 | padding: 7px 14px; | |
3950 | margin: 0 0 18px; | |
3951 | list-style: none; | |
3952 | background-color: #fbfbfb; | |
3953 | background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); | |
3954 | background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); | |
3955 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); | |
3956 | background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); | |
3957 | background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); | |
3958 | background-image: linear-gradient(top, #ffffff, #f5f5f5); | |
3959 | background-repeat: repeat-x; | |
3960 | border: 1px solid #ddd; | |
3961 | -webkit-border-radius: 3px; | |
3962 | -moz-border-radius: 3px; | |
3963 | border-radius: 3px; | |
3964 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); | |
3965 | -webkit-box-shadow: inset 0 1px 0 #ffffff; | |
3966 | -moz-box-shadow: inset 0 1px 0 #ffffff; | |
3967 | box-shadow: inset 0 1px 0 #ffffff; | |
3968 | } | |
3969 | ||
3970 | .breadcrumb li { | |
3971 | display: inline-block; | |
3972 | *display: inline; | |
3973 | text-shadow: 0 1px 0 #ffffff; | |
3974 | *zoom: 1; | |
3975 | } | |
3976 | ||
3977 | .breadcrumb .divider { | |
3978 | padding: 0 5px; | |
3979 | color: #999999; | |
3980 | } | |
3981 | ||
3982 | .breadcrumb .active a { | |
3983 | color: #333333; | |
3984 | } | |
3985 | ||
3986 | .pagination { | |
3987 | height: 36px; | |
3988 | margin: 18px 0; | |
3989 | } | |
3990 | ||
3991 | .pagination ul { | |
3992 | display: inline-block; | |
3993 | *display: inline; | |
3994 | margin-bottom: 0; | |
3995 | margin-left: 0; | |
3996 | -webkit-border-radius: 3px; | |
3997 | -moz-border-radius: 3px; | |
3998 | border-radius: 3px; | |
3999 | *zoom: 1; | |
4000 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); | |
4001 | -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); | |
4002 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); | |
4003 | } | |
4004 | ||
4005 | .pagination li { | |
4006 | display: inline; | |
4007 | } | |
4008 | ||
4009 | .pagination a { | |
4010 | float: left; | |
4011 | padding: 0 14px; | |
4012 | line-height: 34px; | |
4013 | text-decoration: none; | |
4014 | border: 1px solid #ddd; | |
4015 | border-left-width: 0; | |
4016 | } | |
4017 | ||
4018 | .pagination a:hover, | |
4019 | .pagination .active a { | |
4020 | background-color: #f5f5f5; | |
4021 | } | |
4022 | ||
4023 | .pagination .active a { | |
4024 | color: #999999; | |
4025 | cursor: default; | |
4026 | } | |
4027 | ||
4028 | .pagination .disabled span, | |
4029 | .pagination .disabled a, | |
4030 | .pagination .disabled a:hover { | |
4031 | color: #999999; | |
4032 | cursor: default; | |
4033 | background-color: transparent; | |
4034 | } | |
4035 | ||
4036 | .pagination li:first-child a { | |
4037 | border-left-width: 1px; | |
4038 | -webkit-border-radius: 3px 0 0 3px; | |
4039 | -moz-border-radius: 3px 0 0 3px; | |
4040 | border-radius: 3px 0 0 3px; | |
4041 | } | |
4042 | ||
4043 | .pagination li:last-child a { | |
4044 | -webkit-border-radius: 0 3px 3px 0; | |
4045 | -moz-border-radius: 0 3px 3px 0; | |
4046 | border-radius: 0 3px 3px 0; | |
4047 | } | |
4048 | ||
4049 | .pagination-centered { | |
4050 | text-align: center; | |
4051 | } | |
4052 | ||
4053 | .pagination-right { | |
4054 | text-align: right; | |
4055 | } | |
4056 | ||
4057 | .pager { | |
4058 | margin-bottom: 18px; | |
4059 | margin-left: 0; | |
4060 | text-align: center; | |
4061 | list-style: none; | |
4062 | *zoom: 1; | |
4063 | } | |
4064 | ||
4065 | .pager:before, | |
4066 | .pager:after { | |
4067 | display: table; | |
4068 | content: ""; | |
4069 | } | |
4070 | ||
4071 | .pager:after { | |
4072 | clear: both; | |
4073 | } | |
4074 | ||
4075 | .pager li { | |
4076 | display: inline; | |
4077 | } | |
4078 | ||
4079 | .pager a { | |
4080 | display: inline-block; | |
4081 | padding: 5px 14px; | |
4082 | background-color: #fff; | |
4083 | border: 1px solid #ddd; | |
4084 | -webkit-border-radius: 15px; | |
4085 | -moz-border-radius: 15px; | |
4086 | border-radius: 15px; | |
4087 | } | |
4088 | ||
4089 | .pager a:hover { | |
4090 | text-decoration: none; | |
4091 | background-color: #f5f5f5; | |
4092 | } | |
4093 | ||
4094 | .pager .next a { | |
4095 | float: right; | |
4096 | } | |
4097 | ||
4098 | .pager .previous a { | |
4099 | float: left; | |
4100 | } | |
4101 | ||
4102 | .pager .disabled a, | |
4103 | .pager .disabled a:hover { | |
4104 | color: #999999; | |
4105 | cursor: default; | |
4106 | background-color: #fff; | |
4107 | } | |
4108 | ||
4109 | .modal-open .dropdown-menu { | |
4110 | z-index: 2050; | |
4111 | } | |
4112 | ||
4113 | .modal-open .dropdown.open { | |
4114 | *z-index: 2050; | |
4115 | } | |
4116 | ||
4117 | .modal-open .popover { | |
4118 | z-index: 2060; | |
4119 | } | |
4120 | ||
4121 | .modal-open .tooltip { | |
4122 | z-index: 2070; | |
4123 | } | |
4124 | ||
4125 | .modal-backdrop { | |
4126 | position: fixed; | |
4127 | top: 0; | |
4128 | right: 0; | |
4129 | bottom: 0; | |
4130 | left: 0; | |
4131 | z-index: 1040; | |
4132 | background-color: #000000; | |
4133 | } | |
4134 | ||
4135 | .modal-backdrop.fade { | |
4136 | opacity: 0; | |
4137 | } | |
4138 | ||
4139 | .modal-backdrop, | |
4140 | .modal-backdrop.fade.in { | |
4141 | opacity: 0.8; | |
4142 | filter: alpha(opacity=80); | |
4143 | } | |
4144 | ||
4145 | .modal { | |
4146 | position: fixed; | |
4147 | top: 50%; | |
4148 | left: 50%; | |
4149 | z-index: 1050; | |
4150 | width: 560px; | |
4151 | margin: -250px 0 0 -280px; | |
4152 | overflow: auto; | |
4153 | background-color: #ffffff; | |
4154 | border: 1px solid #999; | |
4155 | border: 1px solid rgba(0, 0, 0, 0.3); | |
4156 | *border: 1px solid #999; | |
4157 | -webkit-border-radius: 6px; | |
4158 | -moz-border-radius: 6px; | |
4159 | border-radius: 6px; | |
4160 | -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); | |
4161 | -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); | |
4162 | box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); | |
4163 | -webkit-background-clip: padding-box; | |
4164 | -moz-background-clip: padding-box; | |
4165 | background-clip: padding-box; | |
4166 | } | |
4167 | ||
4168 | .modal.fade { | |
4169 | top: -25%; | |
4170 | -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; | |
4171 | -moz-transition: opacity 0.3s linear, top 0.3s ease-out; | |
4172 | -ms-transition: opacity 0.3s linear, top 0.3s ease-out; | |
4173 | -o-transition: opacity 0.3s linear, top 0.3s ease-out; | |
4174 | transition: opacity 0.3s linear, top 0.3s ease-out; | |
4175 | } | |
4176 | ||
4177 | .modal.fade.in { | |
4178 | top: 50%; | |
4179 | } | |
4180 | ||
4181 | .modal-header { | |
4182 | padding: 9px 15px; | |
4183 | border-bottom: 1px solid #eee; | |
4184 | } | |
4185 | ||
4186 | .modal-header .close { | |
4187 | margin-top: 2px; | |
4188 | } | |
4189 | ||
4190 | .modal-body { | |
4191 | max-height: 400px; | |
4192 | padding: 15px; | |
4193 | overflow-y: auto; | |
4194 | } | |
4195 | ||
4196 | .modal-form { | |
4197 | margin-bottom: 0; | |
4198 | } | |
4199 | ||
4200 | .modal-footer { | |
4201 | padding: 14px 15px 15px; | |
4202 | margin-bottom: 0; | |
4203 | text-align: right; | |
4204 | background-color: #f5f5f5; | |
4205 | border-top: 1px solid #ddd; | |
4206 | -webkit-border-radius: 0 0 6px 6px; | |
4207 | -moz-border-radius: 0 0 6px 6px; | |
4208 | border-radius: 0 0 6px 6px; | |
4209 | *zoom: 1; | |
4210 | -webkit-box-shadow: inset 0 1px 0 #ffffff; | |
4211 | -moz-box-shadow: inset 0 1px 0 #ffffff; | |
4212 | box-shadow: inset 0 1px 0 #ffffff; | |
4213 | } | |
4214 | ||
4215 | .modal-footer:before, | |
4216 | .modal-footer:after { | |
4217 | display: table; | |
4218 | content: ""; | |
4219 | } | |
4220 | ||
4221 | .modal-footer:after { | |
4222 | clear: both; | |
4223 | } | |
4224 | ||
4225 | .modal-footer .btn + .btn { | |
4226 | margin-bottom: 0; | |
4227 | margin-left: 5px; | |
4228 | } | |
4229 | ||
4230 | .modal-footer .btn-group .btn + .btn { | |
4231 | margin-left: -1px; | |
4232 | } | |
4233 | ||
4234 | .tooltip { | |
4235 | position: absolute; | |
4236 | z-index: 1020; | |
4237 | display: block; | |
4238 | padding: 5px; | |
4239 | font-size: 11px; | |
4240 | opacity: 0; | |
4241 | filter: alpha(opacity=0); | |
4242 | visibility: visible; | |
4243 | } | |
4244 | ||
4245 | .tooltip.in { | |
4246 | opacity: 0.8; | |
4247 | filter: alpha(opacity=80); | |
4248 | } | |
4249 | ||
4250 | .tooltip.top { | |
4251 | margin-top: -2px; | |
4252 | } | |
4253 | ||
4254 | .tooltip.right { | |
4255 | margin-left: 2px; | |
4256 | } | |
4257 | ||
4258 | .tooltip.bottom { | |
4259 | margin-top: 2px; | |
4260 | } | |
4261 | ||
4262 | .tooltip.left { | |
4263 | margin-left: -2px; | |
4264 | } | |
4265 | ||
4266 | .tooltip.top .tooltip-arrow { | |
4267 | bottom: 0; | |
4268 | left: 50%; | |
4269 | margin-left: -5px; | |
4270 | border-top: 5px solid #000000; | |
4271 | border-right: 5px solid transparent; | |
4272 | border-left: 5px solid transparent; | |
4273 | } | |
4274 | ||
4275 | .tooltip.left .tooltip-arrow { | |
4276 | top: 50%; | |
4277 | right: 0; | |
4278 | margin-top: -5px; | |
4279 | border-top: 5px solid transparent; | |
4280 | border-bottom: 5px solid transparent; | |
4281 | border-left: 5px solid #000000; | |
4282 | } | |
4283 | ||
4284 | .tooltip.bottom .tooltip-arrow { | |
4285 | top: 0; | |
4286 | left: 50%; | |
4287 | margin-left: -5px; | |
4288 | border-right: 5px solid transparent; | |
4289 | border-bottom: 5px solid #000000; | |
4290 | border-left: 5px solid transparent; | |
4291 | } | |
4292 | ||
4293 | .tooltip.right .tooltip-arrow { | |
4294 | top: 50%; | |
4295 | left: 0; | |
4296 | margin-top: -5px; | |
4297 | border-top: 5px solid transparent; | |
4298 | border-right: 5px solid #000000; | |
4299 | border-bottom: 5px solid transparent; | |
4300 | } | |
4301 | ||
4302 | .tooltip-inner { | |
4303 | max-width: 200px; | |
4304 | padding: 3px 8px; | |
4305 | color: #ffffff; | |
4306 | text-align: center; | |
4307 | text-decoration: none; | |
4308 | background-color: #000000; | |
4309 | -webkit-border-radius: 4px; | |
4310 | -moz-border-radius: 4px; | |
4311 | border-radius: 4px; | |
4312 | } | |
4313 | ||
4314 | .tooltip-arrow { | |
4315 | position: absolute; | |
4316 | width: 0; | |
4317 | height: 0; | |
4318 | } | |
4319 | ||
4320 | .popover { | |
4321 | position: absolute; | |
4322 | top: 0; | |
4323 | left: 0; | |
4324 | z-index: 1010; | |
4325 | display: none; | |
4326 | padding: 5px; | |
4327 | } | |
4328 | ||
4329 | .popover.top { | |
4330 | margin-top: -5px; | |
4331 | } | |
4332 | ||
4333 | .popover.right { | |
4334 | margin-left: 5px; | |
4335 | } | |
4336 | ||
4337 | .popover.bottom { | |
4338 | margin-top: 5px; | |
4339 | } | |
4340 | ||
4341 | .popover.left { | |
4342 | margin-left: -5px; | |
4343 | } | |
4344 | ||
4345 | .popover.top .arrow { | |
4346 | bottom: 0; | |
4347 | left: 50%; | |
4348 | margin-left: -5px; | |
4349 | border-top: 5px solid #000000; | |
4350 | border-right: 5px solid transparent; | |
4351 | border-left: 5px solid transparent; | |
4352 | } | |
4353 | ||
4354 | .popover.right .arrow { | |
4355 | top: 50%; | |
4356 | left: 0; | |
4357 | margin-top: -5px; | |
4358 | border-top: 5px solid transparent; | |
4359 | border-right: 5px solid #000000; | |
4360 | border-bottom: 5px solid transparent; | |
4361 | } | |
4362 | ||
4363 | .popover.bottom .arrow { | |
4364 | top: 0; | |
4365 | left: 50%; | |
4366 | margin-left: -5px; | |
4367 | border-right: 5px solid transparent; | |
4368 | border-bottom: 5px solid #000000; | |
4369 | border-left: 5px solid transparent; | |
4370 | } | |
4371 | ||
4372 | .popover.left .arrow { | |
4373 | top: 50%; | |
4374 | right: 0; | |
4375 | margin-top: -5px; | |
4376 | border-top: 5px solid transparent; | |
4377 | border-bottom: 5px solid transparent; | |
4378 | border-left: 5px solid #000000; | |
4379 | } | |
4380 | ||
4381 | .popover .arrow { | |
4382 | position: absolute; | |
4383 | width: 0; | |
4384 | height: 0; | |
4385 | } | |
4386 | ||
4387 | .popover-inner { | |
4388 | width: 280px; | |
4389 | padding: 3px; | |
4390 | overflow: hidden; | |
4391 | background: #000000; | |
4392 | background: rgba(0, 0, 0, 0.8); | |
4393 | -webkit-border-radius: 6px; | |
4394 | -moz-border-radius: 6px; | |
4395 | border-radius: 6px; | |
4396 | -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); | |
4397 | -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); | |
4398 | box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); | |
4399 | } | |
4400 | ||
4401 | .popover-title { | |
4402 | padding: 9px 15px; | |
4403 | line-height: 1; | |
4404 | background-color: #f5f5f5; | |
4405 | border-bottom: 1px solid #eee; | |
4406 | -webkit-border-radius: 3px 3px 0 0; | |
4407 | -moz-border-radius: 3px 3px 0 0; | |
4408 | border-radius: 3px 3px 0 0; | |
4409 | } | |
4410 | ||
4411 | .popover-content { | |
4412 | padding: 14px; | |
4413 | background-color: #ffffff; | |
4414 | -webkit-border-radius: 0 0 3px 3px; | |
4415 | -moz-border-radius: 0 0 3px 3px; | |
4416 | border-radius: 0 0 3px 3px; | |
4417 | -webkit-background-clip: padding-box; | |
4418 | -moz-background-clip: padding-box; | |
4419 | background-clip: padding-box; | |
4420 | } | |
4421 | ||
4422 | .popover-content p, | |
4423 | .popover-content ul, | |
4424 | .popover-content ol { | |
4425 | margin-bottom: 0; | |
4426 | } | |
4427 | ||
4428 | .thumbnails { | |
4429 | margin-left: -20px; | |
4430 | list-style: none; | |
4431 | *zoom: 1; | |
4432 | } | |
4433 | ||
4434 | .thumbnails:before, | |
4435 | .thumbnails:after { | |
4436 | display: table; | |
4437 | content: ""; | |
4438 | } | |
4439 | ||
4440 | .thumbnails:after { | |
4441 | clear: both; | |
4442 | } | |
4443 | ||
4444 | .row-fluid .thumbnails { | |
4445 | margin-left: 0; | |
4446 | } | |
4447 | ||
4448 | .thumbnails > li { | |
4449 | float: left; | |
4450 | margin-bottom: 18px; | |
4451 | margin-left: 20px; | |
4452 | } | |
4453 | ||
4454 | .thumbnail { | |
4455 | display: block; | |
4456 | padding: 4px; | |
4457 | line-height: 1; | |
4458 | border: 1px solid #ddd; | |
4459 | -webkit-border-radius: 4px; | |
4460 | -moz-border-radius: 4px; | |
4461 | border-radius: 4px; | |
4462 | -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); | |
4463 | -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); | |
4464 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); | |
4465 | } | |
4466 | ||
4467 | a.thumbnail:hover { | |
4468 | border-color: #0088cc; | |
4469 | -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); | |
4470 | -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); | |
4471 | box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); | |
4472 | } | |
4473 | ||
4474 | .thumbnail > img { | |
4475 | display: block; | |
4476 | max-width: 100%; | |
4477 | margin-right: auto; | |
4478 | margin-left: auto; | |
4479 | } | |
4480 | ||
4481 | .thumbnail .caption { | |
4482 | padding: 9px; | |
4483 | } | |
4484 | ||
4485 | .label, | |
4486 | .badge { | |
4487 | font-size: 10.998px; | |
4488 | font-weight: bold; | |
4489 | line-height: 14px; | |
4490 | color: #ffffff; | |
4491 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | |
4492 | white-space: nowrap; | |
4493 | vertical-align: baseline; | |
4494 | background-color: #999999; | |
4495 | } | |
4496 | ||
4497 | .label { | |
4498 | padding: 1px 4px 2px; | |
4499 | -webkit-border-radius: 3px; | |
4500 | -moz-border-radius: 3px; | |
4501 | border-radius: 3px; | |
4502 | } | |
4503 | ||
4504 | .badge { | |
4505 | padding: 1px 9px 2px; | |
4506 | -webkit-border-radius: 9px; | |
4507 | -moz-border-radius: 9px; | |
4508 | border-radius: 9px; | |
4509 | } | |
4510 | ||
4511 | a.label:hover, | |
4512 | a.badge:hover { | |
4513 | color: #ffffff; | |
4514 | text-decoration: none; | |
4515 | cursor: pointer; | |
4516 | } | |
4517 | ||
4518 | .label-important, | |
4519 | .badge-important { | |
4520 | background-color: #b94a48; | |
4521 | } | |
4522 | ||
4523 | .label-important[href], | |
4524 | .badge-important[href] { | |
4525 | background-color: #953b39; | |
4526 | } | |
4527 | ||
4528 | .label-warning, | |
4529 | .badge-warning { | |
4530 | background-color: #f89406; | |
4531 | } | |
4532 | ||
4533 | .label-warning[href], | |
4534 | .badge-warning[href] { | |
4535 | background-color: #c67605; | |
4536 | } | |
4537 | ||
4538 | .label-success, | |
4539 | .badge-success { | |
4540 | background-color: #468847; | |
4541 | } | |
4542 | ||
4543 | .label-success[href], | |
4544 | .badge-success[href] { | |
4545 | background-color: #356635; | |
4546 | } | |
4547 | ||
4548 | .label-info, | |
4549 | .badge-info { | |
4550 | background-color: #3a87ad; | |
4551 | } | |
4552 | ||
4553 | .label-info[href], | |
4554 | .badge-info[href] { | |
4555 | background-color: #2d6987; | |
4556 | } | |
4557 | ||
4558 | .label-inverse, | |
4559 | .badge-inverse { | |
4560 | background-color: #333333; | |
4561 | } | |
4562 | ||
4563 | .label-inverse[href], | |
4564 | .badge-inverse[href] { | |
4565 | background-color: #1a1a1a; | |
4566 | } | |
4567 | ||
4568 | @-webkit-keyframes progress-bar-stripes { | |
4569 | from { | |
4570 | background-position: 40px 0; | |
4571 | } | |
4572 | to { | |
4573 | background-position: 0 0; | |
4574 | } | |
4575 | } | |
4576 | ||
4577 | @-moz-keyframes progress-bar-stripes { | |
4578 | from { | |
4579 | background-position: 40px 0; | |
4580 | } | |
4581 | to { | |
4582 | background-position: 0 0; | |
4583 | } | |
4584 | } | |
4585 | ||
4586 | @-ms-keyframes progress-bar-stripes { | |
4587 | from { | |
4588 | background-position: 40px 0; | |
4589 | } | |
4590 | to { | |
4591 | background-position: 0 0; | |
4592 | } | |
4593 | } | |
4594 | ||
4595 | @-o-keyframes progress-bar-stripes { | |
4596 | from { | |
4597 | background-position: 0 0; | |
4598 | } | |
4599 | to { | |
4600 | background-position: 40px 0; | |
4601 | } | |
4602 | } | |
4603 | ||
4604 | @keyframes progress-bar-stripes { | |
4605 | from { | |
4606 | background-position: 40px 0; | |
4607 | } | |
4608 | to { | |
4609 | background-position: 0 0; | |
4610 | } | |
4611 | } | |
4612 | ||
4613 | .progress { | |
4614 | height: 18px; | |
4615 | margin-bottom: 18px; | |
4616 | overflow: hidden; | |
4617 | background-color: #f7f7f7; | |
4618 | background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); | |
4619 | background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); | |
4620 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); | |
4621 | background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); | |
4622 | background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); | |
4623 | background-image: linear-gradient(top, #f5f5f5, #f9f9f9); | |
4624 | background-repeat: repeat-x; | |
4625 | -webkit-border-radius: 4px; | |
4626 | -moz-border-radius: 4px; | |
4627 | border-radius: 4px; | |
4628 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); | |
4629 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); | |
4630 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); | |
4631 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); | |
4632 | } | |
4633 | ||
4634 | .progress .bar { | |
4635 | width: 0; | |
4636 | height: 18px; | |
4637 | font-size: 12px; | |
4638 | color: #ffffff; | |
4639 | text-align: center; | |
4640 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | |
4641 | background-color: #0e90d2; | |
4642 | background-image: -moz-linear-gradient(top, #149bdf, #0480be); | |
4643 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); | |
4644 | background-image: -webkit-linear-gradient(top, #149bdf, #0480be); | |
4645 | background-image: -o-linear-gradient(top, #149bdf, #0480be); | |
4646 | background-image: linear-gradient(top, #149bdf, #0480be); | |
4647 | background-image: -ms-linear-gradient(top, #149bdf, #0480be); | |
4648 | background-repeat: repeat-x; | |
4649 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); | |
4650 | -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); | |
4651 | -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); | |
4652 | box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); | |
4653 | -webkit-box-sizing: border-box; | |
4654 | -moz-box-sizing: border-box; | |
4655 | -ms-box-sizing: border-box; | |
4656 | box-sizing: border-box; | |
4657 | -webkit-transition: width 0.6s ease; | |
4658 | -moz-transition: width 0.6s ease; | |
4659 | -ms-transition: width 0.6s ease; | |
4660 | -o-transition: width 0.6s ease; | |
4661 | transition: width 0.6s ease; | |
4662 | } | |
4663 | ||
4664 | .progress-striped .bar { | |
4665 | background-color: #149bdf; | |
4666 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4667 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4668 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4669 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4670 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); | |
4671 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4672 | -webkit-background-size: 40px 40px; | |
4673 | -moz-background-size: 40px 40px; | |
4674 | -o-background-size: 40px 40px; | |
4675 | background-size: 40px 40px; | |
4676 | } | |
4677 | ||
4678 | .progress.active .bar { | |
4679 | -webkit-animation: progress-bar-stripes 2s linear infinite; | |
4680 | -moz-animation: progress-bar-stripes 2s linear infinite; | |
4681 | -ms-animation: progress-bar-stripes 2s linear infinite; | |
4682 | -o-animation: progress-bar-stripes 2s linear infinite; | |
4683 | animation: progress-bar-stripes 2s linear infinite; | |
4684 | } | |
4685 | ||
4686 | .progress-danger .bar { | |
4687 | background-color: #dd514c; | |
4688 | background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); | |
4689 | background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); | |
4690 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); | |
4691 | background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); | |
4692 | background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); | |
4693 | background-image: linear-gradient(top, #ee5f5b, #c43c35); | |
4694 | background-repeat: repeat-x; | |
4695 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); | |
4696 | } | |
4697 | ||
4698 | .progress-danger.progress-striped .bar { | |
4699 | background-color: #ee5f5b; | |
4700 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); | |
4701 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4702 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4703 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4704 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4705 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4706 | } | |
4707 | ||
4708 | .progress-success .bar { | |
4709 | background-color: #5eb95e; | |
4710 | background-image: -moz-linear-gradient(top, #62c462, #57a957); | |
4711 | background-image: -ms-linear-gradient(top, #62c462, #57a957); | |
4712 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); | |
4713 | background-image: -webkit-linear-gradient(top, #62c462, #57a957); | |
4714 | background-image: -o-linear-gradient(top, #62c462, #57a957); | |
4715 | background-image: linear-gradient(top, #62c462, #57a957); | |
4716 | background-repeat: repeat-x; | |
4717 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); | |
4718 | } | |
4719 | ||
4720 | .progress-success.progress-striped .bar { | |
4721 | background-color: #62c462; | |
4722 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); | |
4723 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4724 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4725 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4726 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4727 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4728 | } | |
4729 | ||
4730 | .progress-info .bar { | |
4731 | background-color: #4bb1cf; | |
4732 | background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); | |
4733 | background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); | |
4734 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); | |
4735 | background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); | |
4736 | background-image: -o-linear-gradient(top, #5bc0de, #339bb9); | |
4737 | background-image: linear-gradient(top, #5bc0de, #339bb9); | |
4738 | background-repeat: repeat-x; | |
4739 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); | |
4740 | } | |
4741 | ||
4742 | .progress-info.progress-striped .bar { | |
4743 | background-color: #5bc0de; | |
4744 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); | |
4745 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4746 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4747 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4748 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4749 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4750 | } | |
4751 | ||
4752 | .progress-warning .bar { | |
4753 | background-color: #faa732; | |
4754 | background-image: -moz-linear-gradient(top, #fbb450, #f89406); | |
4755 | background-image: -ms-linear-gradient(top, #fbb450, #f89406); | |
4756 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); | |
4757 | background-image: -webkit-linear-gradient(top, #fbb450, #f89406); | |
4758 | background-image: -o-linear-gradient(top, #fbb450, #f89406); | |
4759 | background-image: linear-gradient(top, #fbb450, #f89406); | |
4760 | background-repeat: repeat-x; | |
4761 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); | |
4762 | } | |
4763 | ||
4764 | .progress-warning.progress-striped .bar { | |
4765 | background-color: #fbb450; | |
4766 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); | |
4767 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4768 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4769 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4770 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4771 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); | |
4772 | } | |
4773 | ||
4774 | .accordion { | |
4775 | margin-bottom: 18px; | |
4776 | } | |
4777 | ||
4778 | .accordion-group { | |
4779 | margin-bottom: 2px; | |
4780 | border: 1px solid #e5e5e5; | |
4781 | -webkit-border-radius: 4px; | |
4782 | -moz-border-radius: 4px; | |
4783 | border-radius: 4px; | |
4784 | } | |
4785 | ||
4786 | .accordion-heading { | |
4787 | border-bottom: 0; | |
4788 | } | |
4789 | ||
4790 | .accordion-heading .accordion-toggle { | |
4791 | display: block; | |
4792 | padding: 8px 15px; | |
4793 | } | |
4794 | ||
4795 | .accordion-toggle { | |
4796 | cursor: pointer; | |
4797 | } | |
4798 | ||
4799 | .accordion-inner { | |
4800 | padding: 9px 15px; | |
4801 | border-top: 1px solid #e5e5e5; | |
4802 | } | |
4803 | ||
4804 | .carousel { | |
4805 | position: relative; | |
4806 | margin-bottom: 18px; | |
4807 | line-height: 1; | |
4808 | } | |
4809 | ||
4810 | .carousel-inner { | |
4811 | position: relative; | |
4812 | width: 100%; | |
4813 | overflow: hidden; | |
4814 | } | |
4815 | ||
4816 | .carousel .item { | |
4817 | position: relative; | |
4818 | display: none; | |
4819 | -webkit-transition: 0.6s ease-in-out left; | |
4820 | -moz-transition: 0.6s ease-in-out left; | |
4821 | -ms-transition: 0.6s ease-in-out left; | |
4822 | -o-transition: 0.6s ease-in-out left; | |
4823 | transition: 0.6s ease-in-out left; | |
4824 | } | |
4825 | ||
4826 | .carousel .item > img { | |
4827 | display: block; | |
4828 | line-height: 1; | |
4829 | } | |
4830 | ||
4831 | .carousel .active, | |
4832 | .carousel .next, | |
4833 | .carousel .prev { | |
4834 | display: block; | |
4835 | } | |
4836 | ||
4837 | .carousel .active { | |
4838 | left: 0; | |
4839 | } | |
4840 | ||
4841 | .carousel .next, | |
4842 | .carousel .prev { | |
4843 | position: absolute; | |
4844 | top: 0; | |
4845 | width: 100%; | |
4846 | } | |
4847 | ||
4848 | .carousel .next { | |
4849 | left: 100%; | |
4850 | } | |
4851 | ||
4852 | .carousel .prev { | |
4853 | left: -100%; | |
4854 | } | |
4855 | ||
4856 | .carousel .next.left, | |
4857 | .carousel .prev.right { | |
4858 | left: 0; | |
4859 | } | |
4860 | ||
4861 | .carousel .active.left { | |
4862 | left: -100%; | |
4863 | } | |
4864 | ||
4865 | .carousel .active.right { | |
4866 | left: 100%; | |
4867 | } | |
4868 | ||
4869 | .carousel-control { | |
4870 | position: absolute; | |
4871 | top: 40%; | |
4872 | left: 15px; | |
4873 | width: 40px; | |
4874 | height: 40px; | |
4875 | margin-top: -20px; | |
4876 | font-size: 60px; | |
4877 | font-weight: 100; | |
4878 | line-height: 30px; | |
4879 | color: #ffffff; | |
4880 | text-align: center; | |
4881 | background: #222222; | |
4882 | border: 3px solid #ffffff; | |
4883 | -webkit-border-radius: 23px; | |
4884 | -moz-border-radius: 23px; | |
4885 | border-radius: 23px; | |
4886 | opacity: 0.5; | |
4887 | filter: alpha(opacity=50); | |
4888 | } | |
4889 | ||
4890 | .carousel-control.right { | |
4891 | right: 15px; | |
4892 | left: auto; | |
4893 | } | |
4894 | ||
4895 | .carousel-control:hover { | |
4896 | color: #ffffff; | |
4897 | text-decoration: none; | |
4898 | opacity: 0.9; | |
4899 | filter: alpha(opacity=90); | |
4900 | } | |
4901 | ||
4902 | .carousel-caption { | |
4903 | position: absolute; | |
4904 | right: 0; | |
4905 | bottom: 0; | |
4906 | left: 0; | |
4907 | padding: 10px 15px 5px; | |
4908 | background: #333333; | |
4909 | background: rgba(0, 0, 0, 0.75); | |
4910 | } | |
4911 | ||
4912 | .carousel-caption h4, | |
4913 | .carousel-caption p { | |
4914 | color: #ffffff; | |
4915 | } | |
4916 | ||
4917 | .hero-unit { | |
4918 | padding: 60px; | |
4919 | margin-bottom: 30px; | |
4920 | background-color: #eeeeee; | |
4921 | -webkit-border-radius: 6px; | |
4922 | -moz-border-radius: 6px; | |
4923 | border-radius: 6px; | |
4924 | } | |
4925 | ||
4926 | .hero-unit h1 { | |
4927 | margin-bottom: 0; | |
4928 | font-size: 60px; | |
4929 | line-height: 1; | |
4930 | letter-spacing: -1px; | |
4931 | color: inherit; | |
4932 | } | |
4933 | ||
4934 | .hero-unit p { | |
4935 | font-size: 18px; | |
4936 | font-weight: 200; | |
4937 | line-height: 27px; | |
4938 | color: inherit; | |
4939 | } | |
4940 | ||
4941 | .pull-right { | |
4942 | float: right; | |
4943 | } | |
4944 | ||
4945 | .pull-left { | |
4946 | float: left; | |
4947 | } | |
4948 | ||
4949 | .hide { | |
4950 | display: none; | |
4951 | } | |
4952 | ||
4953 | .show { | |
4954 | display: block; | |
4955 | } | |
4956 | ||
4957 | .invisible { | |
4958 | visibility: hidden; | |
4959 | } |
0 | /* =================================================== | |
1 | * bootstrap-transition.js v2.0.3 | |
2 | * http://twitter.github.com/bootstrap/javascript.html#transitions | |
3 | * =================================================== | |
4 | * Copyright 2012 Twitter, Inc. | |
5 | * | |
6 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | * you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, software | |
13 | * distributed under the License is distributed on an "AS IS" BASIS, | |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | * See the License for the specific language governing permissions and | |
16 | * limitations under the License. | |
17 | * ========================================================== */ | |
18 | ||
19 | ||
20 | !function ($) { | |
21 | ||
22 | $(function () { | |
23 | ||
24 | "use strict"; // jshint ;_; | |
25 | ||
26 | ||
27 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) | |
28 | * ======================================================= */ | |
29 | ||
30 | $.support.transition = (function () { | |
31 | ||
32 | var transitionEnd = (function () { | |
33 | ||
34 | var el = document.createElement('bootstrap') | |
35 | , transEndEventNames = { | |
36 | 'WebkitTransition' : 'webkitTransitionEnd' | |
37 | , 'MozTransition' : 'transitionend' | |
38 | , 'OTransition' : 'oTransitionEnd' | |
39 | //, 'msTransition' : 'MSTransitionEnd' | |
40 | , 'transition' : 'transitionend' | |
41 | } | |
42 | , name | |
43 | ||
44 | for (name in transEndEventNames){ | |
45 | if (el.style[name] !== undefined) { | |
46 | return transEndEventNames[name] | |
47 | } | |
48 | } | |
49 | ||
50 | }()) | |
51 | ||
52 | return transitionEnd && { | |
53 | end: transitionEnd | |
54 | } | |
55 | ||
56 | })() | |
57 | ||
58 | }) | |
59 | ||
60 | }(window.jQuery);/* ========================================================== | |
61 | * bootstrap-alert.js v2.0.3 | |
62 | * http://twitter.github.com/bootstrap/javascript.html#alerts | |
63 | * ========================================================== | |
64 | * Copyright 2012 Twitter, Inc. | |
65 | * | |
66 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
67 | * you may not use this file except in compliance with the License. | |
68 | * You may obtain a copy of the License at | |
69 | * | |
70 | * http://www.apache.org/licenses/LICENSE-2.0 | |
71 | * | |
72 | * Unless required by applicable law or agreed to in writing, software | |
73 | * distributed under the License is distributed on an "AS IS" BASIS, | |
74 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
75 | * See the License for the specific language governing permissions and | |
76 | * limitations under the License. | |
77 | * ========================================================== */ | |
78 | ||
79 | ||
80 | !function ($) { | |
81 | ||
82 | "use strict"; // jshint ;_; | |
83 | ||
84 | ||
85 | /* ALERT CLASS DEFINITION | |
86 | * ====================== */ | |
87 | ||
88 | var dismiss = '[data-dismiss="alert"]' | |
89 | , Alert = function (el) { | |
90 | $(el).on('click', dismiss, this.close) | |
91 | } | |
92 | ||
93 | Alert.prototype.close = function (e) { | |
94 | var $this = $(this) | |
95 | , selector = $this.attr('data-target') | |
96 | , $parent | |
97 | ||
98 | if (!selector) { | |
99 | selector = $this.attr('href') | |
100 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 | |
101 | } | |
102 | ||
103 | $parent = $(selector) | |
104 | ||
105 | e && e.preventDefault() | |
106 | ||
107 | $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) | |
108 | ||
109 | $parent.trigger(e = $.Event('close')) | |
110 | ||
111 | if (e.isDefaultPrevented()) return | |
112 | ||
113 | $parent.removeClass('in') | |
114 | ||
115 | function removeElement() { | |
116 | $parent | |
117 | .trigger('closed') | |
118 | .remove() | |
119 | } | |
120 | ||
121 | $.support.transition && $parent.hasClass('fade') ? | |
122 | $parent.on($.support.transition.end, removeElement) : | |
123 | removeElement() | |
124 | } | |
125 | ||
126 | ||
127 | /* ALERT PLUGIN DEFINITION | |
128 | * ======================= */ | |
129 | ||
130 | $.fn.alert = function (option) { | |
131 | return this.each(function () { | |
132 | var $this = $(this) | |
133 | , data = $this.data('alert') | |
134 | if (!data) $this.data('alert', (data = new Alert(this))) | |
135 | if (typeof option == 'string') data[option].call($this) | |
136 | }) | |
137 | } | |
138 | ||
139 | $.fn.alert.Constructor = Alert | |
140 | ||
141 | ||
142 | /* ALERT DATA-API | |
143 | * ============== */ | |
144 | ||
145 | $(function () { | |
146 | $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) | |
147 | }) | |
148 | ||
149 | }(window.jQuery);/* ============================================================ | |
150 | * bootstrap-button.js v2.0.3 | |
151 | * http://twitter.github.com/bootstrap/javascript.html#buttons | |
152 | * ============================================================ | |
153 | * Copyright 2012 Twitter, Inc. | |
154 | * | |
155 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
156 | * you may not use this file except in compliance with the License. | |
157 | * You may obtain a copy of the License at | |
158 | * | |
159 | * http://www.apache.org/licenses/LICENSE-2.0 | |
160 | * | |
161 | * Unless required by applicable law or agreed to in writing, software | |
162 | * distributed under the License is distributed on an "AS IS" BASIS, | |
163 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
164 | * See the License for the specific language governing permissions and | |
165 | * limitations under the License. | |
166 | * ============================================================ */ | |
167 | ||
168 | ||
169 | !function ($) { | |
170 | ||
171 | "use strict"; // jshint ;_; | |
172 | ||
173 | ||
174 | /* BUTTON PUBLIC CLASS DEFINITION | |
175 | * ============================== */ | |
176 | ||
177 | var Button = function (element, options) { | |
178 | this.$element = $(element) | |
179 | this.options = $.extend({}, $.fn.button.defaults, options) | |
180 | } | |
181 | ||
182 | Button.prototype.setState = function (state) { | |
183 | var d = 'disabled' | |
184 | , $el = this.$element | |
185 | , data = $el.data() | |
186 | , val = $el.is('input') ? 'val' : 'html' | |
187 | ||
188 | state = state + 'Text' | |
189 | data.resetText || $el.data('resetText', $el[val]()) | |
190 | ||
191 | $el[val](data[state] || this.options[state]) | |
192 | ||
193 | // push to event loop to allow forms to submit | |
194 | setTimeout(function () { | |
195 | state == 'loadingText' ? | |
196 | $el.addClass(d).attr(d, d) : | |
197 | $el.removeClass(d).removeAttr(d) | |
198 | }, 0) | |
199 | } | |
200 | ||
201 | Button.prototype.toggle = function () { | |
202 | var $parent = this.$element.parent('[data-toggle="buttons-radio"]') | |
203 | ||
204 | $parent && $parent | |
205 | .find('.active') | |
206 | .removeClass('active') | |
207 | ||
208 | this.$element.toggleClass('active') | |
209 | } | |
210 | ||
211 | ||
212 | /* BUTTON PLUGIN DEFINITION | |
213 | * ======================== */ | |
214 | ||
215 | $.fn.button = function (option) { | |
216 | return this.each(function () { | |
217 | var $this = $(this) | |
218 | , data = $this.data('button') | |
219 | , options = typeof option == 'object' && option | |
220 | if (!data) $this.data('button', (data = new Button(this, options))) | |
221 | if (option == 'toggle') data.toggle() | |
222 | else if (option) data.setState(option) | |
223 | }) | |
224 | } | |
225 | ||
226 | $.fn.button.defaults = { | |
227 | loadingText: 'loading...' | |
228 | } | |
229 | ||
230 | $.fn.button.Constructor = Button | |
231 | ||
232 | ||
233 | /* BUTTON DATA-API | |
234 | * =============== */ | |
235 | ||
236 | $(function () { | |
237 | $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { | |
238 | var $btn = $(e.target) | |
239 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') | |
240 | $btn.button('toggle') | |
241 | }) | |
242 | }) | |
243 | ||
244 | }(window.jQuery);/* ========================================================== | |
245 | * bootstrap-carousel.js v2.0.3 | |
246 | * http://twitter.github.com/bootstrap/javascript.html#carousel | |
247 | * ========================================================== | |
248 | * Copyright 2012 Twitter, Inc. | |
249 | * | |
250 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
251 | * you may not use this file except in compliance with the License. | |
252 | * You may obtain a copy of the License at | |
253 | * | |
254 | * http://www.apache.org/licenses/LICENSE-2.0 | |
255 | * | |
256 | * Unless required by applicable law or agreed to in writing, software | |
257 | * distributed under the License is distributed on an "AS IS" BASIS, | |
258 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
259 | * See the License for the specific language governing permissions and | |
260 | * limitations under the License. | |
261 | * ========================================================== */ | |
262 | ||
263 | ||
264 | !function ($) { | |
265 | ||
266 | "use strict"; // jshint ;_; | |
267 | ||
268 | ||
269 | /* CAROUSEL CLASS DEFINITION | |
270 | * ========================= */ | |
271 | ||
272 | var Carousel = function (element, options) { | |
273 | this.$element = $(element) | |
274 | this.options = options | |
275 | this.options.slide && this.slide(this.options.slide) | |
276 | this.options.pause == 'hover' && this.$element | |
277 | .on('mouseenter', $.proxy(this.pause, this)) | |
278 | .on('mouseleave', $.proxy(this.cycle, this)) | |
279 | } | |
280 | ||
281 | Carousel.prototype = { | |
282 | ||
283 | cycle: function (e) { | |
284 | if (!e) this.paused = false | |
285 | this.options.interval | |
286 | && !this.paused | |
287 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) | |
288 | return this | |
289 | } | |
290 | ||
291 | , to: function (pos) { | |
292 | var $active = this.$element.find('.active') | |
293 | , children = $active.parent().children() | |
294 | , activePos = children.index($active) | |
295 | , that = this | |
296 | ||
297 | if (pos > (children.length - 1) || pos < 0) return | |
298 | ||
299 | if (this.sliding) { | |
300 | return this.$element.one('slid', function () { | |
301 | that.to(pos) | |
302 | }) | |
303 | } | |
304 | ||
305 | if (activePos == pos) { | |
306 | return this.pause().cycle() | |
307 | } | |
308 | ||
309 | return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) | |
310 | } | |
311 | ||
312 | , pause: function (e) { | |
313 | if (!e) this.paused = true | |
314 | clearInterval(this.interval) | |
315 | this.interval = null | |
316 | return this | |
317 | } | |
318 | ||
319 | , next: function () { | |
320 | if (this.sliding) return | |
321 | return this.slide('next') | |
322 | } | |
323 | ||
324 | , prev: function () { | |
325 | if (this.sliding) return | |
326 | return this.slide('prev') | |
327 | } | |
328 | ||
329 | , slide: function (type, next) { | |
330 | var $active = this.$element.find('.active') | |
331 | , $next = next || $active[type]() | |
332 | , isCycling = this.interval | |
333 | , direction = type == 'next' ? 'left' : 'right' | |
334 | , fallback = type == 'next' ? 'first' : 'last' | |
335 | , that = this | |
336 | , e = $.Event('slide') | |
337 | ||
338 | this.sliding = true | |
339 | ||
340 | isCycling && this.pause() | |
341 | ||
342 | $next = $next.length ? $next : this.$element.find('.item')[fallback]() | |
343 | ||
344 | if ($next.hasClass('active')) return | |
345 | ||
346 | if ($.support.transition && this.$element.hasClass('slide')) { | |
347 | this.$element.trigger(e) | |
348 | if (e.isDefaultPrevented()) return | |
349 | $next.addClass(type) | |
350 | $next[0].offsetWidth // force reflow | |
351 | $active.addClass(direction) | |
352 | $next.addClass(direction) | |
353 | this.$element.one($.support.transition.end, function () { | |
354 | $next.removeClass([type, direction].join(' ')).addClass('active') | |
355 | $active.removeClass(['active', direction].join(' ')) | |
356 | that.sliding = false | |
357 | setTimeout(function () { that.$element.trigger('slid') }, 0) | |
358 | }) | |
359 | } else { | |
360 | this.$element.trigger(e) | |
361 | if (e.isDefaultPrevented()) return | |
362 | $active.removeClass('active') | |
363 | $next.addClass('active') | |
364 | this.sliding = false | |
365 | this.$element.trigger('slid') | |
366 | } | |
367 | ||
368 | isCycling && this.cycle() | |
369 | ||
370 | return this | |
371 | } | |
372 | ||
373 | } | |
374 | ||
375 | ||
376 | /* CAROUSEL PLUGIN DEFINITION | |
377 | * ========================== */ | |
378 | ||
379 | $.fn.carousel = function (option) { | |
380 | return this.each(function () { | |
381 | var $this = $(this) | |
382 | , data = $this.data('carousel') | |
383 | , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) | |
384 | if (!data) $this.data('carousel', (data = new Carousel(this, options))) | |
385 | if (typeof option == 'number') data.to(option) | |
386 | else if (typeof option == 'string' || (option = options.slide)) data[option]() | |
387 | else if (options.interval) data.cycle() | |
388 | }) | |
389 | } | |
390 | ||
391 | $.fn.carousel.defaults = { | |
392 | interval: 5000 | |
393 | , pause: 'hover' | |
394 | } | |
395 | ||
396 | $.fn.carousel.Constructor = Carousel | |
397 | ||
398 | ||
399 | /* CAROUSEL DATA-API | |
400 | * ================= */ | |
401 | ||
402 | $(function () { | |
403 | $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { | |
404 | var $this = $(this), href | |
405 | , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 | |
406 | , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) | |
407 | $target.carousel(options) | |
408 | e.preventDefault() | |
409 | }) | |
410 | }) | |
411 | ||
412 | }(window.jQuery);/* ============================================================= | |
413 | * bootstrap-collapse.js v2.0.3 | |
414 | * http://twitter.github.com/bootstrap/javascript.html#collapse | |
415 | * ============================================================= | |
416 | * Copyright 2012 Twitter, Inc. | |
417 | * | |
418 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
419 | * you may not use this file except in compliance with the License. | |
420 | * You may obtain a copy of the License at | |
421 | * | |
422 | * http://www.apache.org/licenses/LICENSE-2.0 | |
423 | * | |
424 | * Unless required by applicable law or agreed to in writing, software | |
425 | * distributed under the License is distributed on an "AS IS" BASIS, | |
426 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
427 | * See the License for the specific language governing permissions and | |
428 | * limitations under the License. | |
429 | * ============================================================ */ | |
430 | ||
431 | ||
432 | !function ($) { | |
433 | ||
434 | "use strict"; // jshint ;_; | |
435 | ||
436 | ||
437 | /* COLLAPSE PUBLIC CLASS DEFINITION | |
438 | * ================================ */ | |
439 | ||
440 | var Collapse = function (element, options) { | |
441 | this.$element = $(element) | |
442 | this.options = $.extend({}, $.fn.collapse.defaults, options) | |
443 | ||
444 | if (this.options.parent) { | |
445 | this.$parent = $(this.options.parent) | |
446 | } | |
447 | ||
448 | this.options.toggle && this.toggle() | |
449 | } | |
450 | ||
451 | Collapse.prototype = { | |
452 | ||
453 | constructor: Collapse | |
454 | ||
455 | , dimension: function () { | |
456 | var hasWidth = this.$element.hasClass('width') | |
457 | return hasWidth ? 'width' : 'height' | |
458 | } | |
459 | ||
460 | , show: function () { | |
461 | var dimension | |
462 | , scroll | |
463 | , actives | |
464 | , hasData | |
465 | ||
466 | if (this.transitioning) return | |
467 | ||
468 | dimension = this.dimension() | |
469 | scroll = $.camelCase(['scroll', dimension].join('-')) | |
470 | actives = this.$parent && this.$parent.find('> .accordion-group > .in') | |
471 | ||
472 | if (actives && actives.length) { | |
473 | hasData = actives.data('collapse') | |
474 | if (hasData && hasData.transitioning) return | |
475 | actives.collapse('hide') | |
476 | hasData || actives.data('collapse', null) | |
477 | } | |
478 | ||
479 | this.$element[dimension](0) | |
480 | this.transition('addClass', $.Event('show'), 'shown') | |
481 | this.$element[dimension](this.$element[0][scroll]) | |
482 | } | |
483 | ||
484 | , hide: function () { | |
485 | var dimension | |
486 | if (this.transitioning) return | |
487 | dimension = this.dimension() | |
488 | this.reset(this.$element[dimension]()) | |
489 | this.transition('removeClass', $.Event('hide'), 'hidden') | |
490 | this.$element[dimension](0) | |
491 | } | |
492 | ||
493 | , reset: function (size) { | |
494 | var dimension = this.dimension() | |
495 | ||
496 | this.$element | |
497 | .removeClass('collapse') | |
498 | [dimension](size || 'auto') | |
499 | [0].offsetWidth | |
500 | ||
501 | this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') | |
502 | ||
503 | return this | |
504 | } | |
505 | ||
506 | , transition: function (method, startEvent, completeEvent) { | |
507 | var that = this | |
508 | , complete = function () { | |
509 | if (startEvent.type == 'show') that.reset() | |
510 | that.transitioning = 0 | |
511 | that.$element.trigger(completeEvent) | |
512 | } | |
513 | ||
514 | this.$element.trigger(startEvent) | |
515 | ||
516 | if (startEvent.isDefaultPrevented()) return | |
517 | ||
518 | this.transitioning = 1 | |
519 | ||
520 | this.$element[method]('in') | |
521 | ||
522 | $.support.transition && this.$element.hasClass('collapse') ? | |
523 | this.$element.one($.support.transition.end, complete) : | |
524 | complete() | |
525 | } | |
526 | ||
527 | , toggle: function () { | |
528 | this[this.$element.hasClass('in') ? 'hide' : 'show']() | |
529 | } | |
530 | ||
531 | } | |
532 | ||
533 | ||
534 | /* COLLAPSIBLE PLUGIN DEFINITION | |
535 | * ============================== */ | |
536 | ||
537 | $.fn.collapse = function (option) { | |
538 | return this.each(function () { | |
539 | var $this = $(this) | |
540 | , data = $this.data('collapse') | |
541 | , options = typeof option == 'object' && option | |
542 | if (!data) $this.data('collapse', (data = new Collapse(this, options))) | |
543 | if (typeof option == 'string') data[option]() | |
544 | }) | |
545 | } | |
546 | ||
547 | $.fn.collapse.defaults = { | |
548 | toggle: true | |
549 | } | |
550 | ||
551 | $.fn.collapse.Constructor = Collapse | |
552 | ||
553 | ||
554 | /* COLLAPSIBLE DATA-API | |
555 | * ==================== */ | |
556 | ||
557 | $(function () { | |
558 | $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { | |
559 | var $this = $(this), href | |
560 | , target = $this.attr('data-target') | |
561 | || e.preventDefault() | |
562 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 | |
563 | , option = $(target).data('collapse') ? 'toggle' : $this.data() | |
564 | $(target).collapse(option) | |
565 | }) | |
566 | }) | |
567 | ||
568 | }(window.jQuery);/* ============================================================ | |
569 | * bootstrap-dropdown.js v2.0.3 | |
570 | * http://twitter.github.com/bootstrap/javascript.html#dropdowns | |
571 | * ============================================================ | |
572 | * Copyright 2012 Twitter, Inc. | |
573 | * | |
574 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
575 | * you may not use this file except in compliance with the License. | |
576 | * You may obtain a copy of the License at | |
577 | * | |
578 | * http://www.apache.org/licenses/LICENSE-2.0 | |
579 | * | |
580 | * Unless required by applicable law or agreed to in writing, software | |
581 | * distributed under the License is distributed on an "AS IS" BASIS, | |
582 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
583 | * See the License for the specific language governing permissions and | |
584 | * limitations under the License. | |
585 | * ============================================================ */ | |
586 | ||
587 | ||
588 | !function ($) { | |
589 | ||
590 | "use strict"; // jshint ;_; | |
591 | ||
592 | ||
593 | /* DROPDOWN CLASS DEFINITION | |
594 | * ========================= */ | |
595 | ||
596 | var toggle = '[data-toggle="dropdown"]' | |
597 | , Dropdown = function (element) { | |
598 | var $el = $(element).on('click.dropdown.data-api', this.toggle) | |
599 | $('html').on('click.dropdown.data-api', function () { | |
600 | $el.parent().removeClass('open') | |
601 | }) | |
602 | } | |
603 | ||
604 | Dropdown.prototype = { | |
605 | ||
606 | constructor: Dropdown | |
607 | ||
608 | , toggle: function (e) { | |
609 | var $this = $(this) | |
610 | , $parent | |
611 | , selector | |
612 | , isActive | |
613 | ||
614 | if ($this.is('.disabled, :disabled')) return | |
615 | ||
616 | selector = $this.attr('data-target') | |
617 | ||
618 | if (!selector) { | |
619 | selector = $this.attr('href') | |
620 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 | |
621 | } | |
622 | ||
623 | $parent = $(selector) | |
624 | $parent.length || ($parent = $this.parent()) | |
625 | ||
626 | isActive = $parent.hasClass('open') | |
627 | ||
628 | clearMenus() | |
629 | ||
630 | if (!isActive) $parent.toggleClass('open') | |
631 | ||
632 | return false | |
633 | } | |
634 | ||
635 | } | |
636 | ||
637 | function clearMenus() { | |
638 | $(toggle).parent().removeClass('open') | |
639 | } | |
640 | ||
641 | ||
642 | /* DROPDOWN PLUGIN DEFINITION | |
643 | * ========================== */ | |
644 | ||
645 | $.fn.dropdown = function (option) { | |
646 | return this.each(function () { | |
647 | var $this = $(this) | |
648 | , data = $this.data('dropdown') | |
649 | if (!data) $this.data('dropdown', (data = new Dropdown(this))) | |
650 | if (typeof option == 'string') data[option].call($this) | |
651 | }) | |
652 | } | |
653 | ||
654 | $.fn.dropdown.Constructor = Dropdown | |
655 | ||
656 | ||
657 | /* APPLY TO STANDARD DROPDOWN ELEMENTS | |
658 | * =================================== */ | |
659 | ||
660 | $(function () { | |
661 | $('html').on('click.dropdown.data-api', clearMenus) | |
662 | $('body') | |
663 | .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() }) | |
664 | .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) | |
665 | }) | |
666 | ||
667 | }(window.jQuery);/* ========================================================= | |
668 | * bootstrap-modal.js v2.0.3 | |
669 | * http://twitter.github.com/bootstrap/javascript.html#modals | |
670 | * ========================================================= | |
671 | * Copyright 2012 Twitter, Inc. | |
672 | * | |
673 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
674 | * you may not use this file except in compliance with the License. | |
675 | * You may obtain a copy of the License at | |
676 | * | |
677 | * http://www.apache.org/licenses/LICENSE-2.0 | |
678 | * | |
679 | * Unless required by applicable law or agreed to in writing, software | |
680 | * distributed under the License is distributed on an "AS IS" BASIS, | |
681 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
682 | * See the License for the specific language governing permissions and | |
683 | * limitations under the License. | |
684 | * ========================================================= */ | |
685 | ||
686 | ||
687 | !function ($) { | |
688 | ||
689 | "use strict"; // jshint ;_; | |
690 | ||
691 | ||
692 | /* MODAL CLASS DEFINITION | |
693 | * ====================== */ | |
694 | ||
695 | var Modal = function (content, options) { | |
696 | this.options = options | |
697 | this.$element = $(content) | |
698 | .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) | |
699 | } | |
700 | ||
701 | Modal.prototype = { | |
702 | ||
703 | constructor: Modal | |
704 | ||
705 | , toggle: function () { | |
706 | return this[!this.isShown ? 'show' : 'hide']() | |
707 | } | |
708 | ||
709 | , show: function () { | |
710 | var that = this | |
711 | , e = $.Event('show') | |
712 | ||
713 | this.$element.trigger(e) | |
714 | ||
715 | if (this.isShown || e.isDefaultPrevented()) return | |
716 | ||
717 | $('body').addClass('modal-open') | |
718 | ||
719 | this.isShown = true | |
720 | ||
721 | escape.call(this) | |
722 | backdrop.call(this, function () { | |
723 | var transition = $.support.transition && that.$element.hasClass('fade') | |
724 | ||
725 | if (!that.$element.parent().length) { | |
726 | that.$element.appendTo(document.body) //don't move modals dom position | |
727 | } | |
728 | ||
729 | that.$element | |
730 | .show() | |
731 | ||
732 | if (transition) { | |
733 | that.$element[0].offsetWidth // force reflow | |
734 | } | |
735 | ||
736 | that.$element.addClass('in') | |
737 | ||
738 | transition ? | |
739 | that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : | |
740 | that.$element.trigger('shown') | |
741 | ||
742 | }) | |
743 | } | |
744 | ||
745 | , hide: function (e) { | |
746 | e && e.preventDefault() | |
747 | ||
748 | var that = this | |
749 | ||
750 | e = $.Event('hide') | |
751 | ||
752 | this.$element.trigger(e) | |
753 | ||
754 | if (!this.isShown || e.isDefaultPrevented()) return | |
755 | ||
756 | this.isShown = false | |
757 | ||
758 | $('body').removeClass('modal-open') | |
759 | ||
760 | escape.call(this) | |
761 | ||
762 | this.$element.removeClass('in') | |
763 | ||
764 | $.support.transition && this.$element.hasClass('fade') ? | |
765 | hideWithTransition.call(this) : | |
766 | hideModal.call(this) | |
767 | } | |
768 | ||
769 | } | |
770 | ||
771 | ||
772 | /* MODAL PRIVATE METHODS | |
773 | * ===================== */ | |
774 | ||
775 | function hideWithTransition() { | |
776 | var that = this | |
777 | , timeout = setTimeout(function () { | |
778 | that.$element.off($.support.transition.end) | |
779 | hideModal.call(that) | |
780 | }, 500) | |
781 | ||
782 | this.$element.one($.support.transition.end, function () { | |
783 | clearTimeout(timeout) | |
784 | hideModal.call(that) | |
785 | }) | |
786 | } | |
787 | ||
788 | function hideModal(that) { | |
789 | this.$element | |
790 | .hide() | |
791 | .trigger('hidden') | |
792 | ||
793 | backdrop.call(this) | |
794 | } | |
795 | ||
796 | function backdrop(callback) { | |
797 | var that = this | |
798 | , animate = this.$element.hasClass('fade') ? 'fade' : '' | |
799 | ||
800 | if (this.isShown && this.options.backdrop) { | |
801 | var doAnimate = $.support.transition && animate | |
802 | ||
803 | this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />') | |
804 | .appendTo(document.body) | |
805 | ||
806 | if (this.options.backdrop != 'static') { | |
807 | this.$backdrop.click($.proxy(this.hide, this)) | |
808 | } | |
809 | ||
810 | if (doAnimate) this.$backdrop[0].offsetWidth // force reflow | |
811 | ||
812 | this.$backdrop.addClass('in') | |
813 | ||
814 | doAnimate ? | |
815 | this.$backdrop.one($.support.transition.end, callback) : | |
816 | callback() | |
817 | ||
818 | } else if (!this.isShown && this.$backdrop) { | |
819 | this.$backdrop.removeClass('in') | |
820 | ||
821 | $.support.transition && this.$element.hasClass('fade')? | |
822 | this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) : | |
823 | removeBackdrop.call(this) | |
824 | ||
825 | } else if (callback) { | |
826 | callback() | |
827 | } | |
828 | } | |
829 | ||
830 | function removeBackdrop() { | |
831 | this.$backdrop.remove() | |
832 | this.$backdrop = null | |
833 | } | |
834 | ||
835 | function escape() { | |
836 | var that = this | |
837 | if (this.isShown && this.options.keyboard) { | |
838 | $(document).on('keyup.dismiss.modal', function ( e ) { | |
839 | e.which == 27 && that.hide() | |
840 | }) | |
841 | } else if (!this.isShown) { | |
842 | $(document).off('keyup.dismiss.modal') | |
843 | } | |
844 | } | |
845 | ||
846 | ||
847 | /* MODAL PLUGIN DEFINITION | |
848 | * ======================= */ | |
849 | ||
850 | $.fn.modal = function (option) { | |
851 | return this.each(function () { | |
852 | var $this = $(this) | |
853 | , data = $this.data('modal') | |
854 | , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option) | |
855 | if (!data) $this.data('modal', (data = new Modal(this, options))) | |
856 | if (typeof option == 'string') data[option]() | |
857 | else if (options.show) data.show() | |
858 | }) | |
859 | } | |
860 | ||
861 | $.fn.modal.defaults = { | |
862 | backdrop: true | |
863 | , keyboard: true | |
864 | , show: true | |
865 | } | |
866 | ||
867 | $.fn.modal.Constructor = Modal | |
868 | ||
869 | ||
870 | /* MODAL DATA-API | |
871 | * ============== */ | |
872 | ||
873 | $(function () { | |
874 | $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) { | |
875 | var $this = $(this), href | |
876 | , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 | |
877 | , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data()) | |
878 | ||
879 | e.preventDefault() | |
880 | $target.modal(option) | |
881 | }) | |
882 | }) | |
883 | ||
884 | }(window.jQuery);/* =========================================================== | |
885 | * bootstrap-tooltip.js v2.0.3 | |
886 | * http://twitter.github.com/bootstrap/javascript.html#tooltips | |
887 | * Inspired by the original jQuery.tipsy by Jason Frame | |
888 | * =========================================================== | |
889 | * Copyright 2012 Twitter, Inc. | |
890 | * | |
891 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
892 | * you may not use this file except in compliance with the License. | |
893 | * You may obtain a copy of the License at | |
894 | * | |
895 | * http://www.apache.org/licenses/LICENSE-2.0 | |
896 | * | |
897 | * Unless required by applicable law or agreed to in writing, software | |
898 | * distributed under the License is distributed on an "AS IS" BASIS, | |
899 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
900 | * See the License for the specific language governing permissions and | |
901 | * limitations under the License. | |
902 | * ========================================================== */ | |
903 | ||
904 | ||
905 | !function ($) { | |
906 | ||
907 | "use strict"; // jshint ;_; | |
908 | ||
909 | ||
910 | /* TOOLTIP PUBLIC CLASS DEFINITION | |
911 | * =============================== */ | |
912 | ||
913 | var Tooltip = function (element, options) { | |
914 | this.init('tooltip', element, options) | |
915 | } | |
916 | ||
917 | Tooltip.prototype = { | |
918 | ||
919 | constructor: Tooltip | |
920 | ||
921 | , init: function (type, element, options) { | |
922 | var eventIn | |
923 | , eventOut | |
924 | ||
925 | this.type = type | |
926 | this.$element = $(element) | |
927 | this.options = this.getOptions(options) | |
928 | this.enabled = true | |
929 | ||
930 | if (this.options.trigger != 'manual') { | |
931 | eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' | |
932 | eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' | |
933 | this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this)) | |
934 | this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this)) | |
935 | } | |
936 | ||
937 | this.options.selector ? | |
938 | (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : | |
939 | this.fixTitle() | |
940 | } | |
941 | ||
942 | , getOptions: function (options) { | |
943 | options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) | |
944 | ||
945 | if (options.delay && typeof options.delay == 'number') { | |
946 | options.delay = { | |
947 | show: options.delay | |
948 | , hide: options.delay | |
949 | } | |
950 | } | |
951 | ||
952 | return options | |
953 | } | |
954 | ||
955 | , enter: function (e) { | |
956 | var self = $(e.currentTarget)[this.type](this._options).data(this.type) | |
957 | ||
958 | if (!self.options.delay || !self.options.delay.show) return self.show() | |
959 | ||
960 | clearTimeout(this.timeout) | |
961 | self.hoverState = 'in' | |
962 | this.timeout = setTimeout(function() { | |
963 | if (self.hoverState == 'in') self.show() | |
964 | }, self.options.delay.show) | |
965 | } | |
966 | ||
967 | , leave: function (e) { | |
968 | var self = $(e.currentTarget)[this.type](this._options).data(this.type) | |
969 | ||
970 | if (!self.options.delay || !self.options.delay.hide) return self.hide() | |
971 | ||
972 | clearTimeout(this.timeout) | |
973 | self.hoverState = 'out' | |
974 | this.timeout = setTimeout(function() { | |
975 | if (self.hoverState == 'out') self.hide() | |
976 | }, self.options.delay.hide) | |
977 | } | |
978 | ||
979 | , show: function () { | |
980 | var $tip | |
981 | , inside | |
982 | , pos | |
983 | , actualWidth | |
984 | , actualHeight | |
985 | , placement | |
986 | , tp | |
987 | ||
988 | if (this.hasContent() && this.enabled) { | |
989 | $tip = this.tip() | |
990 | this.setContent() | |
991 | ||
992 | if (this.options.animation) { | |
993 | $tip.addClass('fade') | |
994 | } | |
995 | ||
996 | placement = typeof this.options.placement == 'function' ? | |
997 | this.options.placement.call(this, $tip[0], this.$element[0]) : | |
998 | this.options.placement | |
999 | ||
1000 | inside = /in/.test(placement) | |
1001 | ||
1002 | $tip | |
1003 | .remove() | |
1004 | .css({ top: 0, left: 0, display: 'block' }) | |
1005 | .appendTo(inside ? this.$element : document.body) | |
1006 | ||
1007 | pos = this.getPosition(inside) | |
1008 | ||
1009 | actualWidth = $tip[0].offsetWidth | |
1010 | actualHeight = $tip[0].offsetHeight | |
1011 | ||
1012 | switch (inside ? placement.split(' ')[1] : placement) { | |
1013 | case 'bottom': | |
1014 | tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} | |
1015 | break | |
1016 | case 'top': | |
1017 | tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} | |
1018 | break | |
1019 | case 'left': | |
1020 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} | |
1021 | break | |
1022 | case 'right': | |
1023 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} | |
1024 | break | |
1025 | } | |
1026 | ||
1027 | $tip | |
1028 | .css(tp) | |
1029 | .addClass(placement) | |
1030 | .addClass('in') | |
1031 | } | |
1032 | } | |
1033 | ||
1034 | , isHTML: function(text) { | |
1035 | // html string detection logic adapted from jQuery | |
1036 | return typeof text != 'string' | |
1037 | || ( text.charAt(0) === "<" | |
1038 | && text.charAt( text.length - 1 ) === ">" | |
1039 | && text.length >= 3 | |
1040 | ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text) | |
1041 | } | |
1042 | ||
1043 | , setContent: function () { | |
1044 | var $tip = this.tip() | |
1045 | , title = this.getTitle() | |
1046 | ||
1047 | $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title) | |
1048 | $tip.removeClass('fade in top bottom left right') | |
1049 | } | |
1050 | ||
1051 | , hide: function () { | |
1052 | var that = this | |
1053 | , $tip = this.tip() | |
1054 | ||
1055 | $tip.removeClass('in') | |
1056 | ||
1057 | function removeWithAnimation() { | |
1058 | var timeout = setTimeout(function () { | |
1059 | $tip.off($.support.transition.end).remove() | |
1060 | }, 500) | |
1061 | ||
1062 | $tip.one($.support.transition.end, function () { | |
1063 | clearTimeout(timeout) | |
1064 | $tip.remove() | |
1065 | }) | |
1066 | } | |
1067 | ||
1068 | $.support.transition && this.$tip.hasClass('fade') ? | |
1069 | removeWithAnimation() : | |
1070 | $tip.remove() | |
1071 | } | |
1072 | ||
1073 | , fixTitle: function () { | |
1074 | var $e = this.$element | |
1075 | if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { | |
1076 | $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') | |
1077 | } | |
1078 | } | |
1079 | ||
1080 | , hasContent: function () { | |
1081 | return this.getTitle() | |
1082 | } | |
1083 | ||
1084 | , getPosition: function (inside) { | |
1085 | return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { | |
1086 | width: this.$element[0].offsetWidth | |
1087 | , height: this.$element[0].offsetHeight | |
1088 | }) | |
1089 | } | |
1090 | ||
1091 | , getTitle: function () { | |
1092 | var title | |
1093 | , $e = this.$element | |
1094 | , o = this.options | |
1095 | ||
1096 | title = $e.attr('data-original-title') | |
1097 | || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) | |
1098 | ||
1099 | return title | |
1100 | } | |
1101 | ||
1102 | , tip: function () { | |
1103 | return this.$tip = this.$tip || $(this.options.template) | |
1104 | } | |
1105 | ||
1106 | , validate: function () { | |
1107 | if (!this.$element[0].parentNode) { | |
1108 | this.hide() | |
1109 | this.$element = null | |
1110 | this.options = null | |
1111 | } | |
1112 | } | |
1113 | ||
1114 | , enable: function () { | |
1115 | this.enabled = true | |
1116 | } | |
1117 | ||
1118 | , disable: function () { | |
1119 | this.enabled = false | |
1120 | } | |
1121 | ||
1122 | , toggleEnabled: function () { | |
1123 | this.enabled = !this.enabled | |
1124 | } | |
1125 | ||
1126 | , toggle: function () { | |
1127 | this[this.tip().hasClass('in') ? 'hide' : 'show']() | |
1128 | } | |
1129 | ||
1130 | } | |
1131 | ||
1132 | ||
1133 | /* TOOLTIP PLUGIN DEFINITION | |
1134 | * ========================= */ | |
1135 | ||
1136 | $.fn.tooltip = function ( option ) { | |
1137 | return this.each(function () { | |
1138 | var $this = $(this) | |
1139 | , data = $this.data('tooltip') | |
1140 | , options = typeof option == 'object' && option | |
1141 | if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) | |
1142 | if (typeof option == 'string') data[option]() | |
1143 | }) | |
1144 | } | |
1145 | ||
1146 | $.fn.tooltip.Constructor = Tooltip | |
1147 | ||
1148 | $.fn.tooltip.defaults = { | |
1149 | animation: true | |
1150 | , placement: 'top' | |
1151 | , selector: false | |
1152 | , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>' | |
1153 | , trigger: 'hover' | |
1154 | , title: '' | |
1155 | , delay: 0 | |
1156 | } | |
1157 | ||
1158 | }(window.jQuery);/* =========================================================== | |
1159 | * bootstrap-popover.js v2.0.3 | |
1160 | * http://twitter.github.com/bootstrap/javascript.html#popovers | |
1161 | * =========================================================== | |
1162 | * Copyright 2012 Twitter, Inc. | |
1163 | * | |
1164 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
1165 | * you may not use this file except in compliance with the License. | |
1166 | * You may obtain a copy of the License at | |
1167 | * | |
1168 | * http://www.apache.org/licenses/LICENSE-2.0 | |
1169 | * | |
1170 | * Unless required by applicable law or agreed to in writing, software | |
1171 | * distributed under the License is distributed on an "AS IS" BASIS, | |
1172 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
1173 | * See the License for the specific language governing permissions and | |
1174 | * limitations under the License. | |
1175 | * =========================================================== */ | |
1176 | ||
1177 | ||
1178 | !function ($) { | |
1179 | ||
1180 | "use strict"; // jshint ;_; | |
1181 | ||
1182 | ||
1183 | /* POPOVER PUBLIC CLASS DEFINITION | |
1184 | * =============================== */ | |
1185 | ||
1186 | var Popover = function ( element, options ) { | |
1187 | this.init('popover', element, options) | |
1188 | } | |
1189 | ||
1190 | ||
1191 | /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js | |
1192 | ========================================== */ | |
1193 | ||
1194 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, { | |
1195 | ||
1196 | constructor: Popover | |
1197 | ||
1198 | , setContent: function () { | |
1199 | var $tip = this.tip() | |
1200 | , title = this.getTitle() | |
1201 | , content = this.getContent() | |
1202 | ||
1203 | $tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title) | |
1204 | $tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content) | |
1205 | ||
1206 | $tip.removeClass('fade top bottom left right in') | |
1207 | } | |
1208 | ||
1209 | , hasContent: function () { | |
1210 | return this.getTitle() || this.getContent() | |
1211 | } | |
1212 | ||
1213 | , getContent: function () { | |
1214 | var content | |
1215 | , $e = this.$element | |
1216 | , o = this.options | |
1217 | ||
1218 | content = $e.attr('data-content') | |
1219 | || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content) | |
1220 | ||
1221 | return content | |
1222 | } | |
1223 | ||
1224 | , tip: function () { | |
1225 | if (!this.$tip) { | |
1226 | this.$tip = $(this.options.template) | |
1227 | } | |
1228 | return this.$tip | |
1229 | } | |
1230 | ||
1231 | }) | |
1232 | ||
1233 | ||
1234 | /* POPOVER PLUGIN DEFINITION | |
1235 | * ======================= */ | |
1236 | ||
1237 | $.fn.popover = function (option) { | |
1238 | return this.each(function () { | |
1239 | var $this = $(this) | |
1240 | , data = $this.data('popover') | |
1241 | , options = typeof option == 'object' && option | |
1242 | if (!data) $this.data('popover', (data = new Popover(this, options))) | |
1243 | if (typeof option == 'string') data[option]() | |
1244 | }) | |
1245 | } | |
1246 | ||
1247 | $.fn.popover.Constructor = Popover | |
1248 | ||
1249 | $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, { | |
1250 | placement: 'right' | |
1251 | , content: '' | |
1252 | , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>' | |
1253 | }) | |
1254 | ||
1255 | }(window.jQuery);/* ============================================================= | |
1256 | * bootstrap-scrollspy.js v2.0.3 | |
1257 | * http://twitter.github.com/bootstrap/javascript.html#scrollspy | |
1258 | * ============================================================= | |
1259 | * Copyright 2012 Twitter, Inc. | |
1260 | * | |
1261 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
1262 | * you may not use this file except in compliance with the License. | |
1263 | * You may obtain a copy of the License at | |
1264 | * | |
1265 | * http://www.apache.org/licenses/LICENSE-2.0 | |
1266 | * | |
1267 | * Unless required by applicable law or agreed to in writing, software | |
1268 | * distributed under the License is distributed on an "AS IS" BASIS, | |
1269 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
1270 | * See the License for the specific language governing permissions and | |
1271 | * limitations under the License. | |
1272 | * ============================================================== */ | |
1273 | ||
1274 | ||
1275 | !function ($) { | |
1276 | ||
1277 | "use strict"; // jshint ;_; | |
1278 | ||
1279 | ||
1280 | /* SCROLLSPY CLASS DEFINITION | |
1281 | * ========================== */ | |
1282 | ||
1283 | function ScrollSpy( element, options) { | |
1284 | var process = $.proxy(this.process, this) | |
1285 | , $element = $(element).is('body') ? $(window) : $(element) | |
1286 | , href | |
1287 | this.options = $.extend({}, $.fn.scrollspy.defaults, options) | |
1288 | this.$scrollElement = $element.on('scroll.scroll.data-api', process) | |
1289 | this.selector = (this.options.target | |
1290 | || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 | |
1291 | || '') + ' .nav li > a' | |
1292 | this.$body = $('body') | |
1293 | this.refresh() | |
1294 | this.process() | |
1295 | } | |
1296 | ||
1297 | ScrollSpy.prototype = { | |
1298 | ||
1299 | constructor: ScrollSpy | |
1300 | ||
1301 | , refresh: function () { | |
1302 | var self = this | |
1303 | , $targets | |
1304 | ||
1305 | this.offsets = $([]) | |
1306 | this.targets = $([]) | |
1307 | ||
1308 | $targets = this.$body | |
1309 | .find(this.selector) | |
1310 | .map(function () { | |
1311 | var $el = $(this) | |
1312 | , href = $el.data('target') || $el.attr('href') | |
1313 | , $href = /^#\w/.test(href) && $(href) | |
1314 | return ( $href | |
1315 | && href.length | |
1316 | && [[ $href.position().top, href ]] ) || null | |
1317 | }) | |
1318 | .sort(function (a, b) { return a[0] - b[0] }) | |
1319 | .each(function () { | |
1320 | self.offsets.push(this[0]) | |
1321 | self.targets.push(this[1]) | |
1322 | }) | |
1323 | } | |
1324 | ||
1325 | , process: function () { | |
1326 | var scrollTop = this.$scrollElement.scrollTop() + this.options.offset | |
1327 | , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight | |
1328 | , maxScroll = scrollHeight - this.$scrollElement.height() | |
1329 | , offsets = this.offsets | |
1330 | , targets = this.targets | |
1331 | , activeTarget = this.activeTarget | |
1332 | , i | |
1333 | ||
1334 | if (scrollTop >= maxScroll) { | |
1335 | return activeTarget != (i = targets.last()[0]) | |
1336 | && this.activate ( i ) | |
1337 | } | |
1338 | ||
1339 | for (i = offsets.length; i--;) { | |
1340 | activeTarget != targets[i] | |
1341 | && scrollTop >= offsets[i] | |
1342 | && (!offsets[i + 1] || scrollTop <= offsets[i + 1]) | |
1343 | && this.activate( targets[i] ) | |
1344 | } | |
1345 | } | |
1346 | ||
1347 | , activate: function (target) { | |
1348 | var active | |
1349 | , selector | |
1350 | ||
1351 | this.activeTarget = target | |
1352 | ||
1353 | $(this.selector) | |
1354 | .parent('.active') | |
1355 | .removeClass('active') | |
1356 | ||
1357 | selector = this.selector | |
1358 | + '[data-target="' + target + '"],' | |
1359 | + this.selector + '[href="' + target + '"]' | |
1360 | ||
1361 | active = $(selector) | |
1362 | .parent('li') | |
1363 | .addClass('active') | |
1364 | ||
1365 | if (active.parent('.dropdown-menu')) { | |
1366 | active = active.closest('li.dropdown').addClass('active') | |
1367 | } | |
1368 | ||
1369 | active.trigger('activate') | |
1370 | } | |
1371 | ||
1372 | } | |
1373 | ||
1374 | ||
1375 | /* SCROLLSPY PLUGIN DEFINITION | |
1376 | * =========================== */ | |
1377 | ||
1378 | $.fn.scrollspy = function ( option ) { | |
1379 | return this.each(function () { | |
1380 | var $this = $(this) | |
1381 | , data = $this.data('scrollspy') | |
1382 | , options = typeof option == 'object' && option | |
1383 | if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options))) | |
1384 | if (typeof option == 'string') data[option]() | |
1385 | }) | |
1386 | } | |
1387 | ||
1388 | $.fn.scrollspy.Constructor = ScrollSpy | |
1389 | ||
1390 | $.fn.scrollspy.defaults = { | |
1391 | offset: 10 | |
1392 | } | |
1393 | ||
1394 | ||
1395 | /* SCROLLSPY DATA-API | |
1396 | * ================== */ | |
1397 | ||
1398 | $(function () { | |
1399 | $('[data-spy="scroll"]').each(function () { | |
1400 | var $spy = $(this) | |
1401 | $spy.scrollspy($spy.data()) | |
1402 | }) | |
1403 | }) | |
1404 | ||
1405 | }(window.jQuery);/* ======================================================== | |
1406 | * bootstrap-tab.js v2.0.3 | |
1407 | * http://twitter.github.com/bootstrap/javascript.html#tabs | |
1408 | * ======================================================== | |
1409 | * Copyright 2012 Twitter, Inc. | |
1410 | * | |
1411 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
1412 | * you may not use this file except in compliance with the License. | |
1413 | * You may obtain a copy of the License at | |
1414 | * | |
1415 | * http://www.apache.org/licenses/LICENSE-2.0 | |
1416 | * | |
1417 | * Unless required by applicable law or agreed to in writing, software | |
1418 | * distributed under the License is distributed on an "AS IS" BASIS, | |
1419 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
1420 | * See the License for the specific language governing permissions and | |
1421 | * limitations under the License. | |
1422 | * ======================================================== */ | |
1423 | ||
1424 | ||
1425 | !function ($) { | |
1426 | ||
1427 | "use strict"; // jshint ;_; | |
1428 | ||
1429 | ||
1430 | /* TAB CLASS DEFINITION | |
1431 | * ==================== */ | |
1432 | ||
1433 | var Tab = function ( element ) { | |
1434 | this.element = $(element) | |
1435 | } | |
1436 | ||
1437 | Tab.prototype = { | |
1438 | ||
1439 | constructor: Tab | |
1440 | ||
1441 | , show: function () { | |
1442 | var $this = this.element | |
1443 | , $ul = $this.closest('ul:not(.dropdown-menu)') | |
1444 | , selector = $this.attr('data-target') | |
1445 | , previous | |
1446 | , $target | |
1447 | , e | |
1448 | ||
1449 | if (!selector) { | |
1450 | selector = $this.attr('href') | |
1451 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 | |
1452 | } | |
1453 | ||
1454 | if ( $this.parent('li').hasClass('active') ) return | |
1455 | ||
1456 | previous = $ul.find('.active a').last()[0] | |
1457 | ||
1458 | e = $.Event('show', { | |
1459 | relatedTarget: previous | |
1460 | }) | |
1461 | ||
1462 | $this.trigger(e) | |
1463 | ||
1464 | if (e.isDefaultPrevented()) return | |
1465 | ||
1466 | $target = $(selector) | |
1467 | ||
1468 | this.activate($this.parent('li'), $ul) | |
1469 | this.activate($target, $target.parent(), function () { | |
1470 | $this.trigger({ | |
1471 | type: 'shown' | |
1472 | , relatedTarget: previous | |
1473 | }) | |
1474 | }) | |
1475 | } | |
1476 | ||
1477 | , activate: function ( element, container, callback) { | |
1478 | var $active = container.find('> .active') | |
1479 | , transition = callback | |
1480 | && $.support.transition | |
1481 | && $active.hasClass('fade') | |
1482 | ||
1483 | function next() { | |
1484 | $active | |
1485 | .removeClass('active') | |
1486 | .find('> .dropdown-menu > .active') | |
1487 | .removeClass('active') | |
1488 | ||
1489 | element.addClass('active') | |
1490 | ||
1491 | if (transition) { | |
1492 | element[0].offsetWidth // reflow for transition | |
1493 | element.addClass('in') | |
1494 | } else { | |
1495 | element.removeClass('fade') | |
1496 | } | |
1497 | ||
1498 | if ( element.parent('.dropdown-menu') ) { | |
1499 | element.closest('li.dropdown').addClass('active') | |
1500 | } | |
1501 | ||
1502 | callback && callback() | |
1503 | } | |
1504 | ||
1505 | transition ? | |
1506 | $active.one($.support.transition.end, next) : | |
1507 | next() | |
1508 | ||
1509 | $active.removeClass('in') | |
1510 | } | |
1511 | } | |
1512 | ||
1513 | ||
1514 | /* TAB PLUGIN DEFINITION | |
1515 | * ===================== */ | |
1516 | ||
1517 | $.fn.tab = function ( option ) { | |
1518 | return this.each(function () { | |
1519 | var $this = $(this) | |
1520 | , data = $this.data('tab') | |
1521 | if (!data) $this.data('tab', (data = new Tab(this))) | |
1522 | if (typeof option == 'string') data[option]() | |
1523 | }) | |
1524 | } | |
1525 | ||
1526 | $.fn.tab.Constructor = Tab | |
1527 | ||
1528 | ||
1529 | /* TAB DATA-API | |
1530 | * ============ */ | |
1531 | ||
1532 | $(function () { | |
1533 | $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { | |
1534 | e.preventDefault() | |
1535 | $(this).tab('show') | |
1536 | }) | |
1537 | }) | |
1538 | ||
1539 | }(window.jQuery);/* ============================================================= | |
1540 | * bootstrap-typeahead.js v2.0.3 | |
1541 | * http://twitter.github.com/bootstrap/javascript.html#typeahead | |
1542 | * ============================================================= | |
1543 | * Copyright 2012 Twitter, Inc. | |
1544 | * | |
1545 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
1546 | * you may not use this file except in compliance with the License. | |
1547 | * You may obtain a copy of the License at | |
1548 | * | |
1549 | * http://www.apache.org/licenses/LICENSE-2.0 | |
1550 | * | |
1551 | * Unless required by applicable law or agreed to in writing, software | |
1552 | * distributed under the License is distributed on an "AS IS" BASIS, | |
1553 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
1554 | * See the License for the specific language governing permissions and | |
1555 | * limitations under the License. | |
1556 | * ============================================================ */ | |
1557 | ||
1558 | ||
1559 | !function($){ | |
1560 | ||
1561 | "use strict"; // jshint ;_; | |
1562 | ||
1563 | ||
1564 | /* TYPEAHEAD PUBLIC CLASS DEFINITION | |
1565 | * ================================= */ | |
1566 | ||
1567 | var Typeahead = function (element, options) { | |
1568 | this.$element = $(element) | |
1569 | this.options = $.extend({}, $.fn.typeahead.defaults, options) | |
1570 | this.matcher = this.options.matcher || this.matcher | |
1571 | this.sorter = this.options.sorter || this.sorter | |
1572 | this.highlighter = this.options.highlighter || this.highlighter | |
1573 | this.updater = this.options.updater || this.updater | |
1574 | this.$menu = $(this.options.menu).appendTo('body') | |
1575 | this.source = this.options.source | |
1576 | this.shown = false | |
1577 | this.listen() | |
1578 | } | |
1579 | ||
1580 | Typeahead.prototype = { | |
1581 | ||
1582 | constructor: Typeahead | |
1583 | ||
1584 | , select: function () { | |
1585 | var val = this.$menu.find('.active').attr('data-value') | |
1586 | this.$element | |
1587 | .val(this.updater(val)) | |
1588 | .change() | |
1589 | return this.hide() | |
1590 | } | |
1591 | ||
1592 | , updater: function (item) { | |
1593 | return item | |
1594 | } | |
1595 | ||
1596 | , show: function () { | |
1597 | var pos = $.extend({}, this.$element.offset(), { | |
1598 | height: this.$element[0].offsetHeight | |
1599 | }) | |
1600 | ||
1601 | this.$menu.css({ | |
1602 | top: pos.top + pos.height | |
1603 | , left: pos.left | |
1604 | }) | |
1605 | ||
1606 | this.$menu.show() | |
1607 | this.shown = true | |
1608 | return this | |
1609 | } | |
1610 | ||
1611 | , hide: function () { | |
1612 | this.$menu.hide() | |
1613 | this.shown = false | |
1614 | return this | |
1615 | } | |
1616 | ||
1617 | , lookup: function (event) { | |
1618 | var that = this | |
1619 | , items | |
1620 | , q | |
1621 | ||
1622 | this.query = this.$element.val() | |
1623 | ||
1624 | if (!this.query) { | |
1625 | return this.shown ? this.hide() : this | |
1626 | } | |
1627 | ||
1628 | items = $.grep(this.source, function (item) { | |
1629 | return that.matcher(item) | |
1630 | }) | |
1631 | ||
1632 | items = this.sorter(items) | |
1633 | ||
1634 | if (!items.length) { | |
1635 | return this.shown ? this.hide() : this | |
1636 | } | |
1637 | ||
1638 | return this.render(items.slice(0, this.options.items)).show() | |
1639 | } | |
1640 | ||
1641 | , matcher: function (item) { | |
1642 | return ~item.toLowerCase().indexOf(this.query.toLowerCase()) | |
1643 | } | |
1644 | ||
1645 | , sorter: function (items) { | |
1646 | var beginswith = [] | |
1647 | , caseSensitive = [] | |
1648 | , caseInsensitive = [] | |
1649 | , item | |
1650 | ||
1651 | while (item = items.shift()) { | |
1652 | if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) | |
1653 | else if (~item.indexOf(this.query)) caseSensitive.push(item) | |
1654 | else caseInsensitive.push(item) | |
1655 | } | |
1656 | ||
1657 | return beginswith.concat(caseSensitive, caseInsensitive) | |
1658 | } | |
1659 | ||
1660 | , highlighter: function (item) { | |
1661 | var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&') | |
1662 | return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { | |
1663 | return '<strong>' + match + '</strong>' | |
1664 | }) | |
1665 | } | |
1666 | ||
1667 | , render: function (items) { | |
1668 | var that = this | |
1669 | ||
1670 | items = $(items).map(function (i, item) { | |
1671 | i = $(that.options.item).attr('data-value', item) | |
1672 | i.find('a').html(that.highlighter(item)) | |
1673 | return i[0] | |
1674 | }) | |
1675 | ||
1676 | items.first().addClass('active') | |
1677 | this.$menu.html(items) | |
1678 | return this | |
1679 | } | |
1680 | ||
1681 | , next: function (event) { | |
1682 | var active = this.$menu.find('.active').removeClass('active') | |
1683 | , next = active.next() | |
1684 | ||
1685 | if (!next.length) { | |
1686 | next = $(this.$menu.find('li')[0]) | |
1687 | } | |
1688 | ||
1689 | next.addClass('active') | |
1690 | } | |
1691 | ||
1692 | , prev: function (event) { | |
1693 | var active = this.$menu.find('.active').removeClass('active') | |
1694 | , prev = active.prev() | |
1695 | ||
1696 | if (!prev.length) { | |
1697 | prev = this.$menu.find('li').last() | |
1698 | } | |
1699 | ||
1700 | prev.addClass('active') | |
1701 | } | |
1702 | ||
1703 | , listen: function () { | |
1704 | this.$element | |
1705 | .on('blur', $.proxy(this.blur, this)) | |
1706 | .on('keypress', $.proxy(this.keypress, this)) | |
1707 | .on('keyup', $.proxy(this.keyup, this)) | |
1708 | ||
1709 | if ($.browser.webkit || $.browser.msie) { | |
1710 | this.$element.on('keydown', $.proxy(this.keypress, this)) | |
1711 | } | |
1712 | ||
1713 | this.$menu | |
1714 | .on('click', $.proxy(this.click, this)) | |
1715 | .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) | |
1716 | } | |
1717 | ||
1718 | , keyup: function (e) { | |
1719 | switch(e.keyCode) { | |
1720 | case 40: // down arrow | |
1721 | case 38: // up arrow | |
1722 | break | |
1723 | ||
1724 | case 9: // tab | |
1725 | case 13: // enter | |
1726 | if (!this.shown) return | |
1727 | this.select() | |
1728 | break | |
1729 | ||
1730 | case 27: // escape | |
1731 | if (!this.shown) return | |
1732 | this.hide() | |
1733 | break | |
1734 | ||
1735 | default: | |
1736 | this.lookup() | |
1737 | } | |
1738 | ||
1739 | e.stopPropagation() | |
1740 | e.preventDefault() | |
1741 | } | |
1742 | ||
1743 | , keypress: function (e) { | |
1744 | if (!this.shown) return | |
1745 | ||
1746 | switch(e.keyCode) { | |
1747 | case 9: // tab | |
1748 | case 13: // enter | |
1749 | case 27: // escape | |
1750 | e.preventDefault() | |
1751 | break | |
1752 | ||
1753 | case 38: // up arrow | |
1754 | if (e.type != 'keydown') break | |
1755 | e.preventDefault() | |
1756 | this.prev() | |
1757 | break | |
1758 | ||
1759 | case 40: // down arrow | |
1760 | if (e.type != 'keydown') break | |
1761 | e.preventDefault() | |
1762 | this.next() | |
1763 | break | |
1764 | } | |
1765 | ||
1766 | e.stopPropagation() | |
1767 | } | |
1768 | ||
1769 | , blur: function (e) { | |
1770 | var that = this | |
1771 | setTimeout(function () { that.hide() }, 150) | |
1772 | } | |
1773 | ||
1774 | , click: function (e) { | |
1775 | e.stopPropagation() | |
1776 | e.preventDefault() | |
1777 | this.select() | |
1778 | } | |
1779 | ||
1780 | , mouseenter: function (e) { | |
1781 | this.$menu.find('.active').removeClass('active') | |
1782 | $(e.currentTarget).addClass('active') | |
1783 | } | |
1784 | ||
1785 | } | |
1786 | ||
1787 | ||
1788 | /* TYPEAHEAD PLUGIN DEFINITION | |
1789 | * =========================== */ | |
1790 | ||
1791 | $.fn.typeahead = function (option) { | |
1792 | return this.each(function () { | |
1793 | var $this = $(this) | |
1794 | , data = $this.data('typeahead') | |
1795 | , options = typeof option == 'object' && option | |
1796 | if (!data) $this.data('typeahead', (data = new Typeahead(this, options))) | |
1797 | if (typeof option == 'string') data[option]() | |
1798 | }) | |
1799 | } | |
1800 | ||
1801 | $.fn.typeahead.defaults = { | |
1802 | source: [] | |
1803 | , items: 8 | |
1804 | , menu: '<ul class="typeahead dropdown-menu"></ul>' | |
1805 | , item: '<li><a href="#"></a></li>' | |
1806 | } | |
1807 | ||
1808 | $.fn.typeahead.Constructor = Typeahead | |
1809 | ||
1810 | ||
1811 | /* TYPEAHEAD DATA-API | |
1812 | * ================== */ | |
1813 | ||
1814 | $(function () { | |
1815 | $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { | |
1816 | var $this = $(this) | |
1817 | if ($this.data('typeahead')) return | |
1818 | e.preventDefault() | |
1819 | $this.typeahead($this.data()) | |
1820 | }) | |
1821 | }) | |
1822 | ||
1823 | }(window.jQuery);⏎ |
0 | /*! | |
1 | * Bootstrap.js by @fat & @mdo | |
2 | * Copyright 2012 Twitter, Inc. | |
3 | * http://www.apache.org/licenses/LICENSE-2.0.txt | |
4 | */ | |
5 | !function(a){a(function(){"use strict",a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(function(){a("body").on("click.alert.data-api",b,c.prototype.close)})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.parent('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")},a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a(function(){a("body").on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=c,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},to:function(b){var c=this.$element.find(".active"),d=c.parent().children(),e=d.index(c),f=this;if(b>d.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){f.to(b)}):e==b?this.pause().cycle():this.slide(b>e?"next":"prev",a(d[b]))},pause:function(a){return a||(this.paused=!0),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j=a.Event("slide");this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h]();if(e.hasClass("active"))return;if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}},a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c);e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):typeof c=="string"||(c=f.slide)?e[c]():f.interval&&e.cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a(function(){a("body").on("click.carousel.data-api","[data-slide]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=!e.data("modal")&&a.extend({},e.data(),c.data());e.carousel(f),b.preventDefault()})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning)return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning)return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}"use strict";var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e,f,g;if(c.is(".disabled, :disabled"))return;return f=c.attr("data-target"),f||(f=c.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,"")),e=a(f),e.length||(e=c.parent()),g=e.hasClass("open"),d(),g||e.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,a.proxy(f,this)):f.call(this)):b&&b()}function f(){this.$backdrop.remove(),this.$backdrop=null}function g(){var b=this;this.isShown&&this.options.keyboard?a(document).on("keyup.dismiss.modal",function(a){a.which==27&&b.hide()}):this.isShown||a(document).off("keyup.dismiss.modal")}"use strict";var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this))};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;a("body").addClass("modal-open"),this.isShown=!0,g.call(this),e.call(this,function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in"),c?b.$element.one(a.support.transition.end,function(){b.$element.trigger("shown")}):b.$element.trigger("shown")})},hide:function(b){b&&b.preventDefault();var e=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,a("body").removeClass("modal-open"),g.call(this),this.$element.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?c.call(this):d.call(this)}},a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a(function(){a("body").on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({},e.data(),c.data());b.preventDefault(),e.modal(f)})})}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,this.options.trigger!="manual"&&(e=this.options.trigger=="hover"?"mouseenter":"focus",f=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(e,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f,this.options.selector,a.proxy(this.leave,this))),this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,b,this.$element.data()),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.show)return c.show();clearTimeout(this.timeout),c.hoverState="in",this.timeout=setTimeout(function(){c.hoverState=="in"&&c.show()},c.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.hide)return c.hide();clearTimeout(this.timeout),c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var a,b,c,d,e,f,g;if(this.hasContent()&&this.enabled){a=this.tip(),this.setContent(),this.options.animation&&a.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,a[0],this.$element[0]):this.options.placement,b=/in/.test(f),a.remove().css({top:0,left:0,display:"block"}).appendTo(b?this.$element:document.body),c=this.getPosition(b),d=a[0].offsetWidth,e=a[0].offsetHeight;switch(b?f.split(" ")[1]:f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}a.css(g).addClass(f).addClass("in")}},isHTML:function(a){return typeof a!="string"||a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3||/^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(a)},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.isHTML(b)?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function d(){var b=setTimeout(function(){c.off(a.support.transition.end).remove()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.remove()})}var b=this,c=this.tip();c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d():c.remove()},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(b){return a.extend({},b?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()}},a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover",title:"",delay:0}}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.isHTML(b)?"html":"text"](b),a.find(".popover-content > *")[this.isHTML(c)?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-content")||(typeof c.content=="function"?c.content.call(b[0]):c.content),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip}}),a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",content:"",template:'<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'})}(window.jQuery),!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}"use strict",b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var b=a(this),c=b.data("target")||b.attr("href"),d=/^#\w/.test(c)&&a(c);return d&&c.length&&[[d.position().top,c]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu")&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}},a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a(function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),!function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active a").last()[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}},a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a(function(){a("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=a(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:b.top+b.height,left:b.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c=this,d,e;return this.query=this.$element.val(),this.query?(d=a.grep(this.source,function(a){return c.matcher(a)}),d=this.sorter(d),d.length?this.render(d.slice(0,this.options.items)).show():this.shown?this.hide():this):this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),(a.browser.webkit||a.browser.msie)&&this.$element.on("keydown",a.proxy(this.keypress,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this))},keyup:function(a){switch(a.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},keypress:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.type!="keydown")break;a.preventDefault(),this.prev();break;case 40:if(a.type!="keydown")break;a.preventDefault(),this.next()}a.stopPropagation()},blur:function(a){var b=this;setTimeout(function(){b.hide()},150)},click:function(a){a.stopPropagation(),a.preventDefault(),this.select()},mouseenter:function(b){this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")}},a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>'},a.fn.typeahead.Constructor=b,a(function(){a("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;b.preventDefault(),c.typeahead(c.data())})})}(window.jQuery);⏎ |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2017 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
37 | 37 | var $CHPauseDownload; |
38 | 38 | var $CHPausePostProcess; |
39 | 39 | var $CHPauseScan; |
40 | var $StatusPausing; | |
41 | var $StatusPaused; | |
42 | var $StatusLeft; | |
43 | 40 | var $StatusSpeed; |
44 | 41 | var $StatusSpeedIcon; |
45 | 42 | var $StatusTimeIcon; |
46 | 43 | var $StatusTime; |
47 | var $StatusURLs; | |
48 | 44 | var $PlayBlock; |
49 | 45 | var $PlayButton; |
50 | 46 | var $PauseButton; |
51 | 47 | var $PlayAnimation; |
52 | var $StatDialog; | |
53 | 48 | var $ScheduledPauseDialog; |
54 | 49 | var $PauseForInput; |
55 | 50 | var $PauseForPreview; |
78 | 73 | $PlayButton = $('#PlayButton'); |
79 | 74 | $PauseButton = $('#PauseButton'); |
80 | 75 | $PlayAnimation = $('#PlayAnimation'); |
81 | $StatusPausing = $('#StatusPausing'); | |
82 | $StatusPaused = $('#StatusPaused'); | |
83 | $StatusLeft = $('#StatusLeft'); | |
84 | 76 | $StatusSpeed = $('#StatusSpeed'); |
85 | 77 | $StatusSpeedIcon = $('#StatusSpeedIcon'); |
86 | 78 | $StatusTimeIcon = $('#StatusTimeIcon'); |
87 | 79 | $StatusTime = $('#StatusTime'); |
88 | $StatusURLs = $('#StatusURLs'); | |
89 | $ScheduledPauseDialog = $('#ScheduledPauseDialog') | |
80 | $ScheduledPauseDialog = $('#ScheduledPauseDialog'); | |
90 | 81 | $PauseForInput = $('#PauseForInput'); |
91 | 82 | $PauseForPreview = $('#PauseForPreview'); |
92 | 83 | |
366 | 357 | var parsedTime = parsable.match(/(\d+):?(\d+)?/) || []; |
367 | 358 | var primaryValue = parsedTime[1]; |
368 | 359 | var secondaryValue = parsedTime[2]; |
369 | var is12H = (indicator === 'am' || indicator === 'pm') | |
360 | var is12H = (indicator === 'am' || indicator === 'pm'); | |
370 | 361 | |
371 | 362 | if (indicator === undefined && secondaryValue === undefined) |
372 | 363 | { |
531 | 522 | var $StatDialog_ArticleCache; |
532 | 523 | var $StatDialog_QueueScripts; |
533 | 524 | var $StatDialog_ChartBlock; |
534 | var $StatDialog_Server; | |
535 | 525 | var $StatRangeDialog; |
536 | 526 | var $StatRangeDialog_PeriodInput; |
537 | 527 | var $StatDialog_Tooltip; |
580 | 570 | $StatDialog_ArticleCache = $('#StatDialog_ArticleCache'); |
581 | 571 | $StatDialog_QueueScripts = $('#StatDialog_QueueScripts'); |
582 | 572 | $StatDialog_ChartBlock = $('#StatDialog_ChartBlock'); |
583 | $StatDialog_Server = $('#StatDialog_Server'); | |
584 | 573 | $StatRangeDialog = $('#StatRangeDialog'); |
585 | 574 | $StatRangeDialog_PeriodInput = $('#StatRangeDialog_PeriodInput'); |
586 | 575 | $StatDialog_Tooltip = $('#StatDialog_Tooltip'); |
941 | 930 | var monDataLo = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; |
942 | 931 | |
943 | 932 | // aggregate daily volumes into months |
944 | var len = servervolumes[serverNo].BytesPerDays.length; | |
945 | 933 | var daySlot = servervolumes[serverNo].DaySlot; |
946 | 934 | var slotDelta = servervolumes[0].FirstDay - servervolumes[serverNo].FirstDay; |
947 | var startDate = new Date(monStartDate.getTime()); | |
948 | 935 | var day = 0; |
949 | 936 | for (var i = monStartIndex; i <= monEndIndex; i++, day++) |
950 | 937 | { |
1208 | 1195 | monthListInitialized = true; |
1209 | 1196 | |
1210 | 1197 | var firstDay = servervolumes[0].FirstDay; |
1211 | var lastDay = firstDay + servervolumes[0].BytesPerDays.length - 1; | |
1212 | 1198 | var curDay = firstDay + servervolumes[0].DaySlot; |
1213 | 1199 | var firstDt = dayToDate(firstDay); |
1214 | var lastDt = dayToDate(lastDay); | |
1215 | 1200 | var curDt = dayToDate(curDay); |
1216 | 1201 | |
1217 | 1202 | var menu = $('#StatDialog_MonthMenu'); |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
193 | 193 | |
194 | 194 | function addFiles(selectedFiles) |
195 | 195 | { |
196 | var list = ''; | |
197 | 196 | for (var i = 0; i<selectedFiles.length; i++) |
198 | 197 | { |
199 | 198 | var file = selectedFiles[i]; |
222 | 221 | |
223 | 222 | this.renameClick = function(no) |
224 | 223 | { |
225 | var file = files[no]; | |
226 | 224 | var info = infos[no]; |
227 | 225 | AddParamDialog.showModal(info, function() { |
228 | 226 | $('#AddDialog_File' + no).html(Util.formatNZBName(info.name + info.ext)); |
0 | 0 | /* |
1 | 1 | * This file is part of nzbget. See <http://nzbget.net>. |
2 | 2 | * |
3 | * Copyright (C) 2012-2016 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
3 | * Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
56 | 56 | |
57 | 57 | this.formatTimeLeft = function(sec) |
58 | 58 | { |
59 | var hms = ''; | |
60 | 59 | var days = Math.floor(sec / 86400); |
61 | 60 | var hours = Math.floor((sec % 86400) / 3600); |
62 | 61 | var minutes = Math.floor((sec / 60) % 60); |
341 | 340 | return text.substring(text.length - substr.length, text.length) === substr; |
342 | 341 | } |
343 | 342 | |
343 | this.makeId = function(text) | |
344 | { | |
345 | return text.replace(/ |\/|\\|\.|\$|\:|\*/g, '_'); | |
346 | } | |
347 | ||
344 | 348 | }(jQuery)); |
345 | 349 | |
346 | 350 | |
378 | 382 | var dialog = this; |
379 | 383 | var body = $('.modal-body', dialog); |
380 | 384 | var footer = $('.modal-footer', dialog); |
381 | var header = $('.modal-header', dialog); | |
382 | 385 | dialog.css({margin: '', left: '', top: '', bottom: '', right: '', width: '', height: ''}); |
383 | 386 | body.css({position: '', height: '', left: '', right: '', top: '', bottom: '', 'max-height': ''}); |
384 | 387 | footer.css({position: '', left: '', right: '', bottom: ''}); |
399 | 402 | var header = $('.modal-header', dialog); |
400 | 403 | |
401 | 404 | var oldBodyHeight = body.height(); |
402 | var oldWinHeight = dialog.height(); | |
403 | 405 | var windowWidth = $(window).width(); |
404 | 406 | var windowHeight = $(window).height(); |
405 | 407 | var oldTabWidth = fromTab.width(); |
529 | 531 | 'use strict'; |
530 | 532 | |
531 | 533 | // Properties |
532 | this.rpcUrl; | |
533 | this.defaultFailureCallback; | |
534 | this.rpcUrl = ''; | |
535 | this.defaultFailureCallback = undefined; | |
534 | 536 | this.connectErrorMessage = 'Cannot establish connection'; |
535 | 537 | this.safeMethods = []; |
536 | 538 | this.etags = {}; |